Commit 3cab1c95 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds

[PATCH] Fix NFS long symlinks checks

The NFS readlink() methods all take a buffer length argument.  Use that
instead of assuming PAGE_SIZE... 

We need to return ENAMETOOLONG rather than EIO.
parent e6863f8b
...@@ -511,8 +511,8 @@ static int ...@@ -511,8 +511,8 @@ static int
nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args) nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int count = args->count - 5;
unsigned int replen; unsigned int replen;
u32 count = args->count - 4;
p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_fhandle(p, args->fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
...@@ -547,12 +547,15 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) ...@@ -547,12 +547,15 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0); strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > rcvbuf->page_len) if (len > rcvbuf->page_len) {
len = rcvbuf->page_len; dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
kunmap_atomic(strlen, KM_USER0);
return -ENAMETOOLONG;
}
*strlen = len; *strlen = len;
/* NULL terminate the string we got */ /* NULL terminate the string we got */
string = (char *)(strlen + 1); string = (char *)(strlen + 1);
string[len] = 0; string[len] = '\0';
kunmap_atomic(strlen, KM_USER0); kunmap_atomic(strlen, KM_USER0);
return 0; return 0;
} }
......
...@@ -702,8 +702,8 @@ static int ...@@ -702,8 +702,8 @@ static int
nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args) nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int count = args->count - 5;
unsigned int replen; unsigned int replen;
u32 count = args->count - 4;
p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_fhandle(p, args->fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
...@@ -742,12 +742,15 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) ...@@ -742,12 +742,15 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0); strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
/* Convert length of symlink */ /* Convert length of symlink */
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > rcvbuf->page_len) if (len > rcvbuf->page_len) {
len = rcvbuf->page_len; dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
kunmap_atomic(strlen, KM_USER0);
return -ENAMETOOLONG;
}
*strlen = len; *strlen = len;
/* NULL terminate the string we got */ /* NULL terminate the string we got */
string = (char *)(strlen + 1); string = (char *)(strlen + 1);
string[len] = 0; string[len] = '\0';
kunmap_atomic(strlen, KM_USER0); kunmap_atomic(strlen, KM_USER0);
return 0; return 0;
} }
......
...@@ -947,7 +947,8 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg ...@@ -947,7 +947,8 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req) static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
{ {
struct rpc_auth *auth = req->rq_task->tk_auth; struct rpc_auth *auth = req->rq_task->tk_auth;
int replen; unsigned int count = readlink->count - 5;
unsigned int replen;
uint32_t *p; uint32_t *p;
RESERVE_SPACE(4); RESERVE_SPACE(4);
...@@ -958,7 +959,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r ...@@ -958,7 +959,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r
* + OP_READLINK + status = 7 * + OP_READLINK + status = 7
*/ */
replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2; replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count); xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, count);
return 0; return 0;
} }
...@@ -2921,10 +2922,10 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req) ...@@ -2921,10 +2922,10 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
*/ */
strlen = (uint32_t *) kmap_atomic(rcvbuf->pages[0], KM_USER0); strlen = (uint32_t *) kmap_atomic(rcvbuf->pages[0], KM_USER0);
len = ntohl(*strlen); len = ntohl(*strlen);
if (len > PAGE_CACHE_SIZE - 5) { if (len > rcvbuf->page_len) {
printk(KERN_WARNING "nfs: server returned giant symlink!\n"); dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
kunmap_atomic(strlen, KM_USER0); kunmap_atomic(strlen, KM_USER0);
return -EIO; return -ENAMETOOLONG;
} }
*strlen = len; *strlen = len;
......
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