Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f2c2db7 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

SUNRPC: Introduce new xdr_stream-based encoders to rpcb_clnt.c



Replace the open-coded encode logic for rpcbind arguments with an
xdr_stream-based implementation, similar to what NFSv4 uses, to
better protect against buffer overflows.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 4116092b
Loading
Loading
Loading
Loading
+75 −1
Original line number Diff line number Diff line
@@ -708,6 +708,30 @@ static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
	return 0;
}

static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p,
			    const struct rpcbind_args *rpcb)
{
	struct rpc_task *task = req->rq_task;
	struct xdr_stream xdr;

	dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n",
			task->tk_pid, task->tk_msg.rpc_proc->p_name,
			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);

	p = xdr_reserve_space(&xdr, sizeof(__be32) * RPCB_mappingargs_sz);
	if (unlikely(p == NULL))
		return -EIO;

	*p++ = htonl(rpcb->r_prog);
	*p++ = htonl(rpcb->r_vers);
	*p++ = htonl(rpcb->r_prot);
	*p   = htonl(rpcb->r_port);

	return 0;
}

static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
			       unsigned short *portp)
{
@@ -746,6 +770,56 @@ static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
	return 0;
}

static int encode_rpcb_string(struct xdr_stream *xdr, const char *string,
				const u32 maxstrlen)
{
	u32 len;
	__be32 *p;

	if (unlikely(string == NULL))
		return -EIO;
	len = strlen(string);
	if (unlikely(len > maxstrlen))
		return -EIO;

	p = xdr_reserve_space(xdr, sizeof(__be32) + len);
	if (unlikely(p == NULL))
		return -EIO;
	xdr_encode_opaque(p, string, len);

	return 0;
}

static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p,
			    const struct rpcbind_args *rpcb)
{
	struct rpc_task *task = req->rq_task;
	struct xdr_stream xdr;

	dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n",
			task->tk_pid, task->tk_msg.rpc_proc->p_name,
			rpcb->r_prog, rpcb->r_vers,
			rpcb->r_netid, rpcb->r_addr);

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);

	p = xdr_reserve_space(&xdr,
			sizeof(__be32) * (RPCB_program_sz + RPCB_version_sz));
	if (unlikely(p == NULL))
		return -EIO;
	*p++ = htonl(rpcb->r_prog);
	*p = htonl(rpcb->r_vers);

	if (encode_rpcb_string(&xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN))
		return -EIO;
	if (encode_rpcb_string(&xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN))
		return -EIO;
	if (encode_rpcb_string(&xdr, rpcb->r_owner, RPCB_MAXOWNERLEN))
		return -EIO;

	return 0;
}

static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
			       unsigned short *portp)
{
@@ -812,7 +886,7 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
#define PROC(proc, argtype, restype)					\
	[RPCBPROC_##proc] = {						\
		.p_proc		= RPCBPROC_##proc,			\
		.p_encode	= (kxdrproc_t) rpcb_encode_##argtype,	\
		.p_encode	= (kxdrproc_t) rpcb_enc_##argtype,	\
		.p_decode	= (kxdrproc_t) rpcb_decode_##restype,	\
		.p_arglen	= RPCB_##argtype##args_sz,		\
		.p_replen	= RPCB_##restype##res_sz,		\