From: "J. Bruce Fields" <bfields@fieldses.org>
To: linux-nfs@vger.kernel.org
Cc: Neil Brown <neilb@suse.de>
Subject: Re: [PATCH] nfsd: check for oversized NFSv2/v3 arguments
Date: Fri, 14 Apr 2017 11:09:40 -0400 [thread overview]
Message-ID: <20170414150940.GB5362@fieldses.org> (raw)
In-Reply-To: <20170414150440.GA5362@fieldses.org>
(Cc'd you, Neil, partly on the off chance you might have a better idea
where this came from. Looks to me like it may have been there forever,
but, I haven't looked too hard yet.)
--b.
On Fri, Apr 14, 2017 at 11:04:40AM -0400, bfields wrote:
> From: "J. Bruce Fields" <bfields@redhat.com>
>
> A client can append random data to the end of an NFSv2 or NFSv3 RPC call
> without our complaining; we'll just stop parsing at the end of the
> expected data and ignore the rest.
>
> Encoded arguments and replies are stored together in an array of pages,
> and if a call is too large it could leave inadequate space for the
> reply. This is normally OK because NFS RPC's typically have either
> short arguments and long replies (like READ) or long arguments and short
> replies (like WRITE). But a client that sends an incorrectly long reply
> can violate those assumptions. This was observed to cause crashes.
>
> So, insist that the argument not be any longer than we expect.
>
> Also, several operations increment rq_next_page in the decode routine
> before checking the argument size, which can leave rq_next_page pointing
> well past the end of the page array, causing trouble later in
> svc_free_pages.
>
> As followup we may also want to rewrite the encoding routines to check
> more carefully that they aren't running off the end of the page array.
>
> Reported-by: Tuomas Haanpää <thaan@synopsys.com>
> Reported-by: Ari Kauppi <ari@synopsys.com>
> Cc: stable@vger.kernel.org
> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
> ---
> fs/nfsd/nfs3xdr.c | 23 +++++++++++++++++------
> fs/nfsd/nfsxdr.c | 13 ++++++++++---
> include/linux/sunrpc/svc.h | 3 +--
> 3 files changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
> index dba2ff8eaa68..be66bcadfaea 100644
> --- a/fs/nfsd/nfs3xdr.c
> +++ b/fs/nfsd/nfs3xdr.c
> @@ -334,8 +334,11 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
> if (!p)
> return 0;
> p = xdr_decode_hyper(p, &args->offset);
> -
> args->count = ntohl(*p++);
> +
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> +
> len = min(args->count, max_blocksize);
>
> /* set up the kvec */
> @@ -349,7 +352,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
> v++;
> }
> args->vlen = v;
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> @@ -536,9 +539,11 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
> p = decode_fh(p, &args->fh);
> if (!p)
> return 0;
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> args->buffer = page_address(*(rqstp->rq_next_page++));
>
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> @@ -564,10 +569,14 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
> args->verf = p; p += 2;
> args->dircount = ~0;
> args->count = ntohl(*p++);
> +
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> +
> args->count = min_t(u32, args->count, PAGE_SIZE);
> args->buffer = page_address(*(rqstp->rq_next_page++));
>
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> @@ -585,6 +594,9 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
> args->dircount = ntohl(*p++);
> args->count = ntohl(*p++);
>
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> +
> len = args->count = min(args->count, max_blocksize);
> while (len > 0) {
> struct page *p = *(rqstp->rq_next_page++);
> @@ -592,8 +604,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
> args->buffer = page_address(p);
> len -= PAGE_SIZE;
> }
> -
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
> index 41b468a6a90f..79268369f7b3 100644
> --- a/fs/nfsd/nfsxdr.c
> +++ b/fs/nfsd/nfsxdr.c
> @@ -257,6 +257,9 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
> len = args->count = ntohl(*p++);
> p++; /* totalcount - unused */
>
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> +
> len = min_t(unsigned int, len, NFSSVC_MAXBLKSIZE_V2);
>
> /* set up somewhere to store response.
> @@ -272,7 +275,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
> v++;
> }
> args->vlen = v;
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> @@ -360,9 +363,11 @@ nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readli
> p = decode_fh(p, &args->fh);
> if (!p)
> return 0;
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> args->buffer = page_address(*(rqstp->rq_next_page++));
>
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> int
> @@ -400,9 +405,11 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
> args->cookie = ntohl(*p++);
> args->count = ntohl(*p++);
> args->count = min_t(u32, args->count, PAGE_SIZE);
> + if (!xdr_argsize_check(rqstp, p))
> + return 0;
> args->buffer = page_address(*(rqstp->rq_next_page++));
>
> - return xdr_argsize_check(rqstp, p);
> + return 1;
> }
>
> /*
> diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
> index e770abeed32d..6ef19cf658b4 100644
> --- a/include/linux/sunrpc/svc.h
> +++ b/include/linux/sunrpc/svc.h
> @@ -336,8 +336,7 @@ xdr_argsize_check(struct svc_rqst *rqstp, __be32 *p)
> {
> char *cp = (char *)p;
> struct kvec *vec = &rqstp->rq_arg.head[0];
> - return cp >= (char*)vec->iov_base
> - && cp <= (char*)vec->iov_base + vec->iov_len;
> + return cp == (char *)vec->iov_base + vec->iov_len;
> }
>
> static inline int
> --
> 2.9.3
>
next prev parent reply other threads:[~2017-04-14 15:09 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-04-14 15:04 [PATCH] nfsd: check for oversized NFSv2/v3 arguments J. Bruce Fields
2017-04-14 15:09 ` J. Bruce Fields [this message]
2017-04-18 0:25 ` NeilBrown
2017-04-18 17:13 ` J. Bruce Fields
2017-04-19 0:17 ` NeilBrown
2017-04-19 0:44 ` J. Bruce Fields
2017-04-20 0:57 ` NeilBrown
2017-04-20 15:16 ` J. Bruce Fields
2017-04-20 16:19 ` J. Bruce Fields
2017-04-20 21:30 ` J. Bruce Fields
2017-04-20 22:11 ` NeilBrown
2017-04-20 22:19 ` J. Bruce Fields
2017-04-21 21:12 ` J. Bruce Fields
2017-04-23 22:21 ` NeilBrown
2017-04-24 14:06 ` J. Bruce Fields
2017-04-24 21:19 ` J. Bruce Fields
2017-04-24 21:20 ` J. Bruce Fields
2017-04-25 3:15 ` NeilBrown
2017-04-25 20:40 ` J. Bruce Fields
2017-04-26 6:31 ` NeilBrown
2017-04-25 3:00 ` NeilBrown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170414150940.GB5362@fieldses.org \
--to=bfields@fieldses.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neilb@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).