Skip to content

Commit

Permalink
SUNRPC: Introduce new xdr_stream-based encoders to rpcb_clnt.c
Browse files Browse the repository at this point in the history
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: Chuck Lever <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
  • Loading branch information
chucklever authored and Trond Myklebust committed Aug 9, 2009
1 parent 4116092 commit 6f2c2db
Showing 1 changed file with 75 additions and 1 deletion.
76 changes: 75 additions & 1 deletion net/sunrpc/rpcb_clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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, \
Expand Down

0 comments on commit 6f2c2db

Please sign in to comment.