nfsd: validate nseconds in TIME_DELEG decode paths

The xdrgen-based TIME_DELEG_ACCESS and TIME_DELEG_MODIFY decode arms
store a raw uint32_t nseconds directly into tv_nsec without enforcing
nseconds < NSEC_PER_SEC. The legacy nfsd4_decode_nfstime4 has this
check but the TIME_DELEG paths do not. A malformed timespec can
propagate through notify_change() to disk.

Add range checks in both nfs4xdr.c (SETATTR path) and
nfs4callback.c (CB_GETATTR path).

Fixes: 6ae30d6eb2 ("nfsd: add support for delegated timestamps")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260611-nfsd-testing-v2-7-5b90e276f2d9@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
Jeff Layton
2026-06-11 16:00:50 -04:00
committed by Chuck Lever
parent 04cce9d79f
commit 0f4a767340
2 changed files with 8 additions and 0 deletions

View File

@@ -108,6 +108,8 @@ static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
if (!xdrgen_decode_fattr4_time_deleg_access(xdr, &access))
return -EIO;
if (access.nseconds >= NSEC_PER_SEC)
return -EIO;
fattr->ncf_cb_atime.tv_sec = access.seconds;
fattr->ncf_cb_atime.tv_nsec = access.nseconds;
@@ -117,6 +119,8 @@ static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
if (!xdrgen_decode_fattr4_time_deleg_modify(xdr, &modify))
return -EIO;
if (modify.nseconds >= NSEC_PER_SEC)
return -EIO;
fattr->ncf_cb_mtime.tv_sec = modify.seconds;
fattr->ncf_cb_mtime.tv_nsec = modify.nseconds;

View File

@@ -637,6 +637,8 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
if (!xdrgen_decode_fattr4_time_deleg_access(argp->xdr, &access))
return nfserr_bad_xdr;
if (access.nseconds >= NSEC_PER_SEC)
return nfserr_inval;
iattr->ia_atime.tv_sec = access.seconds;
iattr->ia_atime.tv_nsec = access.nseconds;
iattr->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET | ATTR_DELEG;
@@ -646,6 +648,8 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
if (!xdrgen_decode_fattr4_time_deleg_modify(argp->xdr, &modify))
return nfserr_bad_xdr;
if (modify.nseconds >= NSEC_PER_SEC)
return nfserr_inval;
iattr->ia_mtime.tv_sec = modify.seconds;
iattr->ia_mtime.tv_nsec = modify.nseconds;
iattr->ia_ctime.tv_sec = modify.seconds;