diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2009-08-09 15:09:40 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-09 15:09:40 -0400 |
commit | 6f2c2db7a46243bd86e3d7ff5f9ff982f26a9fe8 (patch) | |
tree | 7b5ce21079d2723a34f1dc982d98a3318c122afe | |
parent | 4116092b92f859e5e9a90c99d740933e651ee8c0 (diff) |
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: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 1fb1c070c19..823d20dbad0 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -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 @@ out_err: #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, \ |