[PATCH 1/5] NFSv4/flexfiles: bound the multipath address count
Junrui Luo <[email protected]> Tue, 04 Aug 2026 18:55:01 +0800
| Newsgroups | org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs,org.kernel.vger.stable |
|---|---|
| Message-ID | <[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