Commit 6181b0c6 authored by Chuck Lever's avatar Chuck Lever

SUNRPC: Convert svcauth_unix_accept() to use xdr_stream

Done as part of hardening the server-side RPC header decoding path.

Since the server-side of the Linux kernel SunRPC implementation
ignores the contents of the Call's machinename field, there's no
need for its RPC_AUTH_UNIX authenticator to reject names that are
larger than UNX_MAXNODENAME.
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent bee13639
......@@ -34,6 +34,11 @@ enum rpc_auth_flavors {
RPC_AUTH_GSS_SPKMP = 390011,
};
/* Maximum size (in octets) of the machinename in an AUTH_UNIX
* credential (per RFC 5531 Appendix A)
*/
#define RPC_MAX_MACHINENAME (255)
/* Maximum size (in bytes) of an rpc credential or verifier */
#define RPC_MAX_AUTH_SIZE (400)
......
......@@ -867,26 +867,45 @@ struct auth_ops svcauth_tls = {
};
/**
* svcauth_unix_accept - Decode and validate incoming RPC_AUTH_SYS credential
* @rqstp: RPC transaction
*
* Return values:
* %SVC_OK: Both credential and verifier are valid
* %SVC_DENIED: Credential or verifier is not valid
* %SVC_GARBAGE: Failed to decode credential or verifier
* %SVC_CLOSE: Temporary failure
*
* rqstp->rq_auth_stat is set as mandated by RFC 5531.
*/
static int
svcauth_unix_accept(struct svc_rqst *rqstp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
struct xdr_stream *xdr = &rqstp->rq_arg_stream;
struct svc_cred *cred = &rqstp->rq_cred;
struct user_namespace *userns;
u32 slen, i;
int len = argv->iov_len;
u32 flavor, len, i;
void *body;
__be32 *p;
svcxdr_init_decode(rqstp);
if ((len -= 3*4) < 0)
/*
* This implementation ignores the length of the Call's
* credential body field and the timestamp and machinename
* fields.
*/
p = xdr_inline_decode(xdr, XDR_UNIT * 3);
if (!p)
return SVC_GARBAGE;
len = be32_to_cpup(p + 2);
if (len > RPC_MAX_MACHINENAME)
return SVC_GARBAGE;
if (!xdr_inline_decode(xdr, len))
return SVC_GARBAGE;
svc_getu32(argv); /* length */
svc_getu32(argv); /* time stamp */
slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */
if (slen > 64 || (len -= (slen + 3)*4) < 0)
goto badcred;
argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */
argv->iov_len -= slen*4;
/*
* Note: we skip uid_valid()/gid_valid() checks here for
* backwards compatibility with clients that use -1 id's.
......@@ -896,20 +915,33 @@ svcauth_unix_accept(struct svc_rqst *rqstp)
*/
userns = (rqstp->rq_xprt && rqstp->rq_xprt->xpt_cred) ?
rqstp->rq_xprt->xpt_cred->user_ns : &init_user_ns;
cred->cr_uid = make_kuid(userns, svc_getnl(argv)); /* uid */
cred->cr_gid = make_kgid(userns, svc_getnl(argv)); /* gid */
slen = svc_getnl(argv); /* gids length */
if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
if (xdr_stream_decode_u32(xdr, &i) < 0)
return SVC_GARBAGE;
cred->cr_uid = make_kuid(userns, i);
if (xdr_stream_decode_u32(xdr, &i) < 0)
return SVC_GARBAGE;
cred->cr_gid = make_kgid(userns, i);
if (xdr_stream_decode_u32(xdr, &len) < 0)
return SVC_GARBAGE;
if (len > UNX_NGROUPS)
goto badcred;
cred->cr_group_info = groups_alloc(slen);
p = xdr_inline_decode(xdr, XDR_UNIT * len);
if (!p)
return SVC_GARBAGE;
cred->cr_group_info = groups_alloc(len);
if (cred->cr_group_info == NULL)
return SVC_CLOSE;
for (i = 0; i < slen; i++) {
kgid_t kgid = make_kgid(userns, svc_getnl(argv));
for (i = 0; i < len; i++) {
kgid_t kgid = make_kgid(userns, be32_to_cpup(p++));
cred->cr_group_info->gid[i] = kgid;
}
groups_sort(cred->cr_group_info);
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
/* Call's verf field: */
if (xdr_stream_decode_opaque_auth(xdr, &flavor, &body, &len) < 0)
return SVC_GARBAGE;
if (flavor != RPC_AUTH_NULL || len != 0) {
rqstp->rq_auth_stat = rpc_autherr_badverf;
return SVC_DENIED;
}
......@@ -919,7 +951,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp)
svc_putnl(resv, 0);
rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
svcxdr_init_decode(rqstp);
return SVC_OK;
badcred:
......
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