Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- fs/nfsd/nfs4xdr.c | 65 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2c69bf10d556..3cd5b2c843d8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -90,6 +90,8 @@ check_filename(char *str, int len) if (len == 0) return nfserr_inval; + if (len > NFS4_MAXNAMLEN) + return nfserr_nametoolong; if (isdotent(str, len)) return nfserr_badname; for (i = 0; i < len; i++) @@ -203,6 +205,32 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) return ret; } +static __be32 nfsd4_decode_component4(struct nfsd4_compoundargs *argp, + char **namp, u32 *lenp) +{ + __be32 *p, status; + + if (xdr_stream_decode_u32(argp->xdr, lenp) < 0) + goto xdr_error; + p = xdr_inline_decode(argp->xdr, *lenp); + if (!p) + goto xdr_error; + status = check_filename((char *)p, *lenp); + if (status) + goto out; + *namp = svcxdr_tmpalloc(argp, *lenp); + if (!*namp) + goto nomem; + memcpy(*namp, p, *lenp); + status = nfs_ok; +out: + return status; +xdr_error: + return nfserr_bad_xdr; +nomem: + return nfserr_jukebox; +} + static __be32 nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) { @@ -583,24 +611,27 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit static __be32 nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) { - DECODE_HEAD; + __be32 *p, status; - READ_BUF(4); - create->cr_type = be32_to_cpup(p++); + if (xdr_stream_decode_u32(argp->xdr, &create->cr_type) < 0) + goto xdr_error; switch (create->cr_type) { case NF4LNK: - READ_BUF(4); - create->cr_datalen = be32_to_cpup(p++); - READ_BUF(create->cr_datalen); + if (xdr_stream_decode_u32(argp->xdr, &create->cr_datalen) < 0) + goto xdr_error; + p = xdr_inline_decode(argp->xdr, create->cr_datalen); + if (!p) + goto xdr_error; create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen); if (!create->cr_data) return nfserr_jukebox; break; case NF4BLK: case NF4CHR: - READ_BUF(8); - create->cr_specdata1 = be32_to_cpup(p++); - create->cr_specdata2 = be32_to_cpup(p++); + if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata1) < 0) + goto xdr_error; + if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata2) < 0) + goto xdr_error; break; case NF4SOCK: case NF4FIFO: @@ -609,20 +640,20 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create break; } - READ_BUF(4); - create->cr_namelen = be32_to_cpup(p++); - READ_BUF(create->cr_namelen); - SAVEMEM(create->cr_name, create->cr_namelen); - if ((status = check_filename(create->cr_name, create->cr_namelen))) - return status; - + status = nfsd4_decode_component4(argp, &create->cr_name, + &create->cr_namelen); + if (status) + goto out; status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl, &create->cr_label, &create->cr_umask); if (status) goto out; - DECODE_TAIL; +out: + return status; +xdr_error: + return nfserr_bad_xdr; } static inline __be32