nfsd4: fix bad bounds checking
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 1 Mar 2016 01:21:21 +0000 (20:21 -0500)
committerBen Hutchings <ben@decadent.org.uk>
Sat, 30 Apr 2016 22:05:16 +0000 (00:05 +0200)
commit 4aed9c46afb80164401143aa0fdcfe3798baa9d5 upstream.

A number of spots in the xdr decoding follow a pattern like

n = be32_to_cpup(p++);
READ_BUF(n + 4);

where n is a u32.  The only bounds checking is done in READ_BUF itself,
but since it's checking (n + 4), it won't catch cases where n is very
large, (u32)(-4) or higher.  I'm not sure exactly what the consequences
are, but we've seen crashes soon after.

Instead, just break these up into two READ_BUF()s.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
[bwh: Backported to 3.2: adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
fs/nfsd/nfs4xdr.c

index 9d2c52b..31352e2 100644 (file)
@@ -931,8 +931,9 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename
 
        READ_BUF(4);
        READ32(rename->rn_snamelen);
-       READ_BUF(rename->rn_snamelen + 4);
+       READ_BUF(rename->rn_snamelen);
        SAVEMEM(rename->rn_sname, rename->rn_snamelen);
+       READ_BUF(4);
        READ32(rename->rn_tnamelen);
        READ_BUF(rename->rn_tnamelen);
        SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
@@ -1009,13 +1010,14 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
        READ_BUF(8);
        READ32(setclientid->se_callback_prog);
        READ32(setclientid->se_callback_netid_len);
-
-       READ_BUF(setclientid->se_callback_netid_len + 4);
+       READ_BUF(setclientid->se_callback_netid_len);
        SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
+       READ_BUF(4);
        READ32(setclientid->se_callback_addr_len);
 
-       READ_BUF(setclientid->se_callback_addr_len + 4);
+       READ_BUF(setclientid->se_callback_addr_len);
        SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
+       READ_BUF(4);
        READ32(setclientid->se_callback_ident);
 
        DECODE_TAIL;
@@ -1584,8 +1586,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
         */
        READ_BUF(4);
        READ32(argp->taglen);
-       READ_BUF(argp->taglen + 8);
+       READ_BUF(argp->taglen);
        SAVEMEM(argp->tag, argp->taglen);
+       READ_BUF(8);
        READ32(argp->minorversion);
        READ32(argp->opcnt);