mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	SUNRPC: Use struct xdr_stream when decoding RPC Reply header
Modernize and harden the code path that parses an RPC Reply message. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
This commit is contained in:
		
							parent
							
								
									7f5667a5f8
								
							
						
					
					
						commit
						a0584ee9ae
					
				
					 7 changed files with 241 additions and 199 deletions
				
			
		| 
						 | 
					@ -134,11 +134,12 @@ struct rpc_credops {
 | 
				
			||||||
	int			(*crmarshal)(struct rpc_task *task,
 | 
						int			(*crmarshal)(struct rpc_task *task,
 | 
				
			||||||
					     struct xdr_stream *xdr);
 | 
										     struct xdr_stream *xdr);
 | 
				
			||||||
	int			(*crrefresh)(struct rpc_task *);
 | 
						int			(*crrefresh)(struct rpc_task *);
 | 
				
			||||||
	__be32 *		(*crvalidate)(struct rpc_task *, __be32 *);
 | 
						int			(*crvalidate)(struct rpc_task *task,
 | 
				
			||||||
 | 
										      struct xdr_stream *xdr);
 | 
				
			||||||
	int			(*crwrap_req)(struct rpc_task *task,
 | 
						int			(*crwrap_req)(struct rpc_task *task,
 | 
				
			||||||
					      struct xdr_stream *xdr);
 | 
										      struct xdr_stream *xdr);
 | 
				
			||||||
	int			(*crunwrap_resp)(struct rpc_task *, kxdrdproc_t,
 | 
						int			(*crunwrap_resp)(struct rpc_task *task,
 | 
				
			||||||
						void *, __be32 *, void *);
 | 
											 struct xdr_stream *xdr);
 | 
				
			||||||
	int			(*crkey_timeout)(struct rpc_cred *);
 | 
						int			(*crkey_timeout)(struct rpc_cred *);
 | 
				
			||||||
	char *			(*crstringify_acceptor)(struct rpc_cred *);
 | 
						char *			(*crstringify_acceptor)(struct rpc_cred *);
 | 
				
			||||||
	bool			(*crneed_reencode)(struct rpc_task *);
 | 
						bool			(*crneed_reencode)(struct rpc_task *);
 | 
				
			||||||
| 
						 | 
					@ -168,12 +169,16 @@ struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *, int);
 | 
				
			||||||
void			put_rpccred(struct rpc_cred *);
 | 
					void			put_rpccred(struct rpc_cred *);
 | 
				
			||||||
int			rpcauth_marshcred(struct rpc_task *task,
 | 
					int			rpcauth_marshcred(struct rpc_task *task,
 | 
				
			||||||
					  struct xdr_stream *xdr);
 | 
										  struct xdr_stream *xdr);
 | 
				
			||||||
__be32 *		rpcauth_checkverf(struct rpc_task *, __be32 *);
 | 
					int			rpcauth_checkverf(struct rpc_task *task,
 | 
				
			||||||
 | 
										  struct xdr_stream *xdr);
 | 
				
			||||||
int			rpcauth_wrap_req_encode(struct rpc_task *task,
 | 
					int			rpcauth_wrap_req_encode(struct rpc_task *task,
 | 
				
			||||||
						struct xdr_stream *xdr);
 | 
											struct xdr_stream *xdr);
 | 
				
			||||||
int			rpcauth_wrap_req(struct rpc_task *task,
 | 
					int			rpcauth_wrap_req(struct rpc_task *task,
 | 
				
			||||||
					 struct xdr_stream *xdr);
 | 
										 struct xdr_stream *xdr);
 | 
				
			||||||
int			rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj);
 | 
					int			rpcauth_unwrap_resp_decode(struct rpc_task *task,
 | 
				
			||||||
 | 
											   struct xdr_stream *xdr);
 | 
				
			||||||
 | 
					int			rpcauth_unwrap_resp(struct rpc_task *task,
 | 
				
			||||||
 | 
										    struct xdr_stream *xdr);
 | 
				
			||||||
bool			rpcauth_xmit_need_reencode(struct rpc_task *task);
 | 
					bool			rpcauth_xmit_need_reencode(struct rpc_task *task);
 | 
				
			||||||
int			rpcauth_refreshcred(struct rpc_task *);
 | 
					int			rpcauth_refreshcred(struct rpc_task *);
 | 
				
			||||||
void			rpcauth_invalcred(struct rpc_task *);
 | 
					void			rpcauth_invalcred(struct rpc_task *);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,6 +89,7 @@ xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define	rpc_auth_null	cpu_to_be32(RPC_AUTH_NULL)
 | 
					#define	rpc_auth_null	cpu_to_be32(RPC_AUTH_NULL)
 | 
				
			||||||
#define	rpc_auth_unix	cpu_to_be32(RPC_AUTH_UNIX)
 | 
					#define	rpc_auth_unix	cpu_to_be32(RPC_AUTH_UNIX)
 | 
				
			||||||
 | 
					#define	rpc_auth_short	cpu_to_be32(RPC_AUTH_SHORT)
 | 
				
			||||||
#define	rpc_auth_gss	cpu_to_be32(RPC_AUTH_GSS)
 | 
					#define	rpc_auth_gss	cpu_to_be32(RPC_AUTH_GSS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define	rpc_call	cpu_to_be32(RPC_CALL)
 | 
					#define	rpc_call	cpu_to_be32(RPC_CALL)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,8 @@
 | 
				
			||||||
#include <linux/sunrpc/gss_api.h>
 | 
					#include <linux/sunrpc/gss_api.h>
 | 
				
			||||||
#include <linux/spinlock.h>
 | 
					#include <linux/spinlock.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <trace/events/sunrpc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RPC_CREDCACHE_DEFAULT_HASHBITS	(4)
 | 
					#define RPC_CREDCACHE_DEFAULT_HASHBITS	(4)
 | 
				
			||||||
struct rpc_cred_cache {
 | 
					struct rpc_cred_cache {
 | 
				
			||||||
	struct hlist_head	*hashtable;
 | 
						struct hlist_head	*hashtable;
 | 
				
			||||||
| 
						 | 
					@ -773,14 +775,6 @@ int rpcauth_marshcred(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
	return ops->crmarshal(task, xdr);
 | 
						return ops->crmarshal(task, xdr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__be32 *
 | 
					 | 
				
			||||||
rpcauth_checkverf(struct rpc_task *task, __be32 *p)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rpc_cred	*cred = task->tk_rqstp->rq_cred;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return cred->cr_ops->crvalidate(task, p);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * rpcauth_wrap_req_encode - XDR encode the RPC procedure
 | 
					 * rpcauth_wrap_req_encode - XDR encode the RPC procedure
 | 
				
			||||||
 * @task: controlling RPC task
 | 
					 * @task: controlling RPC task
 | 
				
			||||||
| 
						 | 
					@ -814,27 +808,52 @@ int rpcauth_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
	return ops->crwrap_req(task, xdr);
 | 
						return ops->crwrap_req(task, xdr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					/**
 | 
				
			||||||
rpcauth_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
 | 
					 * rpcauth_checkverf - Validate verifier in RPC Reply header
 | 
				
			||||||
			  __be32 *data, void *obj)
 | 
					 * @task: controlling RPC task
 | 
				
			||||||
 | 
					 * @xdr: xdr_stream containing RPC Reply header
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * On success, @xdr is updated to point past the verifier and
 | 
				
			||||||
 | 
					 * zero is returned. Otherwise, @xdr is in an undefined state
 | 
				
			||||||
 | 
					 * and a negative errno is returned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					rpcauth_checkverf(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct xdr_stream xdr;
 | 
						const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, data, rqstp);
 | 
						return ops->crvalidate(task, xdr);
 | 
				
			||||||
	return decode(rqstp, &xdr, obj);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * rpcauth_unwrap_resp_decode - Invoke XDR decode function
 | 
				
			||||||
 | 
					 * @task: controlling RPC task
 | 
				
			||||||
 | 
					 * @xdr: stream where the Reply message resides
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns zero on success; otherwise a negative errno is returned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
int
 | 
					int
 | 
				
			||||||
rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp,
 | 
					rpcauth_unwrap_resp_decode(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
		__be32 *data, void *obj)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 | 
						kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cred->cr_ops->crunwrap_resp)
 | 
						return decode(task->tk_rqstp, xdr, task->tk_msg.rpc_resp);
 | 
				
			||||||
		return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
 | 
					}
 | 
				
			||||||
						   data, obj);
 | 
					EXPORT_SYMBOL_GPL(rpcauth_unwrap_resp_decode);
 | 
				
			||||||
	/* By default, we decode the arguments normally. */
 | 
					
 | 
				
			||||||
	return rpcauth_unwrap_req_decode(decode, rqstp, data, obj);
 | 
					/**
 | 
				
			||||||
 | 
					 * rpcauth_unwrap_resp - Invoke unwrap and decode function for the cred
 | 
				
			||||||
 | 
					 * @task: controlling RPC task
 | 
				
			||||||
 | 
					 * @xdr: stream where the Reply message resides
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns zero on success; otherwise a negative errno is returned.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					rpcauth_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct rpc_credops *ops = task->tk_rqstp->rq_cred->cr_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ops->crunwrap_resp(task, xdr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool
 | 
					bool
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1671,59 +1671,62 @@ gss_refresh_null(struct rpc_task *task)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __be32 *
 | 
					static int
 | 
				
			||||||
gss_validate(struct rpc_task *task, __be32 *p)
 | 
					gss_validate(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 | 
						struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 | 
				
			||||||
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
 | 
						struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
 | 
				
			||||||
	__be32		*seq = NULL;
 | 
						__be32		*p, *seq = NULL;
 | 
				
			||||||
	struct kvec	iov;
 | 
						struct kvec	iov;
 | 
				
			||||||
	struct xdr_buf	verf_buf;
 | 
						struct xdr_buf	verf_buf;
 | 
				
			||||||
	struct xdr_netobj mic;
 | 
						struct xdr_netobj mic;
 | 
				
			||||||
	u32		flav,len;
 | 
						u32		len, maj_stat;
 | 
				
			||||||
	u32		maj_stat;
 | 
						int		status;
 | 
				
			||||||
	__be32		*ret = ERR_PTR(-EIO);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
 | 
						p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							goto validate_failed;
 | 
				
			||||||
 | 
						if (*p++ != rpc_auth_gss)
 | 
				
			||||||
 | 
							goto validate_failed;
 | 
				
			||||||
 | 
						len = be32_to_cpup(p);
 | 
				
			||||||
 | 
						if (len > RPC_MAX_AUTH_SIZE)
 | 
				
			||||||
 | 
							goto validate_failed;
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, len);
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							goto validate_failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flav = ntohl(*p++);
 | 
					 | 
				
			||||||
	if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
 | 
					 | 
				
			||||||
		goto out_bad;
 | 
					 | 
				
			||||||
	if (flav != RPC_AUTH_GSS)
 | 
					 | 
				
			||||||
		goto out_bad;
 | 
					 | 
				
			||||||
	seq = kmalloc(4, GFP_NOFS);
 | 
						seq = kmalloc(4, GFP_NOFS);
 | 
				
			||||||
	if (!seq)
 | 
						if (!seq)
 | 
				
			||||||
		goto out_bad;
 | 
							goto validate_failed;
 | 
				
			||||||
	*seq = htonl(task->tk_rqstp->rq_seqno);
 | 
						*seq = cpu_to_be32(task->tk_rqstp->rq_seqno);
 | 
				
			||||||
	iov.iov_base = seq;
 | 
						iov.iov_base = seq;
 | 
				
			||||||
	iov.iov_len = 4;
 | 
						iov.iov_len = 4;
 | 
				
			||||||
	xdr_buf_from_iov(&iov, &verf_buf);
 | 
						xdr_buf_from_iov(&iov, &verf_buf);
 | 
				
			||||||
	mic.data = (u8 *)p;
 | 
						mic.data = (u8 *)p;
 | 
				
			||||||
	mic.len = len;
 | 
						mic.len = len;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	ret = ERR_PTR(-EACCES);
 | 
					 | 
				
			||||||
	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
 | 
						maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
 | 
				
			||||||
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
						if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
				
			||||||
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
							clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
				
			||||||
	if (maj_stat) {
 | 
						if (maj_stat)
 | 
				
			||||||
		dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
 | 
							goto bad_mic;
 | 
				
			||||||
			task->tk_pid, __func__, maj_stat);
 | 
					
 | 
				
			||||||
		goto out_bad;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* We leave it to unwrap to calculate au_rslack. For now we just
 | 
						/* We leave it to unwrap to calculate au_rslack. For now we just
 | 
				
			||||||
	 * calculate the length of the verifier: */
 | 
						 * calculate the length of the verifier: */
 | 
				
			||||||
	cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
 | 
						cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
 | 
				
			||||||
 | 
						status = 0;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	gss_put_ctx(ctx);
 | 
						gss_put_ctx(ctx);
 | 
				
			||||||
	dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n",
 | 
					 | 
				
			||||||
			task->tk_pid, __func__);
 | 
					 | 
				
			||||||
	kfree(seq);
 | 
						kfree(seq);
 | 
				
			||||||
	return p + XDR_QUADLEN(len);
 | 
						return status;
 | 
				
			||||||
out_bad:
 | 
					
 | 
				
			||||||
	gss_put_ctx(ctx);
 | 
					validate_failed:
 | 
				
			||||||
	dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__,
 | 
						status = -EIO;
 | 
				
			||||||
		PTR_ERR(ret));
 | 
						goto out;
 | 
				
			||||||
	kfree(seq);
 | 
					bad_mic:
 | 
				
			||||||
	return ret;
 | 
						dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n",
 | 
				
			||||||
 | 
							task->tk_pid, __func__, maj_stat);
 | 
				
			||||||
 | 
						status = -EACCES;
 | 
				
			||||||
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
					static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
				
			||||||
| 
						 | 
					@ -1921,79 +1924,98 @@ static int gss_wrap_req(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
	return status;
 | 
						return status;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static int
 | 
				
			||||||
gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
					gss_unwrap_resp_auth(struct rpc_cred *cred)
 | 
				
			||||||
		struct rpc_rqst *rqstp, __be32 **p)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct xdr_buf	*rcv_buf = &rqstp->rq_rcv_buf;
 | 
						cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize;
 | 
				
			||||||
	struct xdr_buf integ_buf;
 | 
						return 0;
 | 
				
			||||||
	struct xdr_netobj mic;
 | 
					}
 | 
				
			||||||
	u32 data_offset, mic_offset;
 | 
					 | 
				
			||||||
	u32 integ_len;
 | 
					 | 
				
			||||||
	u32 maj_stat;
 | 
					 | 
				
			||||||
	int status = -EIO;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	integ_len = ntohl(*(*p)++);
 | 
					static int
 | 
				
			||||||
 | 
					gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
				
			||||||
 | 
							      struct rpc_rqst *rqstp, struct xdr_stream *xdr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct xdr_buf integ_buf, *rcv_buf = &rqstp->rq_rcv_buf;
 | 
				
			||||||
 | 
						u32 data_offset, mic_offset, integ_len, maj_stat;
 | 
				
			||||||
 | 
						struct xdr_netobj mic;
 | 
				
			||||||
 | 
						__be32 *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 | 
				
			||||||
 | 
						if (unlikely(!p))
 | 
				
			||||||
 | 
							goto unwrap_failed;
 | 
				
			||||||
 | 
						integ_len = be32_to_cpup(p++);
 | 
				
			||||||
	if (integ_len & 3)
 | 
						if (integ_len & 3)
 | 
				
			||||||
		return status;
 | 
							goto unwrap_failed;
 | 
				
			||||||
	data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
 | 
						data_offset = (u8 *)(p) - (u8 *)rcv_buf->head[0].iov_base;
 | 
				
			||||||
	mic_offset = integ_len + data_offset;
 | 
						mic_offset = integ_len + data_offset;
 | 
				
			||||||
	if (mic_offset > rcv_buf->len)
 | 
						if (mic_offset > rcv_buf->len)
 | 
				
			||||||
		return status;
 | 
							goto unwrap_failed;
 | 
				
			||||||
	if (ntohl(*(*p)++) != rqstp->rq_seqno)
 | 
						if (be32_to_cpup(p) != rqstp->rq_seqno)
 | 
				
			||||||
		return status;
 | 
							goto unwrap_failed;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
 | 
					 | 
				
			||||||
				mic_offset - data_offset))
 | 
					 | 
				
			||||||
		return status;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, integ_len))
 | 
				
			||||||
 | 
							goto unwrap_failed;
 | 
				
			||||||
	if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset))
 | 
						if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset))
 | 
				
			||||||
		return status;
 | 
							goto unwrap_failed;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
 | 
						maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
 | 
				
			||||||
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
						if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
				
			||||||
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
							clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
				
			||||||
	if (maj_stat != GSS_S_COMPLETE)
 | 
						if (maj_stat != GSS_S_COMPLETE)
 | 
				
			||||||
		return status;
 | 
							goto bad_mic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 +
 | 
				
			||||||
 | 
									   1 + XDR_QUADLEN(mic.len);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					unwrap_failed:
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
 | 
					bad_mic:
 | 
				
			||||||
 | 
						dprintk("RPC:       %s: gss_verify_mic returned error 0x%08x\n",
 | 
				
			||||||
 | 
							__func__, maj_stat);
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int
 | 
					static int
 | 
				
			||||||
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
					gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
 | 
				
			||||||
		struct rpc_rqst *rqstp, __be32 **p)
 | 
							     struct rpc_rqst *rqstp, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
 | 
						struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
 | 
				
			||||||
	u32 offset;
 | 
						struct kvec *head = rqstp->rq_rcv_buf.head;
 | 
				
			||||||
	u32 opaque_len;
 | 
						unsigned int savedlen = rcv_buf->len;
 | 
				
			||||||
	u32 maj_stat;
 | 
						u32 offset, opaque_len, maj_stat;
 | 
				
			||||||
	int status = -EIO;
 | 
						__be32 *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	opaque_len = ntohl(*(*p)++);
 | 
						p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 | 
				
			||||||
	offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
 | 
						if (unlikely(!p))
 | 
				
			||||||
 | 
							goto unwrap_failed;
 | 
				
			||||||
 | 
						opaque_len = be32_to_cpup(p++);
 | 
				
			||||||
 | 
						offset = (u8 *)(p) - (u8 *)head->iov_base;
 | 
				
			||||||
	if (offset + opaque_len > rcv_buf->len)
 | 
						if (offset + opaque_len > rcv_buf->len)
 | 
				
			||||||
		return status;
 | 
							goto unwrap_failed;
 | 
				
			||||||
	/* remove padding: */
 | 
					 | 
				
			||||||
	rcv_buf->len = offset + opaque_len;
 | 
						rcv_buf->len = offset + opaque_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
 | 
						maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
 | 
				
			||||||
	if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
						if (maj_stat == GSS_S_CONTEXT_EXPIRED)
 | 
				
			||||||
		clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
							clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
 | 
				
			||||||
	if (maj_stat != GSS_S_COMPLETE)
 | 
						if (maj_stat != GSS_S_COMPLETE)
 | 
				
			||||||
		return status;
 | 
							goto bad_unwrap;
 | 
				
			||||||
	if (ntohl(*(*p)++) != rqstp->rq_seqno)
 | 
						/* gss_unwrap decrypted the sequence number */
 | 
				
			||||||
		return status;
 | 
						if (be32_to_cpup(p++) != rqstp->rq_seqno)
 | 
				
			||||||
 | 
							goto unwrap_failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* gss_unwrap redacts the opaque blob from the head iovec.
 | 
				
			||||||
 | 
						 * rcv_buf has changed, thus the stream needs to be reset.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						xdr_init_decode(xdr, rcv_buf, p, rqstp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 +
 | 
				
			||||||
 | 
									   XDR_QUADLEN(savedlen - rcv_buf->len);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					unwrap_failed:
 | 
				
			||||||
 | 
						return -EIO;
 | 
				
			||||||
static int
 | 
					bad_unwrap:
 | 
				
			||||||
gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp,
 | 
						dprintk("RPC:       %s: gss_unwrap returned error 0x%08x\n",
 | 
				
			||||||
		      __be32 *p, void *obj)
 | 
							__func__, maj_stat);
 | 
				
			||||||
{
 | 
						return -EIO;
 | 
				
			||||||
	struct xdr_stream xdr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p, rqstp);
 | 
					 | 
				
			||||||
	return decode(rqstp, &xdr, obj);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
| 
						 | 
					@ -2037,39 +2059,33 @@ gss_xmit_need_reencode(struct rpc_task *task)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
gss_unwrap_resp(struct rpc_task *task,
 | 
					gss_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
		kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_cred *cred = task->tk_rqstp->rq_cred;
 | 
						struct rpc_rqst *rqstp = task->tk_rqstp;
 | 
				
			||||||
 | 
						struct rpc_cred *cred = rqstp->rq_cred;
 | 
				
			||||||
	struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
 | 
						struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
 | 
				
			||||||
			gc_base);
 | 
								gc_base);
 | 
				
			||||||
	struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
 | 
						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;
 | 
						int status = -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ctx->gc_proc != RPC_GSS_PROC_DATA)
 | 
						if (ctx->gc_proc != RPC_GSS_PROC_DATA)
 | 
				
			||||||
		goto out_decode;
 | 
							goto out_decode;
 | 
				
			||||||
	switch (gss_cred->gc_service) {
 | 
						switch (gss_cred->gc_service) {
 | 
				
			||||||
	case RPC_GSS_SVC_NONE:
 | 
						case RPC_GSS_SVC_NONE:
 | 
				
			||||||
 | 
							status = gss_unwrap_resp_auth(cred);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case RPC_GSS_SVC_INTEGRITY:
 | 
						case RPC_GSS_SVC_INTEGRITY:
 | 
				
			||||||
		status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p);
 | 
							status = gss_unwrap_resp_integ(cred, ctx, rqstp, xdr);
 | 
				
			||||||
		if (status)
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case RPC_GSS_SVC_PRIVACY:
 | 
						case RPC_GSS_SVC_PRIVACY:
 | 
				
			||||||
		status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
 | 
							status = gss_unwrap_resp_priv(cred, ctx, rqstp, xdr);
 | 
				
			||||||
		if (status)
 | 
					 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* take into account extra slack for integrity and privacy cases: */
 | 
						if (status)
 | 
				
			||||||
	cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
 | 
							goto out;
 | 
				
			||||||
						+ (savedlen - head->iov_len);
 | 
					
 | 
				
			||||||
out_decode:
 | 
					out_decode:
 | 
				
			||||||
	status = gss_unwrap_req_decode(decode, rqstp, p, obj);
 | 
						status = rpcauth_unwrap_resp_decode(task, xdr);
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	gss_put_ctx(ctx);
 | 
						gss_put_ctx(ctx);
 | 
				
			||||||
	dprintk("RPC: %5u %s returning %d\n",
 | 
						dprintk("RPC: %5u %s returning %d\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,25 +86,19 @@ nul_refresh(struct rpc_task *task)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __be32 *
 | 
					static int
 | 
				
			||||||
nul_validate(struct rpc_task *task, __be32 *p)
 | 
					nul_validate(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rpc_authflavor_t	flavor;
 | 
						__be32 *p;
 | 
				
			||||||
	u32			size;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flavor = ntohl(*p++);
 | 
						p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 | 
				
			||||||
	if (flavor != RPC_AUTH_NULL) {
 | 
						if (!p)
 | 
				
			||||||
		printk("RPC: bad verf flavor: %u\n", flavor);
 | 
							return -EIO;
 | 
				
			||||||
		return ERR_PTR(-EIO);
 | 
						if (*p++ != rpc_auth_null)
 | 
				
			||||||
	}
 | 
							return -EIO;
 | 
				
			||||||
 | 
						if (*p != xdr_zero)
 | 
				
			||||||
	size = ntohl(*p++);
 | 
							return -EIO;
 | 
				
			||||||
	if (size != 0) {
 | 
						return 0;
 | 
				
			||||||
		printk("RPC: bad verf size: %u\n", size);
 | 
					 | 
				
			||||||
		return ERR_PTR(-EIO);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return p;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct rpc_authops authnull_ops = {
 | 
					const struct rpc_authops authnull_ops = {
 | 
				
			||||||
| 
						 | 
					@ -134,6 +128,7 @@ const struct rpc_credops null_credops = {
 | 
				
			||||||
	.crwrap_req	= rpcauth_wrap_req_encode,
 | 
						.crwrap_req	= rpcauth_wrap_req_encode,
 | 
				
			||||||
	.crrefresh	= nul_refresh,
 | 
						.crrefresh	= nul_refresh,
 | 
				
			||||||
	.crvalidate	= nul_validate,
 | 
						.crvalidate	= nul_validate,
 | 
				
			||||||
 | 
						.crunwrap_resp	= rpcauth_unwrap_resp_decode,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static
 | 
					static
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,29 +160,32 @@ unx_refresh(struct rpc_task *task)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __be32 *
 | 
					static int
 | 
				
			||||||
unx_validate(struct rpc_task *task, __be32 *p)
 | 
					unx_validate(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rpc_authflavor_t	flavor;
 | 
						__be32 *p;
 | 
				
			||||||
	u32 size;
 | 
						u32 size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flavor = ntohl(*p++);
 | 
						p = xdr_inline_decode(xdr, 2 * sizeof(*p));
 | 
				
			||||||
	if (flavor != RPC_AUTH_NULL &&
 | 
						if (!p)
 | 
				
			||||||
	    flavor != RPC_AUTH_UNIX &&
 | 
							return -EIO;
 | 
				
			||||||
	    flavor != RPC_AUTH_SHORT) {
 | 
						switch (*p++) {
 | 
				
			||||||
		printk("RPC: bad verf flavor: %u\n", flavor);
 | 
						case rpc_auth_null:
 | 
				
			||||||
		return ERR_PTR(-EIO);
 | 
						case rpc_auth_unix:
 | 
				
			||||||
 | 
						case rpc_auth_short:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						size = be32_to_cpup(p);
 | 
				
			||||||
 | 
						if (size > RPC_MAX_AUTH_SIZE)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, size);
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size = ntohl(*p++);
 | 
					 | 
				
			||||||
	if (size > RPC_MAX_AUTH_SIZE) {
 | 
					 | 
				
			||||||
		printk("RPC: giant verf size: %u\n", size);
 | 
					 | 
				
			||||||
		return ERR_PTR(-EIO);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
 | 
						task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
 | 
				
			||||||
	p += (size >> 2);
 | 
						return 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return p;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __init rpc_init_authunix(void)
 | 
					int __init rpc_init_authunix(void)
 | 
				
			||||||
| 
						 | 
					@ -223,4 +226,5 @@ const struct rpc_credops unix_credops = {
 | 
				
			||||||
	.crwrap_req	= rpcauth_wrap_req_encode,
 | 
						.crwrap_req	= rpcauth_wrap_req_encode,
 | 
				
			||||||
	.crrefresh	= unx_refresh,
 | 
						.crrefresh	= unx_refresh,
 | 
				
			||||||
	.crvalidate	= unx_validate,
 | 
						.crvalidate	= unx_validate,
 | 
				
			||||||
 | 
						.crunwrap_resp	= rpcauth_unwrap_resp_decode,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,8 @@ static void	call_connect_status(struct rpc_task *task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int	rpc_encode_header(struct rpc_task *task,
 | 
					static int	rpc_encode_header(struct rpc_task *task,
 | 
				
			||||||
				  struct xdr_stream *xdr);
 | 
									  struct xdr_stream *xdr);
 | 
				
			||||||
static __be32	*rpc_decode_header(struct rpc_task *task);
 | 
					static int	rpc_decode_header(struct rpc_task *task,
 | 
				
			||||||
 | 
									  struct xdr_stream *xdr);
 | 
				
			||||||
static int	rpc_ping(struct rpc_clnt *clnt);
 | 
					static int	rpc_ping(struct rpc_clnt *clnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void rpc_register_client(struct rpc_clnt *clnt)
 | 
					static void rpc_register_client(struct rpc_clnt *clnt)
 | 
				
			||||||
| 
						 | 
					@ -2251,12 +2252,11 @@ call_decode(struct rpc_task *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_clnt	*clnt = task->tk_client;
 | 
						struct rpc_clnt	*clnt = task->tk_client;
 | 
				
			||||||
	struct rpc_rqst	*req = task->tk_rqstp;
 | 
						struct rpc_rqst	*req = task->tk_rqstp;
 | 
				
			||||||
	kxdrdproc_t	decode = task->tk_msg.rpc_proc->p_decode;
 | 
						struct xdr_stream xdr;
 | 
				
			||||||
	__be32		*p;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dprint_status(task);
 | 
						dprint_status(task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!decode) {
 | 
						if (!task->tk_msg.rpc_proc->p_decode) {
 | 
				
			||||||
		task->tk_action = rpc_exit_task;
 | 
							task->tk_action = rpc_exit_task;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2292,31 +2292,29 @@ call_decode(struct rpc_task *task)
 | 
				
			||||||
		goto out_retry;
 | 
							goto out_retry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = rpc_decode_header(task);
 | 
						xdr_init_decode(&xdr, &req->rq_rcv_buf,
 | 
				
			||||||
	if (IS_ERR(p)) {
 | 
								req->rq_rcv_buf.head[0].iov_base, req);
 | 
				
			||||||
		if (p == ERR_PTR(-EAGAIN))
 | 
						switch (rpc_decode_header(task, &xdr)) {
 | 
				
			||||||
			goto out_retry;
 | 
						case 0:
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		task->tk_action = rpc_exit_task;
 | 
							task->tk_action = rpc_exit_task;
 | 
				
			||||||
 | 
							task->tk_status = rpcauth_unwrap_resp(task, &xdr);
 | 
				
			||||||
	task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
 | 
							dprintk("RPC: %5u %s result %d\n",
 | 
				
			||||||
					      task->tk_msg.rpc_resp);
 | 
								task->tk_pid, __func__, task->tk_status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,
 | 
					 | 
				
			||||||
			task->tk_status);
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
						case -EAGAIN:
 | 
				
			||||||
out_retry:
 | 
					out_retry:
 | 
				
			||||||
		task->tk_status = 0;
 | 
							task->tk_status = 0;
 | 
				
			||||||
		/* Note: rpc_decode_header() may have freed the RPC slot */
 | 
							/* Note: rpc_decode_header() may have freed the RPC slot */
 | 
				
			||||||
		if (task->tk_rqstp == req) {
 | 
							if (task->tk_rqstp == req) {
 | 
				
			||||||
			xdr_free_bvec(&req->rq_rcv_buf);
 | 
								xdr_free_bvec(&req->rq_rcv_buf);
 | 
				
			||||||
		req->rq_reply_bytes_recvd = req->rq_rcv_buf.len = 0;
 | 
								req->rq_reply_bytes_recvd = 0;
 | 
				
			||||||
 | 
								req->rq_rcv_buf.len = 0;
 | 
				
			||||||
			if (task->tk_client->cl_discrtry)
 | 
								if (task->tk_client->cl_discrtry)
 | 
				
			||||||
				xprt_conditional_disconnect(req->rq_xprt,
 | 
									xprt_conditional_disconnect(req->rq_xprt,
 | 
				
			||||||
							    req->rq_connect_cookie);
 | 
												    req->rq_connect_cookie);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
 | 
					rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
| 
						 | 
					@ -2347,14 +2345,12 @@ rpc_encode_header(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
	return error;
 | 
						return error;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static noinline __be32 *
 | 
					static noinline int
 | 
				
			||||||
rpc_decode_header(struct rpc_task *task)
 | 
					rpc_decode_header(struct rpc_task *task, struct xdr_stream *xdr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rpc_clnt *clnt = task->tk_client;
 | 
						struct rpc_clnt *clnt = task->tk_client;
 | 
				
			||||||
	struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
 | 
					 | 
				
			||||||
	int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
 | 
					 | 
				
			||||||
	__be32	*p = iov->iov_base;
 | 
					 | 
				
			||||||
	int error = -EACCES;
 | 
						int error = -EACCES;
 | 
				
			||||||
 | 
						__be32 *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RFC-1014 says that the representation of XDR data must be a
 | 
						/* RFC-1014 says that the representation of XDR data must be a
 | 
				
			||||||
	 * multiple of four bytes
 | 
						 * multiple of four bytes
 | 
				
			||||||
| 
						 | 
					@ -2363,25 +2359,26 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (task->tk_rqstp->rq_rcv_buf.len & 3)
 | 
						if (task->tk_rqstp->rq_rcv_buf.len & 3)
 | 
				
			||||||
		goto out_badlen;
 | 
							goto out_badlen;
 | 
				
			||||||
	if ((len -= 3) < 0)
 | 
					 | 
				
			||||||
		goto out_unparsable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, 3 * sizeof(*p));
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							goto out_unparsable;
 | 
				
			||||||
	p++;	/* skip XID */
 | 
						p++;	/* skip XID */
 | 
				
			||||||
	if (*p++ != rpc_reply)
 | 
						if (*p++ != rpc_reply)
 | 
				
			||||||
		goto out_unparsable;
 | 
							goto out_unparsable;
 | 
				
			||||||
	if (*p++ != rpc_msg_accepted)
 | 
						if (*p++ != rpc_msg_accepted)
 | 
				
			||||||
		goto out_msg_denied;
 | 
							goto out_msg_denied;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = rpcauth_checkverf(task, p);
 | 
						error = rpcauth_checkverf(task, xdr);
 | 
				
			||||||
	if (IS_ERR(p))
 | 
						if (error)
 | 
				
			||||||
		goto out_verifier;
 | 
							goto out_verifier;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = p - (__be32 *)iov->iov_base - 1;
 | 
						p = xdr_inline_decode(xdr, sizeof(*p));
 | 
				
			||||||
	if (len < 0)
 | 
						if (!p)
 | 
				
			||||||
		goto out_unparsable;
 | 
							goto out_unparsable;
 | 
				
			||||||
	switch (*p++) {
 | 
						switch (*p) {
 | 
				
			||||||
	case rpc_success:
 | 
						case rpc_success:
 | 
				
			||||||
		return p;
 | 
							return 0;
 | 
				
			||||||
	case rpc_prog_unavail:
 | 
						case rpc_prog_unavail:
 | 
				
			||||||
		trace_rpc__prog_unavail(task);
 | 
							trace_rpc__prog_unavail(task);
 | 
				
			||||||
		error = -EPFNOSUPPORT;
 | 
							error = -EPFNOSUPPORT;
 | 
				
			||||||
| 
						 | 
					@ -2406,11 +2403,11 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
	if (task->tk_garb_retry) {
 | 
						if (task->tk_garb_retry) {
 | 
				
			||||||
		task->tk_garb_retry--;
 | 
							task->tk_garb_retry--;
 | 
				
			||||||
		task->tk_action = call_encode;
 | 
							task->tk_action = call_encode;
 | 
				
			||||||
		return ERR_PTR(-EAGAIN);
 | 
							return -EAGAIN;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
out_err:
 | 
					out_err:
 | 
				
			||||||
	rpc_exit(task, error);
 | 
						rpc_exit(task, error);
 | 
				
			||||||
	return ERR_PTR(error);
 | 
						return error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_badlen:
 | 
					out_badlen:
 | 
				
			||||||
	trace_rpc__unparsable(task);
 | 
						trace_rpc__unparsable(task);
 | 
				
			||||||
| 
						 | 
					@ -2424,10 +2421,12 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_verifier:
 | 
					out_verifier:
 | 
				
			||||||
	trace_rpc_bad_verifier(task);
 | 
						trace_rpc_bad_verifier(task);
 | 
				
			||||||
	error = PTR_ERR(p);
 | 
					 | 
				
			||||||
	goto out_garbage;
 | 
						goto out_garbage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_msg_denied:
 | 
					out_msg_denied:
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, sizeof(*p));
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							goto out_unparsable;
 | 
				
			||||||
	switch (*p++) {
 | 
						switch (*p++) {
 | 
				
			||||||
	case rpc_auth_error:
 | 
						case rpc_auth_error:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					@ -2441,6 +2440,9 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
		goto out_err;
 | 
							goto out_err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = xdr_inline_decode(xdr, sizeof(*p));
 | 
				
			||||||
 | 
						if (!p)
 | 
				
			||||||
 | 
							goto out_unparsable;
 | 
				
			||||||
	switch (*p++) {
 | 
						switch (*p++) {
 | 
				
			||||||
	case rpc_autherr_rejectedcred:
 | 
						case rpc_autherr_rejectedcred:
 | 
				
			||||||
	case rpc_autherr_rejectedverf:
 | 
						case rpc_autherr_rejectedverf:
 | 
				
			||||||
| 
						 | 
					@ -2454,7 +2456,7 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
		/* Ensure we obtain a new XID! */
 | 
							/* Ensure we obtain a new XID! */
 | 
				
			||||||
		xprt_release(task);
 | 
							xprt_release(task);
 | 
				
			||||||
		task->tk_action = call_reserve;
 | 
							task->tk_action = call_reserve;
 | 
				
			||||||
		return ERR_PTR(-EAGAIN);
 | 
							return -EAGAIN;
 | 
				
			||||||
	case rpc_autherr_badcred:
 | 
						case rpc_autherr_badcred:
 | 
				
			||||||
	case rpc_autherr_badverf:
 | 
						case rpc_autherr_badverf:
 | 
				
			||||||
		/* possibly garbled cred/verf? */
 | 
							/* possibly garbled cred/verf? */
 | 
				
			||||||
| 
						 | 
					@ -2463,7 +2465,7 @@ rpc_decode_header(struct rpc_task *task)
 | 
				
			||||||
		task->tk_garb_retry--;
 | 
							task->tk_garb_retry--;
 | 
				
			||||||
		trace_rpc__bad_creds(task);
 | 
							trace_rpc__bad_creds(task);
 | 
				
			||||||
		task->tk_action = call_encode;
 | 
							task->tk_action = call_encode;
 | 
				
			||||||
		return ERR_PTR(-EAGAIN);
 | 
							return -EAGAIN;
 | 
				
			||||||
	case rpc_autherr_tooweak:
 | 
						case rpc_autherr_tooweak:
 | 
				
			||||||
		trace_rpc__auth_tooweak(task);
 | 
							trace_rpc__auth_tooweak(task);
 | 
				
			||||||
		pr_warn("RPC: server %s requires stronger authentication.\n",
 | 
							pr_warn("RPC: server %s requires stronger authentication.\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue