mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
@@ -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;
|
||||
|
||||
if ((len -= 3*4) < 0)
|
||||
svcxdr_init_decode(rqstp);
|
||||
|
||||
/*
|
||||
* 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:
|
||||
|
||||
Reference in New Issue
Block a user