Commit 6232dbbc authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

NFS: Use unsigned intermediates for manipulating header lengths (NFSv2 XDR)

Clean up: prevent length underflow and mixed sign comparisons when
unmarshalling NFS version 2 read, readdir, and readlink replies.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 8a8c74bf
...@@ -262,7 +262,9 @@ static int ...@@ -262,7 +262,9 @@ static int
nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
{ {
struct kvec *iov = req->rq_rcv_buf.head; struct kvec *iov = req->rq_rcv_buf.head;
int status, count, recvd, hdrlen; size_t hdrlen;
u32 count, recvd;
int status;
if ((status = ntohl(*p++))) if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
...@@ -273,7 +275,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -273,7 +275,7 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
dprintk("NFS: READ reply header overflowed:" dprintk("NFS: READ reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %Zu > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READ header is short. iovec will be shifted.\n"); dprintk("NFS: READ header is short. iovec will be shifted.\n");
...@@ -283,11 +285,11 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res) ...@@ -283,11 +285,11 @@ nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
recvd = req->rq_rcv_buf.len - hdrlen; recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) { if (count > recvd) {
dprintk("NFS: server cheating in read reply: " dprintk("NFS: server cheating in read reply: "
"count %d > recvd %d\n", count, recvd); "count %u > recvd %u\n", count, recvd);
count = recvd; count = recvd;
} }
dprintk("RPC: readres OK count %d\n", count); dprintk("RPC: readres OK count %u\n", count);
if (count < res->count) if (count < res->count)
res->count = count; res->count = count;
...@@ -423,9 +425,10 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -423,9 +425,10 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head; struct kvec *iov = rcvbuf->head;
struct page **page; struct page **page;
int hdrlen, recvd; size_t hdrlen;
unsigned int pglen, recvd;
u32 len;
int status, nr; int status, nr;
unsigned int len, pglen;
__be32 *end, *entry, *kaddr; __be32 *end, *entry, *kaddr;
if ((status = ntohl(*p++))) if ((status = ntohl(*p++)))
...@@ -434,7 +437,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -434,7 +437,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
dprintk("NFS: READDIR reply header overflowed:" dprintk("NFS: READDIR reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %Zu > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
...@@ -576,7 +579,8 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -576,7 +579,8 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
{ {
struct xdr_buf *rcvbuf = &req->rq_rcv_buf; struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head; struct kvec *iov = rcvbuf->head;
int hdrlen, len, recvd; size_t hdrlen;
u32 len, recvd;
char *kaddr; char *kaddr;
int status; int status;
...@@ -584,14 +588,14 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy) ...@@ -584,14 +588,14 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
return -nfs_stat_to_errno(status); return -nfs_stat_to_errno(status);
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*p++); len = ntohl(*p++);
if (len >= rcvbuf->page_len || len <= 0) { if (len >= rcvbuf->page_len) {
dprintk("nfs: server returned giant symlink!\n"); dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG; return -ENAMETOOLONG;
} }
hdrlen = (u8 *) p - (u8 *) iov->iov_base; hdrlen = (u8 *) p - (u8 *) iov->iov_base;
if (iov->iov_len < hdrlen) { if (iov->iov_len < hdrlen) {
dprintk("NFS: READLINK reply header overflowed:" dprintk("NFS: READLINK reply header overflowed:"
"length %d > %Zu\n", hdrlen, iov->iov_len); "length %Zu > %Zu\n", hdrlen, iov->iov_len);
return -errno_NFSERR_IO; return -errno_NFSERR_IO;
} else if (iov->iov_len != hdrlen) { } else if (iov->iov_len != hdrlen) {
dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment