[PATCH 1/5] NFSv4/flexfiles: bound the multipath address count

Junrui Luo via B4 Relay <[email protected]>
Newsgroups org.kernel.vger.linux-nfs,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
From: Junrui Luo <[email protected]>

nfs4_ff_alloc_deviceid_node() decodes the multipath address list of a
flexfiles device from the GETDEVICEINFO reply body. mp_count is taken
straight off the wire and used as the loop bound for the
nfs4_decode_mp_ds_addr() calls. nfs4_get_device_info() bounds pdev->pglen
but not the counts encoded inside it, so a server can advertise up to
2^32 - 1 addresses in a body that holds none of them.

Once the xdr_stream is exhausted the loop stops making progress:
xdr_stream_decode_string_dup() fails in xdr_stream_decode_opaque_inline()
, so nfs4_decode_mp_ds_addr() returns NULL without consuming a byte and
every remaining iteration re-fails at the same offset. With mp_count set
to 0xffffffff this spins for roughly 2^32 iterations with no rescheduling
point, potentially tripping the soft lockup watchdog and the RCU stall
detector on non-preemptible kernels. The list_empty(&dsaddrs) check
below the loop only runs once the loop has finished.

Reject implausible counts up front, as ff_layout_alloc_lseg() already
does for mirror_array_cnt and dss_count.

Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver")
Reported-by: Yuhao Jiang <[email protected]>
Assisted-by: Claude:claude-opus-5
Cc: [email protected]
Signed-off-by: Junrui Luo <[email protected]>
---
 fs/nfs/flexfilelayout/flexfilelayout.h    | 4 ++++
 fs/nfs/flexfilelayout/flexfilelayoutdev.c | 5 +++++
 2 files changed, 9 insertions(+)

diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h
index a5bd00f69e82..d024b8db4ce0 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.h
+++ b/fs/nfs/flexfilelayout/flexfilelayout.h
@@ -23,6 +23,10 @@
 
 #define NFS4_FLEXFILE_LAYOUT_MAX_STRIPE_CNT 4096
 
+/* Filter out insanely large multipath address counts, which would
+ * otherwise let a server spin the GETDEVICEINFO decode loop. */
+#define NFS4_FLEXFILE_LAYOUT_MAX_MULTIPATH_CNT 4096
+
 /* LAYOUTSTATS report interval in ms */
 #define FF_LAYOUTSTATS_REPORT_INTERVAL (60000L)
 #define FF_LAYOUTSTATS_MAXDEV 4
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index 1109462a9699..659a2bf7b502 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -79,6 +79,11 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
 	mp_count = be32_to_cpup(p);
 	dprintk("%s: multipath ds count %d\n", __func__, mp_count);
 
+	if (mp_count > NFS4_FLEXFILE_LAYOUT_MAX_MULTIPATH_CNT) {
+		ret = -EINVAL;
+		goto out_err_drain_dsaddrs;
+	}
+
 	for (i = 0; i < mp_count; i++) {
 		/* multipath ds */
 		da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags);

-- 
2.51.2
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.