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 /net/sunrpc | |
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>
Diffstat (limited to 'net/sunrpc')
-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 1fb1c070c19d..823d20dbad09 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, | |||
708 | return 0; | 708 | return 0; |
709 | } | 709 | } |
710 | 710 | ||
711 | static int rpcb_enc_mapping(struct rpc_rqst *req, __be32 *p, | ||
712 | const struct rpcbind_args *rpcb) | ||
713 | { | ||
714 | struct rpc_task *task = req->rq_task; | ||
715 | struct xdr_stream xdr; | ||
716 | |||
717 | dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", | ||
718 | task->tk_pid, task->tk_msg.rpc_proc->p_name, | ||
719 | rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); | ||
720 | |||
721 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
722 | |||
723 | p = xdr_reserve_space(&xdr, sizeof(__be32) * RPCB_mappingargs_sz); | ||
724 | if (unlikely(p == NULL)) | ||
725 | return -EIO; | ||
726 | |||
727 | *p++ = htonl(rpcb->r_prog); | ||
728 | *p++ = htonl(rpcb->r_vers); | ||
729 | *p++ = htonl(rpcb->r_prot); | ||
730 | *p = htonl(rpcb->r_port); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
711 | static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, | 735 | static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p, |
712 | unsigned short *portp) | 736 | unsigned short *portp) |
713 | { | 737 | { |
@@ -746,6 +770,56 @@ static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p, | |||
746 | return 0; | 770 | return 0; |
747 | } | 771 | } |
748 | 772 | ||
773 | static int encode_rpcb_string(struct xdr_stream *xdr, const char *string, | ||
774 | const u32 maxstrlen) | ||
775 | { | ||
776 | u32 len; | ||
777 | __be32 *p; | ||
778 | |||
779 | if (unlikely(string == NULL)) | ||
780 | return -EIO; | ||
781 | len = strlen(string); | ||
782 | if (unlikely(len > maxstrlen)) | ||
783 | return -EIO; | ||
784 | |||
785 | p = xdr_reserve_space(xdr, sizeof(__be32) + len); | ||
786 | if (unlikely(p == NULL)) | ||
787 | return -EIO; | ||
788 | xdr_encode_opaque(p, string, len); | ||
789 | |||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int rpcb_enc_getaddr(struct rpc_rqst *req, __be32 *p, | ||
794 | const struct rpcbind_args *rpcb) | ||
795 | { | ||
796 | struct rpc_task *task = req->rq_task; | ||
797 | struct xdr_stream xdr; | ||
798 | |||
799 | dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", | ||
800 | task->tk_pid, task->tk_msg.rpc_proc->p_name, | ||
801 | rpcb->r_prog, rpcb->r_vers, | ||
802 | rpcb->r_netid, rpcb->r_addr); | ||
803 | |||
804 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
805 | |||
806 | p = xdr_reserve_space(&xdr, | ||
807 | sizeof(__be32) * (RPCB_program_sz + RPCB_version_sz)); | ||
808 | if (unlikely(p == NULL)) | ||
809 | return -EIO; | ||
810 | *p++ = htonl(rpcb->r_prog); | ||
811 | *p = htonl(rpcb->r_vers); | ||
812 | |||
813 | if (encode_rpcb_string(&xdr, rpcb->r_netid, RPCBIND_MAXNETIDLEN)) | ||
814 | return -EIO; | ||
815 | if (encode_rpcb_string(&xdr, rpcb->r_addr, RPCBIND_MAXUADDRLEN)) | ||
816 | return -EIO; | ||
817 | if (encode_rpcb_string(&xdr, rpcb->r_owner, RPCB_MAXOWNERLEN)) | ||
818 | return -EIO; | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
749 | static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, | 823 | static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p, |
750 | unsigned short *portp) | 824 | unsigned short *portp) |
751 | { | 825 | { |
@@ -812,7 +886,7 @@ out_err: | |||
812 | #define PROC(proc, argtype, restype) \ | 886 | #define PROC(proc, argtype, restype) \ |
813 | [RPCBPROC_##proc] = { \ | 887 | [RPCBPROC_##proc] = { \ |
814 | .p_proc = RPCBPROC_##proc, \ | 888 | .p_proc = RPCBPROC_##proc, \ |
815 | .p_encode = (kxdrproc_t) rpcb_encode_##argtype, \ | 889 | .p_encode = (kxdrproc_t) rpcb_enc_##argtype, \ |
816 | .p_decode = (kxdrproc_t) rpcb_decode_##restype, \ | 890 | .p_decode = (kxdrproc_t) rpcb_decode_##restype, \ |
817 | .p_arglen = RPCB_##argtype##args_sz, \ | 891 | .p_arglen = RPCB_##argtype##args_sz, \ |
818 | .p_replen = RPCB_##restype##res_sz, \ | 892 | .p_replen = RPCB_##restype##res_sz, \ |