| From 4aed9c46afb80164401143aa0fdcfe3798baa9d5 Mon Sep 17 00:00:00 2001 |
| From: "J. Bruce Fields" <bfields@redhat.com> |
| Date: Mon, 29 Feb 2016 20:21:21 -0500 |
| Subject: nfsd4: fix bad bounds checking |
| |
| From: J. Bruce Fields <bfields@redhat.com> |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfsd/nfs4xdr.c | 13 ++++++++----- |
| 1 file changed, 8 insertions(+), 5 deletions(-) |
| |
| --- a/fs/nfsd/nfs4xdr.c |
| +++ b/fs/nfsd/nfs4xdr.c |
| @@ -1072,8 +1072,9 @@ nfsd4_decode_rename(struct nfsd4_compoun |
| |
| READ_BUF(4); |
| rename->rn_snamelen = be32_to_cpup(p++); |
| - READ_BUF(rename->rn_snamelen + 4); |
| + READ_BUF(rename->rn_snamelen); |
| SAVEMEM(rename->rn_sname, rename->rn_snamelen); |
| + READ_BUF(4); |
| rename->rn_tnamelen = be32_to_cpup(p++); |
| READ_BUF(rename->rn_tnamelen); |
| SAVEMEM(rename->rn_tname, rename->rn_tnamelen); |
| @@ -1155,13 +1156,14 @@ nfsd4_decode_setclientid(struct nfsd4_co |
| READ_BUF(8); |
| setclientid->se_callback_prog = be32_to_cpup(p++); |
| setclientid->se_callback_netid_len = be32_to_cpup(p++); |
| - |
| - 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); |
| setclientid->se_callback_addr_len = be32_to_cpup(p++); |
| |
| - 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); |
| setclientid->se_callback_ident = be32_to_cpup(p++); |
| |
| DECODE_TAIL; |
| @@ -1815,8 +1817,9 @@ nfsd4_decode_compound(struct nfsd4_compo |
| |
| READ_BUF(4); |
| argp->taglen = be32_to_cpup(p++); |
| - READ_BUF(argp->taglen + 8); |
| + READ_BUF(argp->taglen); |
| SAVEMEM(argp->tag, argp->taglen); |
| + READ_BUF(8); |
| argp->minorversion = be32_to_cpup(p++); |
| argp->opcnt = be32_to_cpup(p++); |
| max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2); |