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 | } |