aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2007-10-26 13:31:57 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-01-30 02:05:44 -0500
commitc957c526ef86e472359dadb4204dab8a503b687d (patch)
tree1db0a284fdf0d0182432a66c7532ce7cf03aa7e2 /fs
parent6232dbbcffc617a5a47596b2ec347b24dc2dd2fd (diff)
NFS: Use unsigned intermediates for manipulating header lengths (NFSv3 XDR)
Clean up: prevent length underflow and mixed sign comparisons when unmarshalling NFS version 3 read, readdir, and readlink replies. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs3xdr.c27
1 files changed, 15 insertions, 12 deletions
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 616d3267b7e7..3917e2fa4e40 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -506,9 +506,9 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
506 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 506 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
507 struct kvec *iov = rcvbuf->head; 507 struct kvec *iov = rcvbuf->head;
508 struct page **page; 508 struct page **page;
509 int hdrlen, recvd; 509 size_t hdrlen;
510 u32 len, recvd, pglen;
510 int status, nr; 511 int status, nr;
511 unsigned int len, pglen;
512 __be32 *entry, *end, *kaddr; 512 __be32 *entry, *end, *kaddr;
513 513
514 status = ntohl(*p++); 514 status = ntohl(*p++);
@@ -527,7 +527,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
527 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 527 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
528 if (iov->iov_len < hdrlen) { 528 if (iov->iov_len < hdrlen) {
529 dprintk("NFS: READDIR reply header overflowed:" 529 dprintk("NFS: READDIR reply header overflowed:"
530 "length %d > %Zu\n", hdrlen, iov->iov_len); 530 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
531 return -errno_NFSERR_IO; 531 return -errno_NFSERR_IO;
532 } else if (iov->iov_len != hdrlen) { 532 } else if (iov->iov_len != hdrlen) {
533 dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 533 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
@@ -549,7 +549,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
549 len = ntohl(*p++); /* string length */ 549 len = ntohl(*p++); /* string length */
550 p += XDR_QUADLEN(len) + 2; /* name + cookie */ 550 p += XDR_QUADLEN(len) + 2; /* name + cookie */
551 if (len > NFS3_MAXNAMLEN) { 551 if (len > NFS3_MAXNAMLEN) {
552 dprintk("NFS: giant filename in readdir (len %x)!\n", 552 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
553 len); 553 len);
554 goto err_unmap; 554 goto err_unmap;
555 } 555 }
@@ -570,7 +570,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res
570 len = ntohl(*p++); 570 len = ntohl(*p++);
571 if (len > NFS3_FHSIZE) { 571 if (len > NFS3_FHSIZE) {
572 dprintk("NFS: giant filehandle in " 572 dprintk("NFS: giant filehandle in "
573 "readdir (len %x)!\n", len); 573 "readdir (len 0x%x)!\n", len);
574 goto err_unmap; 574 goto err_unmap;
575 } 575 }
576 p += XDR_QUADLEN(len); 576 p += XDR_QUADLEN(len);
@@ -815,7 +815,8 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
815{ 815{
816 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 816 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
817 struct kvec *iov = rcvbuf->head; 817 struct kvec *iov = rcvbuf->head;
818 int hdrlen, len, recvd; 818 size_t hdrlen;
819 u32 len, recvd;
819 char *kaddr; 820 char *kaddr;
820 int status; 821 int status;
821 822
@@ -827,7 +828,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
827 828
828 /* Convert length of symlink */ 829 /* Convert length of symlink */
829 len = ntohl(*p++); 830 len = ntohl(*p++);
830 if (len >= rcvbuf->page_len || len <= 0) { 831 if (len >= rcvbuf->page_len) {
831 dprintk("nfs: server returned giant symlink!\n"); 832 dprintk("nfs: server returned giant symlink!\n");
832 return -ENAMETOOLONG; 833 return -ENAMETOOLONG;
833 } 834 }
@@ -835,7 +836,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
835 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 836 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
836 if (iov->iov_len < hdrlen) { 837 if (iov->iov_len < hdrlen) {
837 dprintk("NFS: READLINK reply header overflowed:" 838 dprintk("NFS: READLINK reply header overflowed:"
838 "length %d > %Zu\n", hdrlen, iov->iov_len); 839 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
839 return -errno_NFSERR_IO; 840 return -errno_NFSERR_IO;
840 } else if (iov->iov_len != hdrlen) { 841 } else if (iov->iov_len != hdrlen) {
841 dprintk("NFS: READLINK header is short. " 842 dprintk("NFS: READLINK header is short. "
@@ -863,7 +864,9 @@ static int
863nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) 864nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
864{ 865{
865 struct kvec *iov = req->rq_rcv_buf.head; 866 struct kvec *iov = req->rq_rcv_buf.head;
866 int status, count, ocount, recvd, hdrlen; 867 size_t hdrlen;
868 u32 count, ocount, recvd;
869 int status;
867 870
868 status = ntohl(*p++); 871 status = ntohl(*p++);
869 p = xdr_decode_post_op_attr(p, res->fattr); 872 p = xdr_decode_post_op_attr(p, res->fattr);
@@ -871,7 +874,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
871 if (status != 0) 874 if (status != 0)
872 return -nfs_stat_to_errno(status); 875 return -nfs_stat_to_errno(status);
873 876
874 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant 877 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
875 * in that it puts the count both in the res struct and in the 878 * in that it puts the count both in the res struct and in the
876 * opaque data count. */ 879 * opaque data count. */
877 count = ntohl(*p++); 880 count = ntohl(*p++);
@@ -886,7 +889,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
886 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 889 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
887 if (iov->iov_len < hdrlen) { 890 if (iov->iov_len < hdrlen) {
888 dprintk("NFS: READ reply header overflowed:" 891 dprintk("NFS: READ reply header overflowed:"
889 "length %d > %Zu\n", hdrlen, iov->iov_len); 892 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
890 return -errno_NFSERR_IO; 893 return -errno_NFSERR_IO;
891 } else if (iov->iov_len != hdrlen) { 894 } else if (iov->iov_len != hdrlen) {
892 dprintk("NFS: READ header is short. iovec will be shifted.\n"); 895 dprintk("NFS: READ header is short. iovec will be shifted.\n");
@@ -896,7 +899,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
896 recvd = req->rq_rcv_buf.len - hdrlen; 899 recvd = req->rq_rcv_buf.len - hdrlen;
897 if (count > recvd) { 900 if (count > recvd) {
898 dprintk("NFS: server cheating in read reply: " 901 dprintk("NFS: server cheating in read reply: "
899 "count %d > recvd %d\n", count, recvd); 902 "count %u > recvd %u\n", count, recvd);
900 count = recvd; 903 count = recvd;
901 res->eof = 0; 904 res->eof = 0;
902 } 905 }