diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c74fdb114b48..c54aae364bee 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -74,7 +74,7 @@ static int nfs4_stat_to_errno(int); | |||
| 74 | /* lock,open owner id: | 74 | /* lock,open owner id: |
| 75 | * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) | 75 | * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2) |
| 76 | */ | 76 | */ |
| 77 | #define open_owner_id_maxsz (1 + 1 + 4) | 77 | #define open_owner_id_maxsz (1 + 2 + 1 + 1 + 2) |
| 78 | #define lock_owner_id_maxsz (1 + 1 + 4) | 78 | #define lock_owner_id_maxsz (1 + 1 + 4) |
| 79 | #define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) | 79 | #define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ)) |
| 80 | #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) | 80 | #define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) |
| @@ -1340,12 +1340,13 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena | |||
| 1340 | */ | 1340 | */ |
| 1341 | encode_nfs4_seqid(xdr, arg->seqid); | 1341 | encode_nfs4_seqid(xdr, arg->seqid); |
| 1342 | encode_share_access(xdr, arg->fmode); | 1342 | encode_share_access(xdr, arg->fmode); |
| 1343 | p = reserve_space(xdr, 32); | 1343 | p = reserve_space(xdr, 36); |
| 1344 | p = xdr_encode_hyper(p, arg->clientid); | 1344 | p = xdr_encode_hyper(p, arg->clientid); |
| 1345 | *p++ = cpu_to_be32(20); | 1345 | *p++ = cpu_to_be32(24); |
| 1346 | p = xdr_encode_opaque_fixed(p, "open id:", 8); | 1346 | p = xdr_encode_opaque_fixed(p, "open id:", 8); |
| 1347 | *p++ = cpu_to_be32(arg->server->s_dev); | 1347 | *p++ = cpu_to_be32(arg->server->s_dev); |
| 1348 | xdr_encode_hyper(p, arg->id); | 1348 | *p++ = cpu_to_be32(arg->id.uniquifier); |
| 1349 | xdr_encode_hyper(p, arg->id.create_time); | ||
| 1349 | } | 1350 | } |
| 1350 | 1351 | ||
| 1351 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) | 1352 | static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) |
| @@ -4257,8 +4258,6 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap, | |||
| 4257 | status = decode_attr_error(xdr, bitmap, &err); | 4258 | status = decode_attr_error(xdr, bitmap, &err); |
| 4258 | if (status < 0) | 4259 | if (status < 0) |
| 4259 | goto xdr_error; | 4260 | goto xdr_error; |
| 4260 | if (err == -NFS4ERR_WRONGSEC) | ||
| 4261 | nfs_fixup_secinfo_attributes(fattr, fh); | ||
| 4262 | 4261 | ||
| 4263 | status = decode_attr_filehandle(xdr, bitmap, fh); | 4262 | status = decode_attr_filehandle(xdr, bitmap, fh); |
| 4264 | if (status < 0) | 4263 | if (status < 0) |
| @@ -4901,11 +4900,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 4901 | bitmap[3] = {0}; | 4900 | bitmap[3] = {0}; |
| 4902 | struct kvec *iov = req->rq_rcv_buf.head; | 4901 | struct kvec *iov = req->rq_rcv_buf.head; |
| 4903 | int status; | 4902 | int status; |
| 4903 | size_t page_len = xdr->buf->page_len; | ||
| 4904 | 4904 | ||
| 4905 | res->acl_len = 0; | 4905 | res->acl_len = 0; |
| 4906 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) | 4906 | if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0) |
| 4907 | goto out; | 4907 | goto out; |
| 4908 | |||
| 4908 | 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 | |||
| 4909 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) | 4916 | if ((status = decode_attr_bitmap(xdr, bitmap)) != 0) |
| 4910 | goto out; | 4917 | goto out; |
| 4911 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) | 4918 | if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0) |
| @@ -4915,28 +4922,24 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req, | |||
| 4915 | return -EIO; | 4922 | return -EIO; |
| 4916 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { | 4923 | if (likely(bitmap[0] & FATTR4_WORD0_ACL)) { |
| 4917 | size_t hdrlen; | 4924 | size_t hdrlen; |
| 4918 | u32 recvd; | ||
| 4919 | 4925 | ||
| 4920 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words | 4926 | /* The bitmap (xdr len + bitmaps) and the attr xdr len words |
| 4921 | * are stored with the acl data to handle the problem of | 4927 | * are stored with the acl data to handle the problem of |
| 4922 | * variable length bitmaps.*/ | 4928 | * variable length bitmaps.*/ |
| 4923 | xdr->p = bm_p; | 4929 | xdr->p = bm_p; |
| 4924 | res->acl_data_offset = be32_to_cpup(bm_p) + 2; | ||
| 4925 | res->acl_data_offset <<= 2; | ||
| 4926 | 4930 | ||
| 4927 | /* We ignore &savep and don't do consistency checks on | 4931 | /* We ignore &savep and don't do consistency checks on |
| 4928 | * the attr length. Let userspace figure it out.... */ | 4932 | * the attr length. Let userspace figure it out.... */ |
| 4929 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; | 4933 | hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base; |
| 4930 | attrlen += res->acl_data_offset; | 4934 | attrlen += res->acl_data_offset; |
| 4931 | recvd = req->rq_rcv_buf.len - hdrlen; | 4935 | if (attrlen > page_len) { |
| 4932 | if (attrlen > recvd) { | ||
| 4933 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { | 4936 | if (res->acl_flags & NFS4_ACL_LEN_REQUEST) { |
| 4934 | /* getxattr interface called with a NULL buf */ | 4937 | /* getxattr interface called with a NULL buf */ |
| 4935 | res->acl_len = attrlen; | 4938 | res->acl_len = attrlen; |
| 4936 | goto out; | 4939 | goto out; |
| 4937 | } | 4940 | } |
| 4938 | dprintk("NFS: acl reply: attrlen %u > recvd %u\n", | 4941 | dprintk("NFS: acl reply: attrlen %u > page_len %zu\n", |
| 4939 | attrlen, recvd); | 4942 | attrlen, page_len); |
| 4940 | return -EINVAL; | 4943 | return -EINVAL; |
| 4941 | } | 4944 | } |
| 4942 | xdr_read_pages(xdr, attrlen); | 4945 | xdr_read_pages(xdr, attrlen); |
| @@ -5089,16 +5092,13 @@ out_err: | |||
| 5089 | return -EINVAL; | 5092 | return -EINVAL; |
| 5090 | } | 5093 | } |
| 5091 | 5094 | ||
| 5092 | 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) |
| 5093 | { | 5096 | { |
| 5094 | struct nfs4_secinfo_flavor *sec_flavor; | 5097 | struct nfs4_secinfo_flavor *sec_flavor; |
| 5095 | int status; | 5098 | int status; |
| 5096 | __be32 *p; | 5099 | __be32 *p; |
| 5097 | int i, num_flavors; | 5100 | int i, num_flavors; |
| 5098 | 5101 | ||
| 5099 | status = decode_op_hdr(xdr, OP_SECINFO); | ||
| 5100 | if (status) | ||
| 5101 | goto out; | ||
| 5102 | p = xdr_inline_decode(xdr, 4); | 5102 | p = xdr_inline_decode(xdr, 4); |
| 5103 | if (unlikely(!p)) | 5103 | if (unlikely(!p)) |
| 5104 | goto out_overflow; | 5104 | goto out_overflow; |
| @@ -5124,6 +5124,7 @@ static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res) | |||
| 5124 | res->flavors->num_flavors++; | 5124 | res->flavors->num_flavors++; |
| 5125 | } | 5125 | } |
| 5126 | 5126 | ||
| 5127 | status = 0; | ||
| 5127 | out: | 5128 | out: |
| 5128 | return status; | 5129 | return status; |
| 5129 | out_overflow: | 5130 | out_overflow: |
| @@ -5131,7 +5132,23 @@ out_overflow: | |||
| 5131 | return -EIO; | 5132 | return -EIO; |
| 5132 | } | 5133 | } |
| 5133 | 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 | |||
| 5134 | #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 | |||
| 5135 | static int decode_exchange_id(struct xdr_stream *xdr, | 5152 | static int decode_exchange_id(struct xdr_stream *xdr, |
| 5136 | struct nfs41_exchange_id_res *res) | 5153 | struct nfs41_exchange_id_res *res) |
| 5137 | { | 5154 | { |
| @@ -6816,7 +6833,7 @@ static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, | |||
| 6816 | status = decode_putrootfh(xdr); | 6833 | status = decode_putrootfh(xdr); |
| 6817 | if (status) | 6834 | if (status) |
| 6818 | goto out; | 6835 | goto out; |
| 6819 | status = decode_secinfo(xdr, res); | 6836 | status = decode_secinfo_no_name(xdr, res); |
| 6820 | out: | 6837 | out: |
| 6821 | return status; | 6838 | return status; |
| 6822 | } | 6839 | } |
