Commit ddd1ea56 authored by J. Bruce Fields's avatar J. Bruce Fields

nfsd4: use xdr_reserve_space in attribute encoding

This is a cosmetic change for now; no change in behavior.

Note we're just depending on xdr_reserve_space to do the bounds checking
for us, we're not really depending on its adjustment of iovec or xdr_buf
lengths yet, as those are fixed up by as necessary after the fact by
read-link operations and by nfs4svc_encode_compoundres.  However we do
have to update xdr->iov on read-like operations to prevent
xdr_reserve_space from messing with the already-fixed-up length of the
the head.

When the attribute encoding fails partway through we have to undo the
length adjustments made so far.  We do it manually for now, but later
patches will add an xdr_truncate_encode() helper to handle cases like
this.
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 5f4ab945
...@@ -49,7 +49,7 @@ struct svc_rqst; ...@@ -49,7 +49,7 @@ struct svc_rqst;
struct nfs4_acl *nfs4_acl_new(int); struct nfs4_acl *nfs4_acl_new(int);
int nfs4_acl_get_whotype(char *, u32); int nfs4_acl_get_whotype(char *, u32);
__be32 nfs4_acl_write_who(int who, __be32 **p, int *len); __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who);
int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
struct nfs4_acl **acl); struct nfs4_acl **acl);
......
...@@ -56,7 +56,7 @@ static inline void nfsd_idmap_shutdown(struct net *net) ...@@ -56,7 +56,7 @@ static inline void nfsd_idmap_shutdown(struct net *net)
__be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, kuid_t *); __be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, kuid_t *);
__be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, kgid_t *); __be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, kgid_t *);
__be32 nfsd4_encode_user(struct svc_rqst *, kuid_t, __be32 **, int *); __be32 nfsd4_encode_user(struct xdr_stream *, struct svc_rqst *, kuid_t);
__be32 nfsd4_encode_group(struct svc_rqst *, kgid_t, __be32 **, int *); __be32 nfsd4_encode_group(struct xdr_stream *, struct svc_rqst *, kgid_t);
#endif /* LINUX_NFSD_IDMAP_H */ #endif /* LINUX_NFSD_IDMAP_H */
...@@ -919,20 +919,19 @@ nfs4_acl_get_whotype(char *p, u32 len) ...@@ -919,20 +919,19 @@ nfs4_acl_get_whotype(char *p, u32 len)
return NFS4_ACL_WHO_NAMED; return NFS4_ACL_WHO_NAMED;
} }
__be32 nfs4_acl_write_who(int who, __be32 **p, int *len) __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who)
{ {
__be32 *p;
int i; int i;
int bytes;
for (i = 0; i < ARRAY_SIZE(s2t_map); i++) { for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
if (s2t_map[i].type != who) if (s2t_map[i].type != who)
continue; continue;
bytes = 4 + (XDR_QUADLEN(s2t_map[i].stringlen) << 2); p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4);
if (bytes > *len) if (!p)
return nfserr_resource; return nfserr_resource;
*p = xdr_encode_opaque(*p, s2t_map[i].string, p = xdr_encode_opaque(p, s2t_map[i].string,
s2t_map[i].stringlen); s2t_map[i].stringlen);
*len -= bytes;
return 0; return 0;
} }
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
......
...@@ -551,44 +551,43 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen ...@@ -551,44 +551,43 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
return 0; return 0;
} }
static __be32 encode_ascii_id(u32 id, __be32 **p, int *buflen) static __be32 encode_ascii_id(struct xdr_stream *xdr, u32 id)
{ {
char buf[11]; char buf[11];
int len; int len;
int bytes; __be32 *p;
len = sprintf(buf, "%u", id); len = sprintf(buf, "%u", id);
bytes = 4 + (XDR_QUADLEN(len) << 2); p = xdr_reserve_space(xdr, len + 4);
if (bytes > *buflen) if (!p)
return nfserr_resource; return nfserr_resource;
*p = xdr_encode_opaque(*p, buf, len); p = xdr_encode_opaque(p, buf, len);
*buflen -= bytes;
return 0; return 0;
} }
static __be32 idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, __be32 **p, int *buflen) static __be32 idmap_id_to_name(struct xdr_stream *xdr,
struct svc_rqst *rqstp, int type, u32 id)
{ {
struct ent *item, key = { struct ent *item, key = {
.id = id, .id = id,
.type = type, .type = type,
}; };
__be32 *p;
int ret; int ret;
int bytes;
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
if (ret == -ENOENT) if (ret == -ENOENT)
return encode_ascii_id(id, p, buflen); return encode_ascii_id(xdr, id);
if (ret) if (ret)
return nfserrno(ret); return nfserrno(ret);
ret = strlen(item->name); ret = strlen(item->name);
WARN_ON_ONCE(ret > IDMAP_NAMESZ); WARN_ON_ONCE(ret > IDMAP_NAMESZ);
bytes = 4 + (XDR_QUADLEN(ret) << 2); p = xdr_reserve_space(xdr, ret + 4);
if (bytes > *buflen) if (!p)
return nfserr_resource; return nfserr_resource;
*p = xdr_encode_opaque(*p, item->name, ret); p = xdr_encode_opaque(p, item->name, ret);
*buflen -= bytes;
cache_put(&item->h, nn->idtoname_cache); cache_put(&item->h, nn->idtoname_cache);
return 0; return 0;
} }
...@@ -622,11 +621,12 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u ...@@ -622,11 +621,12 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u
return idmap_name_to_id(rqstp, type, name, namelen, id); return idmap_name_to_id(rqstp, type, name, namelen, id);
} }
static __be32 encode_name_from_id(struct svc_rqst *rqstp, int type, u32 id, __be32 **p, int *buflen) static __be32 encode_name_from_id(struct xdr_stream *xdr,
struct svc_rqst *rqstp, int type, u32 id)
{ {
if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS) if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
return encode_ascii_id(id, p, buflen); return encode_ascii_id(xdr, id);
return idmap_id_to_name(rqstp, type, id, p, buflen); return idmap_id_to_name(xdr, rqstp, type, id);
} }
__be32 __be32
...@@ -655,14 +655,16 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen, ...@@ -655,14 +655,16 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
return status; return status;
} }
__be32 nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t uid, __be32 **p, int *buflen) __be32 nfsd4_encode_user(struct xdr_stream *xdr, struct svc_rqst *rqstp,
kuid_t uid)
{ {
u32 id = from_kuid(&init_user_ns, uid); u32 id = from_kuid(&init_user_ns, uid);
return encode_name_from_id(rqstp, IDMAP_TYPE_USER, id, p, buflen); return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_USER, id);
} }
__be32 nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t gid, __be32 **p, int *buflen) __be32 nfsd4_encode_group(struct xdr_stream *xdr, struct svc_rqst *rqstp,
kgid_t gid)
{ {
u32 id = from_kgid(&init_user_ns, gid); u32 id = from_kgid(&init_user_ns, gid);
return encode_name_from_id(rqstp, IDMAP_TYPE_GROUP, id, p, buflen); return encode_name_from_id(xdr, rqstp, IDMAP_TYPE_GROUP, id);
} }
...@@ -1259,6 +1259,7 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp, ...@@ -1259,6 +1259,7 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp,
struct kvec *head = buf->head; struct kvec *head = buf->head;
xdr->buf = buf; xdr->buf = buf;
xdr->iov = head;
xdr->p = head->iov_base + head->iov_len; xdr->p = head->iov_base + head->iov_len;
xdr->end = head->iov_base + PAGE_SIZE - 2 * RPC_MAX_AUTH_SIZE; xdr->end = head->iov_base + PAGE_SIZE - 2 * RPC_MAX_AUTH_SIZE;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment