diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
-rw-r--r-- | fs/nfs/nfs4xdr.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 77fc5f959c4e..c54aae364bee 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -4258,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
4258 | status = decode_attr_error(xdr, bitmap, &err); | 4258 | status = decode_attr_error(xdr, bitmap, &err); |
4259 | if (status < 0) | 4259 | if (status < 0) |
4260 | goto xdr_error; | 4260 | goto xdr_error; |
4261 | if (err == -NFS4ERR_WRONGSEC) | ||
4262 | nfs_fixup_secinfo_attributes(fattr, fh); | ||
4263 | 4261 | ||
4264 | status = decode_attr_filehandle(xdr, bitmap, fh); | 4262 | status = decode_attr_filehandle(xdr, bitmap, fh); |
4265 | if (status < 0) | 4263 | if (status < 0) |
@@ -4902,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4902 | bitmap[3] = {0}; | 4900 | bitmap[3] = {0}; |
4903 | struct kvec *iov = req->rq_rcv_buf.head; | 4901 | struct kvec *iov = req->rq_rcv_buf.head; |
4904 | int status; | 4902 | int status; |
4903 | size_t page_len = xdr->buf->page_len; | ||
4905 | 4904 | ||
4906 | res->acl_len = 0; | 4905 | res->acl_len = 0; |
4907 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 4906 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
4908 | goto out; | 4907 | goto out; |
4908 | |||
4909 | bm_p = xdr->p; | 4909 | bm_p = xdr->p; |
4910 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
4911 | res->acl_data_offset <<= 2; | ||
4912 | /* Check if the acl data starts beyond the allocated buffer */ | ||
4913 | if (res->acl_data_offset > page_len) | ||
4914 | return -ERANGE; | ||
4915 | |||
4910 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 4916 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
4911 | goto out; | 4917 | goto out; |
4912 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | 4918 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) |
@@ -4916,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
4916 | return -EIO; | 4922 | return -EIO; |
4917 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 4923 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
4918 | size_t hdrlen; | 4924 | size_t hdrlen; |
4919 | u32 recvd; | ||
4920 | 4925 | ||
4921 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 4926 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
4922 | * are stored with the acl data to handle the problem of | 4927 | * are stored with the acl data to handle the problem of |
4923 | * variable length bitmaps.*/ | 4928 | * variable length bitmaps.*/ |
4924 | xdr->p = bm_p; | 4929 | xdr->p = bm_p; |
4925 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
4926 | res->acl_data_offset <<= 2; | ||
4927 | 4930 | ||
4928 | /* We ignore &savep and don't do consistency checks on | 4931 | /* We ignore &savep and don't do consistency checks on |
4929 | * the attr length. Let userspace figure it out.... */ | 4932 | * the attr length. Let userspace figure it out.... */ |
4930 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | 4933 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; |
4931 | attrlen += res->acl_data_offset; | 4934 | attrlen += res->acl_data_offset; |
4932 | recvd = req->rq_rcv_buf.len - hdrlen; | 4935 | if (attrlen > page_len) { |
4933 | if (attrlen > recvd) { | ||
4934 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | 4936 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
4935 | /* getxattr interface called with a NULL buf */ | 4937 | /* getxattr interface called with a NULL buf */ |
4936 | res->acl_len = attrlen; | 4938 | res->acl_len = attrlen; |
4937 | goto out; | 4939 | goto out; |
4938 | } | 4940 | } |
4939 | dprintk("NFS: acl reply: attrlen %u > recvd %u\n", | 4941 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", |
4940 | attrlen, recvd); | 4942 | attrlen, page_len); |
4941 | return -EINVAL; | 4943 | return -EINVAL; |
4942 | } | 4944 | } |
4943 | xdr_read_pages(xdr, attrlen); | 4945 | xdr_read_pages(xdr, attrlen); |
@@ -5090,16 +5092,13 @@ out_err: | |||
5090 | return -EINVAL; | 5092 | return -EINVAL; |
5091 | } | 5093 | } |
5092 | 5094 | ||
5093 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | 5095 | static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) |
5094 | { | 5096 | { |
5095 | struct nfs4_secinfo_flavor *sec_flavor; | 5097 | struct nfs4_secinfo_flavor *sec_flavor; |
5096 | int status; | 5098 | int status; |
5097 | __be32 *p; | 5099 | __be32 *p; |
5098 | int i, num_flavors; | 5100 | int i, num_flavors; |
5099 | 5101 | ||
5100 | status = decode_op_hdr(xdr, OP_SECINFO); | ||
5101 | if (status) | ||
5102 | goto out; | ||
5103 | p = xdr_inline_decode(xdr, 4); | 5102 | p = xdr_inline_decode(xdr, 4); |
5104 | if (unlikely(!p)) | 5103 | if (unlikely(!p)) |
5105 | goto out_overflow; | 5104 | goto out_overflow; |
@@ -5125,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | |||
5125 | res->flavors->num_flavors++; | 5124 | res->flavors->num_flavors++; |
5126 | } | 5125 | } |
5127 | 5126 | ||
5127 | status = 0; | ||
5128 | out: | 5128 | out: |
5129 | return status; | 5129 | return status; |
5130 | out_overflow: | 5130 | out_overflow: |
@@ -5132,7 +5132,23 @@ out_overflow: | |||
5132 | return -EIO; | 5132 | return -EIO; |
5133 | } | 5133 | } |
5134 | 5134 | ||
5135 | static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
5136 | { | ||
5137 | int status = decode_op_hdr(xdr, OP_SECINFO); | ||
5138 | if (status) | ||
5139 | return status; | ||
5140 | return decode_secinfo_common(xdr, res); | ||
5141 | } | ||
5142 | |||
5135 | #if defined(CONFIG_NFS_V4_1) | 5143 | #if defined(CONFIG_NFS_V4_1) |
5144 | static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | ||
5145 | { | ||
5146 | int status = decode_op_hdr(xdr, OP_SECINFO_NO_NAME); | ||
5147 | if (status) | ||
5148 | return status; | ||
5149 | return decode_secinfo_common(xdr, res); | ||
5150 | } | ||
5151 | |||
5136 | static int decode_exchange_id(struct xdr_stream *xdr, | 5152 | static int decode_exchange_id(struct xdr_stream *xdr, |
5137 | struct nfs41_exchange_id_res *res) | 5153 | struct nfs41_exchange_id_res *res) |
5138 | { | 5154 | { |
@@ -6817,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, | |||
6817 | status = decode_putrootfh(xdr); | 6833 | status = decode_putrootfh(xdr); |
6818 | if (status) | 6834 | if (status) |
6819 | goto out; | 6835 | goto out; |
6820 | status = decode_secinfo(xdr, res); | 6836 | status = decode_secinfo_no_name(xdr, res); |
6821 | out: | 6837 | out: |
6822 | return status; | 6838 | return status; |
6823 | } | 6839 | } |