[PATCH 1/5] NFSv4/flexfiles: bound the multipath address count
Junrui Luo via B4 Relay <[email protected]> Tue, 04 Aug 2026 18:55:01 +0800
| Newsgroups | gmane.linux.kernel,gmane.linux.nfs,gmane.linux.kernel.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