[PATCH 5/5] NFSv4/flexfiles: bound stripe_unit to 32 bits
Junrui Luo <[email protected]> Tue, 04 Aug 2026 18:55:05 +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]> |
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