mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 20:54:03 +02:00
SUNRPC: Convert the svcauth_gss_accept() pre-amble to use xdr_stream
Done as part of hardening the server-side RPC header decoding path. Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
6734706bc0
commit
b0bc53470d
|
|
@ -697,23 +697,6 @@ static inline u32 round_up_to_quad(u32 i)
|
||||||
return (i + 3 ) & ~3;
|
return (i + 3 ) & ~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
|
|
||||||
{
|
|
||||||
int l;
|
|
||||||
|
|
||||||
if (argv->iov_len < 4)
|
|
||||||
return -1;
|
|
||||||
o->len = svc_getnl(argv);
|
|
||||||
l = round_up_to_quad(o->len);
|
|
||||||
if (argv->iov_len < l)
|
|
||||||
return -1;
|
|
||||||
o->data = argv->iov_base;
|
|
||||||
argv->iov_base += l;
|
|
||||||
argv->iov_len -= l;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
|
svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
|
||||||
{
|
{
|
||||||
|
|
@ -1553,27 +1536,91 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) {}
|
||||||
#endif /* CONFIG_PROC_FS */
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Accept an rpcsec packet.
|
* The Call's credential body should contain a struct rpc_gss_cred_t.
|
||||||
* If context establishment, punt to user space
|
*
|
||||||
* If data exchange, verify/decrypt
|
* RFC 2203 Section 5
|
||||||
* If context destruction, handle here
|
*
|
||||||
* In the context establishment and destruction case we encode
|
* struct rpc_gss_cred_t {
|
||||||
* response here and return SVC_COMPLETE.
|
* union switch (unsigned int version) {
|
||||||
|
* case RPCSEC_GSS_VERS_1:
|
||||||
|
* struct {
|
||||||
|
* rpc_gss_proc_t gss_proc;
|
||||||
|
* unsigned int seq_num;
|
||||||
|
* rpc_gss_service_t service;
|
||||||
|
* opaque handle<>;
|
||||||
|
* } rpc_gss_cred_vers_1_t;
|
||||||
|
* }
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
svcauth_gss_decode_credbody(struct xdr_stream *xdr,
|
||||||
|
struct rpc_gss_wire_cred *gc,
|
||||||
|
__be32 **rpcstart)
|
||||||
|
{
|
||||||
|
ssize_t handle_len;
|
||||||
|
u32 body_len;
|
||||||
|
__be32 *p;
|
||||||
|
|
||||||
|
p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||||
|
if (!p)
|
||||||
|
return false;
|
||||||
|
/*
|
||||||
|
* start of rpc packet is 7 u32's back from here:
|
||||||
|
* xid direction rpcversion prog vers proc flavour
|
||||||
|
*/
|
||||||
|
*rpcstart = p - 7;
|
||||||
|
body_len = be32_to_cpup(p);
|
||||||
|
if (body_len > RPC_MAX_AUTH_SIZE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* struct rpc_gss_cred_t */
|
||||||
|
if (xdr_stream_decode_u32(xdr, &gc->gc_v) < 0)
|
||||||
|
return false;
|
||||||
|
if (xdr_stream_decode_u32(xdr, &gc->gc_proc) < 0)
|
||||||
|
return false;
|
||||||
|
if (xdr_stream_decode_u32(xdr, &gc->gc_seq) < 0)
|
||||||
|
return false;
|
||||||
|
if (xdr_stream_decode_u32(xdr, &gc->gc_svc) < 0)
|
||||||
|
return false;
|
||||||
|
handle_len = xdr_stream_decode_opaque_inline(xdr,
|
||||||
|
(void **)&gc->gc_ctx.data,
|
||||||
|
body_len);
|
||||||
|
if (handle_len < 0)
|
||||||
|
return false;
|
||||||
|
if (body_len != XDR_UNIT * 5 + xdr_align_size(handle_len))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
gc->gc_ctx.len = handle_len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* svcauth_gss_accept - Decode and validate incoming RPC_AUTH_GSS credential
|
||||||
|
* @rqstp: RPC transaction
|
||||||
|
*
|
||||||
|
* Return values:
|
||||||
|
* %SVC_OK: Success
|
||||||
|
* %SVC_COMPLETE: GSS context lifetime event
|
||||||
|
* %SVC_DENIED: Credential or verifier is not valid
|
||||||
|
* %SVC_GARBAGE: Failed to decode credential or verifier
|
||||||
|
* %SVC_CLOSE: Temporary failure
|
||||||
|
*
|
||||||
|
* The rqstp->rq_auth_stat field is also set (see RFCs 2203 and 5531).
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
svcauth_gss_accept(struct svc_rqst *rqstp)
|
svcauth_gss_accept(struct svc_rqst *rqstp)
|
||||||
{
|
{
|
||||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
|
||||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||||
u32 crlen;
|
|
||||||
struct gss_svc_data *svcdata = rqstp->rq_auth_data;
|
struct gss_svc_data *svcdata = rqstp->rq_auth_data;
|
||||||
|
__be32 *rpcstart;
|
||||||
struct rpc_gss_wire_cred *gc;
|
struct rpc_gss_wire_cred *gc;
|
||||||
struct rsc *rsci = NULL;
|
struct rsc *rsci = NULL;
|
||||||
__be32 *rpcstart;
|
|
||||||
__be32 *reject_stat = resv->iov_base + resv->iov_len;
|
__be32 *reject_stat = resv->iov_base + resv->iov_len;
|
||||||
int ret;
|
int ret;
|
||||||
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
|
struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
|
||||||
|
|
||||||
|
svcxdr_init_decode(rqstp);
|
||||||
|
|
||||||
rqstp->rq_auth_stat = rpc_autherr_badcred;
|
rqstp->rq_auth_stat = rpc_autherr_badcred;
|
||||||
if (!svcdata)
|
if (!svcdata)
|
||||||
svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
|
svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
|
||||||
|
|
@ -1584,31 +1631,10 @@ svcauth_gss_accept(struct svc_rqst *rqstp)
|
||||||
svcdata->rsci = NULL;
|
svcdata->rsci = NULL;
|
||||||
gc = &svcdata->clcred;
|
gc = &svcdata->clcred;
|
||||||
|
|
||||||
/* start of rpc packet is 7 u32's back from here:
|
if (!svcauth_gss_decode_credbody(&rqstp->rq_arg_stream, gc, &rpcstart))
|
||||||
* xid direction rpcversion prog vers proc flavour
|
|
||||||
*/
|
|
||||||
rpcstart = argv->iov_base;
|
|
||||||
rpcstart -= 7;
|
|
||||||
|
|
||||||
/* credential is:
|
|
||||||
* version(==1), proc(0,1,2,3), seq, service (1,2,3), handle
|
|
||||||
* at least 5 u32s, and is preceded by length, so that makes 6.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (argv->iov_len < 5 * 4)
|
|
||||||
goto auth_err;
|
goto auth_err;
|
||||||
crlen = svc_getnl(argv);
|
if (gc->gc_v != RPC_GSS_VERSION)
|
||||||
if (svc_getnl(argv) != RPC_GSS_VERSION)
|
|
||||||
goto auth_err;
|
goto auth_err;
|
||||||
gc->gc_proc = svc_getnl(argv);
|
|
||||||
gc->gc_seq = svc_getnl(argv);
|
|
||||||
gc->gc_svc = svc_getnl(argv);
|
|
||||||
if (svc_safe_getnetobj(argv, &gc->gc_ctx))
|
|
||||||
goto auth_err;
|
|
||||||
if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
|
|
||||||
goto auth_err;
|
|
||||||
|
|
||||||
svcxdr_init_decode(rqstp);
|
|
||||||
|
|
||||||
switch (gc->gc_proc) {
|
switch (gc->gc_proc) {
|
||||||
case RPC_GSS_PROC_INIT:
|
case RPC_GSS_PROC_INIT:
|
||||||
|
|
@ -1621,7 +1647,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp)
|
||||||
goto auth_err;
|
goto auth_err;
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case RPC_GSS_PROC_DATA:
|
case RPC_GSS_PROC_DATA:
|
||||||
/* Look up the context, and check the verifier: */
|
|
||||||
rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
|
rqstp->rq_auth_stat = rpcsec_gsserr_credproblem;
|
||||||
rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
|
rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
|
||||||
if (!rsci)
|
if (!rsci)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user