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

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

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



Replace the open-coded decode logic for PMAP_GETPORT/RPCB_GETADDR with
an xdr_stream-based implementation, similar to what NFSv4 uses, to
protect against buffer overflows.  The new implementation also checks
that the incoming port number is reasonable.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 7ed0ff98
Loading
Loading
Loading
Loading
+77 −3
Original line number Original line Diff line number Diff line
@@ -454,7 +454,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
	struct rpc_message msg = {
	struct rpc_message msg = {
		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
		.rpc_argp	= &map,
		.rpc_argp	= &map,
		.rpc_resp	= &map.r_port,
		.rpc_resp	= &map,
	};
	};
	struct rpc_clnt	*rpcb_clnt;
	struct rpc_clnt	*rpcb_clnt;
	int status;
	int status;
@@ -484,7 +484,7 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
	struct rpc_message msg = {
	struct rpc_message msg = {
		.rpc_proc = proc,
		.rpc_proc = proc,
		.rpc_argp = map,
		.rpc_argp = map,
		.rpc_resp = &map->r_port,
		.rpc_resp = map,
	};
	};
	struct rpc_task_setup task_setup_data = {
	struct rpc_task_setup task_setup_data = {
		.rpc_client = rpcb_clnt,
		.rpc_client = rpcb_clnt,
@@ -727,6 +727,31 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
	return 0;
	return 0;
}
}


static int rpcb_dec_getport(struct rpc_rqst *req, __be32 *p,
			    struct rpcbind_args *rpcb)
{
	struct rpc_task *task = req->rq_task;
	struct xdr_stream xdr;
	unsigned long port;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);

	rpcb->r_port = 0;

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

	port = ntohl(*p);
	dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid,
			task->tk_msg.rpc_proc->p_name, port);
	if (unlikely(port > USHORT_MAX))
		return -EIO;

	rpcb->r_port = port;
	return 0;
}

static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
			   unsigned int *boolp)
			   unsigned int *boolp)
{
{
@@ -871,11 +896,60 @@ static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
	return -EIO;
	return -EIO;
}
}


static int rpcb_dec_getaddr(struct rpc_rqst *req, __be32 *p,
			    struct rpcbind_args *rpcb)
{
	struct sockaddr_storage address;
	struct sockaddr *sap = (struct sockaddr *)&address;
	struct rpc_task *task = req->rq_task;
	struct xdr_stream xdr;
	u32 len;

	rpcb->r_port = 0;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);

	p = xdr_inline_decode(&xdr, sizeof(__be32));
	if (unlikely(p == NULL))
		goto out_fail;
	len = ntohl(*p);

	/*
	 * If the returned universal address is a null string,
	 * the requested RPC service was not registered.
	 */
	if (len == 0) {
		dprintk("RPC: %5u RPCB reply: program not registered\n",
				task->tk_pid);
		return 0;
	}

	if (unlikely(len > RPCBIND_MAXUADDRLEN))
		goto out_fail;

	p = xdr_inline_decode(&xdr, len);
	if (unlikely(p == NULL))
		goto out_fail;
	dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid,
			task->tk_msg.rpc_proc->p_name, (char *)p);

	if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0)
		goto out_fail;
	rpcb->r_port = rpc_get_port(sap);

	return 0;

out_fail:
	dprintk("RPC: %5u malformed RPCB_%s reply\n",
			task->tk_pid, task->tk_msg.rpc_proc->p_name);
	return -EIO;
}

#define PROC(proc, argtype, restype)					\
#define PROC(proc, argtype, restype)					\
	[RPCBPROC_##proc] = {						\
	[RPCBPROC_##proc] = {						\
		.p_proc		= RPCBPROC_##proc,			\
		.p_proc		= RPCBPROC_##proc,			\
		.p_encode	= (kxdrproc_t) rpcb_enc_##argtype,	\
		.p_encode	= (kxdrproc_t) rpcb_enc_##argtype,	\
		.p_decode	= (kxdrproc_t) rpcb_decode_##restype,	\
		.p_decode	= (kxdrproc_t) rpcb_dec_##restype,	\
		.p_arglen	= RPCB_##argtype##args_sz,		\
		.p_arglen	= RPCB_##argtype##args_sz,		\
		.p_replen	= RPCB_##restype##res_sz,		\
		.p_replen	= RPCB_##restype##res_sz,		\
		.p_statidx	= RPCBPROC_##proc,			\
		.p_statidx	= RPCBPROC_##proc,			\