[PATCH 5/5] NFSv4/flexfiles: bound stripe_unit to 32 bits

Junrui Luo via B4 Relay <[email protected]> Tue, 04 Aug 2026 18:55:05 +0800
Newsgroups gmane.linux.kernel,gmane.linux.nfs,gmane.linux.kernel.stable
Message-ID <[email protected]>
From: Junrui Luo <[email protected]>

ff_layout_alloc_lseg() decodes stripe_unit from the flexfiles LAYOUTGET
body as a 64-bit value and validates it as one:

	if (dss_count > 1 && stripe_unit == 0)
		goto out_err_free;

but every consumer divides by only its low 32 bits.  ff_layout_pg_test()
narrows it explicitly:

	u32 stripe_unit = FF_LAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
	...
	do_div(p_stripe, stripe_unit);

and nfs4_ff_layout_calc_dss_id() passes the u64 straight to do_div(),
which narrows the divisor itself.

A server-supplied non-zero multiple of 2^32 such as 0x100000000
therefore passes the check and reaches both dividers as a zero divisor,
so the first read or write through the layout takes a divide error and
panics the client.  The same narrowing silently turns any other value
above U32_MAX into an unrelated stripe size.

Values that do not fit in 32 bits are not representable by the
arithmetic this driver performs on stripe_unit, so reject them at decode
time rather than truncating them.

Fixes: 20b1d75fb840 ("NFSv4/flexfiles: Add support for striped layouts")
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.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index bdc4b960eeb7..63391f48c5d9 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -515,7 +515,8 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
 		    dss_count == 0)
 			goto out_err_free;
 
-		if (dss_count > 1 && stripe_unit == 0)
+		if (dss_count > 1 &&
+		    (stripe_unit == 0 || stripe_unit > U32_MAX))
 			goto out_err_free;
 
 		fls->mirror_array[i] = ff_layout_alloc_mirror(dss_count, gfp_flags);

-- 
2.51.2