diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 41 |
1 files changed, 16 insertions, 25 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ca13483edd60..8dba6bd48557 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -5045,22 +5045,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5045 | struct nfs_getaclres *res) | 5045 | struct nfs_getaclres *res) |
5046 | { | 5046 | { |
5047 | unsigned int savep; | 5047 | unsigned int savep; |
5048 | __be32 *bm_p; | ||
5049 | uint32_t attrlen, | 5048 | uint32_t attrlen, |
5050 | bitmap[3] = {0}; | 5049 | bitmap[3] = {0}; |
5051 | int status; | 5050 | int status; |
5052 | size_t page_len = xdr->buf->page_len; | 5051 | unsigned int pg_offset; |
5053 | 5052 | ||
5054 | res->acl_len = 0; | 5053 | res->acl_len = 0; |
5055 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 5054 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
5056 | goto out; | 5055 | goto out; |
5057 | 5056 | ||
5058 | bm_p = xdr->p; | 5057 | xdr_enter_page(xdr, xdr->buf->page_len); |
5059 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | 5058 | |
5060 | res->acl_data_offset <<= 2; | 5059 | /* Calculate the offset of the page data */ |
5061 | /* Check if the acl data starts beyond the allocated buffer */ | 5060 | pg_offset = xdr->buf->head[0].iov_len; |
5062 | if (res->acl_data_offset > page_len) | ||
5063 | return -ERANGE; | ||
5064 | 5061 | ||
5065 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 5062 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
5066 | goto out; | 5063 | goto out; |
@@ -5074,23 +5071,16 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
5074 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 5071 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
5075 | * are stored with the acl data to handle the problem of | 5072 | * are stored with the acl data to handle the problem of |
5076 | * variable length bitmaps.*/ | 5073 | * variable length bitmaps.*/ |
5077 | xdr->p = bm_p; | 5074 | res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset; |
5078 | |||
5079 | /* We ignore &savep and don't do consistency checks on | ||
5080 | * the attr length. Let userspace figure it out.... */ | ||
5081 | attrlen += res->acl_data_offset; | ||
5082 | if (attrlen > page_len) { | ||
5083 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | ||
5084 | /* getxattr interface called with a NULL buf */ | ||
5085 | res->acl_len = attrlen; | ||
5086 | goto out; | ||
5087 | } | ||
5088 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", | ||
5089 | attrlen, page_len); | ||
5090 | return -EINVAL; | ||
5091 | } | ||
5092 | xdr_read_pages(xdr, attrlen); | ||
5093 | res->acl_len = attrlen; | 5075 | res->acl_len = attrlen; |
5076 | |||
5077 | /* Check for receive buffer overflow */ | ||
5078 | if (res->acl_len > (xdr->nwords << 2) || | ||
5079 | res->acl_len + res->acl_data_offset > xdr->buf->page_len) { | ||
5080 | res->acl_flags |= NFS4_ACL_TRUNC; | ||
5081 | dprintk("NFS: acl reply: attrlen %u > page_len %u\n", | ||
5082 | attrlen, xdr->nwords << 2); | ||
5083 | } | ||
5094 | } else | 5084 | } else |
5095 | status = -EOPNOTSUPP; | 5085 | status = -EOPNOTSUPP; |
5096 | 5086 | ||
@@ -6235,7 +6225,8 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |||
6235 | status = decode_open(xdr, res); | 6225 | status = decode_open(xdr, res); |
6236 | if (status) | 6226 | if (status) |
6237 | goto out; | 6227 | goto out; |
6238 | if (decode_getfh(xdr, &res->fh) != 0) | 6228 | status = decode_getfh(xdr, &res->fh); |
6229 | if (status) | ||
6239 | goto out; | 6230 | goto out; |
6240 | decode_getfattr(xdr, res->f_attr, res->server); | 6231 | decode_getfattr(xdr, res->f_attr, res->server); |
6241 | out: | 6232 | out: |