From 5d12e9340eafe1e230472e4018fc5d6501f8d3ce Mon Sep 17 00:00:00 2001 From: ZhangXiaoxu Date: Wed, 12 Jun 2019 21:53:31 +0800 Subject: [PATCH] SUNRPC: Use struct xdr_stream when decoding RPC Reply header mainline inclusion from mainline-v5.1-rc1 commit a0584ee9aed805446b044ce855e67264f0dc619e category: bugfix bugzilla: 13061 CVE: NA ----------------------------------------------- Modernize and harden the code path that parses an RPC Reply message. Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker Conflict: include/linux/sunrpc/auth.h include/linux/sunrpc/xdr.h net/sunrpc/auth.c net/sunrpc/auth_gss/auth_gss.c net/sunrpc/auth_null.c net/sunrpc/clnt.c Partly merged because it can fix xfstests generic/095 failed with WARN_ON when call_decode. eb90a16e9087 ("SUNRPC: rpc_decode_header() must always return a non-zero value on error") is not needed because we not merge the code: error = rpcauth_checkverf(task, xdr) Signed-off-by: ZhangXiaoxu Reviewed-by: yangerkun Signed-off-by: Yang Yingliang --- net/sunrpc/auth_gss/auth_gss.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index ae22ec632d8e..735109a3f312 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -1919,6 +1919,15 @@ gss_wrap_req(struct rpc_task *task, return status; } +static inline int +gss_unwrap_resp_auth(struct rpc_cred *cred) +{ + struct rpc_auth *auth = cred->cr_auth; + + auth->au_rslack = auth->au_verfsize; + return 0; +} + static inline int gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, struct rpc_rqst *rqstp, __be32 **p) @@ -1930,6 +1939,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, u32 integ_len; u32 maj_stat; int status = -EIO; + struct rpc_auth *auth = cred->cr_auth; integ_len = ntohl(*(*p)++); if (integ_len & 3) @@ -1953,6 +1963,8 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); if (maj_stat != GSS_S_COMPLETE) return status; + + auth->au_rslack = auth->au_verfsize + 2 + 1 + XDR_QUADLEN(mic.len); return 0; } @@ -1965,6 +1977,8 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, u32 opaque_len; u32 maj_stat; int status = -EIO; + unsigned int savedlen = rcv_buf->len; + struct rpc_auth *auth = cred->cr_auth; opaque_len = ntohl(*(*p)++); offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; @@ -1981,6 +1995,8 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, if (ntohl(*(*p)++) != rqstp->rq_seqno) return status; + auth->au_rslack = auth->au_verfsize + 2 + XDR_QUADLEN(savedlen - rcv_buf->len); + return 0; } @@ -2002,15 +2018,13 @@ gss_unwrap_resp(struct rpc_task *task, struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); - __be32 *savedp = p; - struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; - int savedlen = head->iov_len; int status = -EIO; if (ctx->gc_proc != RPC_GSS_PROC_DATA) goto out_decode; switch (gss_cred->gc_service) { case RPC_GSS_SVC_NONE: + status = gss_unwrap_resp_auth(cred); break; case RPC_GSS_SVC_INTEGRITY: status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p); @@ -2023,9 +2037,6 @@ gss_unwrap_resp(struct rpc_task *task, goto out; break; } - /* take into account extra slack for integrity and privacy cases: */ - cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) - + (savedlen - head->iov_len); out_decode: status = gss_unwrap_req_decode(decode, rqstp, p, obj); out: -- GitLab