Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- fs/nfsd/nfs4xdr.c | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 3cd5b2c843d8..bc36c746b293 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -246,29 +246,29 @@ nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) } static __be32 -nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) +nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, + u32 bmlen) { - u32 bmlen; - DECODE_HEAD; + __be32 *p; + u32 len, i; - bmval[0] = 0; - bmval[1] = 0; - bmval[2] = 0; + for (i = 0; i < bmlen; i++) + bmval[i] = 0; - READ_BUF(4); - bmlen = be32_to_cpup(p++); - if (bmlen > 1000) + if (xdr_stream_decode_u32(argp->xdr, &len) < 0) + goto xdr_error; + if (len > 1000) goto xdr_error; - READ_BUF(bmlen << 2); - if (bmlen > 0) - bmval[0] = be32_to_cpup(p++); - if (bmlen > 1) - bmval[1] = be32_to_cpup(p++); - if (bmlen > 2) - bmval[2] = be32_to_cpup(p++); + p = xdr_inline_decode(argp->xdr, len << 2); + if (!p) + goto xdr_error; + for (i = 0; i < len && i < bmlen; i++) + bmval[i] = be32_to_cpup(p++); - DECODE_TAIL; + return nfs_ok; +xdr_error: + return nfserr_bad_xdr; } static __be32 @@ -282,8 +282,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, DECODE_HEAD; iattr->ia_valid = 0; - if ((status = nfsd4_decode_bitmap(argp, bmval))) - return status; + status = nfsd4_decode_bitmap4(argp, bmval, 3); + if (status) + goto out; if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 @@ -665,7 +666,8 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu static inline __be32 nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) { - return nfsd4_decode_bitmap(argp, getattr->ga_bmval); + return nfsd4_decode_bitmap4(argp, getattr->ga_bmval, + ARRAY_SIZE(getattr->ga_bmval)); } static __be32 @@ -1060,7 +1062,9 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); readdir->rd_dircount = be32_to_cpup(p++); readdir->rd_maxcount = be32_to_cpup(p++); - if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) + status = nfsd4_decode_bitmap4(argp, readdir->rd_bmval, + ARRAY_SIZE(readdir->rd_bmval)); + if (status) goto out; DECODE_TAIL; @@ -1206,7 +1210,9 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify { DECODE_HEAD; - if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) + status = nfsd4_decode_bitmap4(argp, verify->ve_bmval, + ARRAY_SIZE(verify->ve_bmval)); + if (status) goto out; /* For convenience's sake, we compare raw xdr'd attributes in @@ -1285,12 +1291,13 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, break; case SP4_MACH_CRED: /* spo_must_enforce */ - status = nfsd4_decode_bitmap(argp, - exid->spo_must_enforce); + status = nfsd4_decode_bitmap4(argp, exid->spo_must_enforce, + ARRAY_SIZE(exid->spo_must_enforce)); if (status) goto out; /* spo_must_allow */ - status = nfsd4_decode_bitmap(argp, exid->spo_must_allow); + status = nfsd4_decode_bitmap4(argp, exid->spo_must_allow, + ARRAY_SIZE(exid->spo_must_allow)); if (status) goto out; break;