From: "J. Bruce Fields" <bfields@fieldses.org>
To: Chuck Lever <chuck.lever@oracle.com>
Cc: linux-nfs@vger.kernel.org
Subject: Re: [PATCH 09/19] NFSD: Prevent a buffer overflow in svc_xprt_names()
Date: Mon, 27 Apr 2009 19:56:44 -0400 [thread overview]
Message-ID: <20090427235644.GE5108@fieldses.org> (raw)
In-Reply-To: <20090423233225.17283.10176.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
On Thu, Apr 23, 2009 at 07:32:25PM -0400, Chuck Lever wrote:
> The svc_xprt_names() function can overflow its buffer if it's so near
> the end of the passed in buffer that the "name too long" string still
> doesn't fit. Of course, it could never tell if it was near the end
> of the passed in buffer, since its only caller passes in zero as the
> buffer length.
>
> Let's make this API a little safer.
>
> Change svc_xprt_names() so it *always* checks for a buffer overflow,
> and change its only caller to pass in the correct buffer length.
>
> If svc_xprt_names() does overflow its buffer, it now fails with an
> ENAMETOOLONG errno, instead of trying to write a message at the end
> of the buffer. I don't like this much, but I can't figure out a clean
> way that's always safe to return some of the names, *and* an
> indication that the buffer was not long enough.
>
> The displayed error when doing a 'cat /proc/fs/nfsd/portlist' is
> "File name too long".
Also worth noting that the buffer in question is nearly a page, which
makes this a bit academic for now. (Not an objection to the patch, just
something to note.)
--b.
>
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
>
> fs/nfsd/nfsctl.c | 2 +
> include/linux/sunrpc/svc_xprt.h | 2 +
> net/sunrpc/svc_xprt.c | 56 +++++++++++++++++++++++++++------------
> 3 files changed, 41 insertions(+), 19 deletions(-)
>
> diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
> index e051847..6a1cd90 100644
> --- a/fs/nfsd/nfsctl.c
> +++ b/fs/nfsd/nfsctl.c
> @@ -918,7 +918,7 @@ static ssize_t __write_ports_names(char *buf)
> {
> if (nfsd_serv == NULL)
> return 0;
> - return svc_xprt_names(nfsd_serv, buf, 0);
> + return svc_xprt_names(nfsd_serv, buf, SIMPLE_TRANSACTION_LIMIT);
> }
>
> /*
> diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
> index d790c52..2223ae0 100644
> --- a/include/linux/sunrpc/svc_xprt.h
> +++ b/include/linux/sunrpc/svc_xprt.h
> @@ -83,7 +83,7 @@ int svc_port_is_privileged(struct sockaddr *sin);
> int svc_print_xprts(char *buf, int maxlen);
> struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
> const sa_family_t af, const unsigned short port);
> -int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen);
> +int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen);
>
> static inline void svc_xprt_get(struct svc_xprt *xprt)
> {
> diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
> index c200d92..96eb873 100644
> --- a/net/sunrpc/svc_xprt.c
> +++ b/net/sunrpc/svc_xprt.c
> @@ -1097,36 +1097,58 @@ struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name,
> }
> EXPORT_SYMBOL_GPL(svc_find_xprt);
>
> -/*
> - * Format a buffer with a list of the active transports. A zero for
> - * the buflen parameter disables target buffer overflow checking.
> +static int svc_one_xprt_name(const struct svc_xprt *xprt,
> + char *pos, int remaining)
> +{
> + int len;
> +
> + len = snprintf(pos, remaining, "%s %u\n",
> + xprt->xpt_class->xcl_name,
> + svc_xprt_local_port(xprt));
> + if (len >= remaining)
> + return -ENAMETOOLONG;
> + return len;
> +}
> +
> +/**
> + * svc_xprt_names - format a buffer with a list of transport names
> + * @serv: pointer to an RPC service
> + * @buf: pointer to a buffer to be filled in
> + * @buflen: length of buffer to be filled in
> + *
> + * Fills in @buf with a string containing a list of transport names,
> + * each name terminated with '\n'.
> + *
> + * Returns positive length of the filled-in string on success; otherwise
> + * a negative errno value is returned if an error occurs.
> */
> -int svc_xprt_names(struct svc_serv *serv, char *buf, int buflen)
> +int svc_xprt_names(struct svc_serv *serv, char *buf, const int buflen)
> {
> struct svc_xprt *xprt;
> - char xprt_str[64];
> - int totlen = 0;
> - int len;
> + int len, totlen;
> + char *pos;
>
> /* Sanity check args */
> if (!serv)
> return 0;
>
> spin_lock_bh(&serv->sv_lock);
> +
> + pos = buf;
> + totlen = 0;
> list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
> - len = snprintf(xprt_str, sizeof(xprt_str),
> - "%s %d\n", xprt->xpt_class->xcl_name,
> - svc_xprt_local_port(xprt));
> - /* If the string was truncated, replace with error string */
> - if (len >= sizeof(xprt_str))
> - strcpy(xprt_str, "name-too-long\n");
> - /* Don't overflow buffer */
> - len = strlen(xprt_str);
> - if (buflen && (len + totlen >= buflen))
> + len = svc_one_xprt_name(xprt, pos, buflen - totlen);
> + if (len < 0) {
> + *buf = '\0';
> + totlen = len;
> + }
> + if (len <= 0)
> break;
> - strcpy(buf+totlen, xprt_str);
> +
> + pos += len;
> totlen += len;
> }
> +
> spin_unlock_bh(&serv->sv_lock);
> return totlen;
> }
>
next prev parent reply other threads:[~2009-04-27 23:56 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-23 23:31 [PATCH 00/19] Proposed server-side patches for 2.6.31 Chuck Lever
[not found] ` <20090423231550.17283.24432.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-23 23:31 ` [PATCH 01/19] SUNRPC: Fix error return value of svc_addr_len() Chuck Lever
[not found] ` <20090423233124.17283.40252.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-25 22:17 ` J. Bruce Fields
2009-04-27 16:49 ` Chuck Lever
2009-04-27 23:51 ` J. Bruce Fields
2009-04-28 15:28 ` Chuck Lever
2009-04-28 15:31 ` J. Bruce Fields
2009-04-23 23:31 ` [PATCH 02/19] NFSD: Refactor transport removal out of __write_ports() Chuck Lever
2009-04-23 23:31 ` [PATCH 03/19] NFSD: Refactor transport addition " Chuck Lever
2009-04-23 23:31 ` [PATCH 04/19] NFSD: Refactor portlist socket closing into a helper Chuck Lever
2009-04-23 23:31 ` [PATCH 05/19] NFSD: Refactor socket creation out of __write_ports() Chuck Lever
[not found] ` <20090423233155.17283.37345.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-25 22:40 ` J. Bruce Fields
2009-04-23 23:32 ` [PATCH 06/19] NFSD: Note an additional requirement when passing TCP sockets to portlist Chuck Lever
2009-04-23 23:32 ` [PATCH 07/19] NFSD: Finish refactoring __write_ports() Chuck Lever
2009-04-23 23:32 ` [PATCH 08/19] NFSD: move lockd_up() before svc_addsock() Chuck Lever
2009-04-23 23:32 ` [PATCH 09/19] NFSD: Prevent a buffer overflow in svc_xprt_names() Chuck Lever
[not found] ` <20090423233225.17283.10176.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-27 23:56 ` J. Bruce Fields [this message]
2009-04-23 23:32 ` [PATCH 10/19] SUNRPC: pass buffer size to svc_addsock() Chuck Lever
2009-04-23 23:32 ` [PATCH 11/19] SUNRPC: pass buffer size to svc_sock_names() Chuck Lever
2009-04-23 23:32 ` [PATCH 12/19] SUNRPC: Switch one_sock_name() to use snprintf() Chuck Lever
2009-04-23 23:32 ` [PATCH 13/19] SUNRPC: Support PF_INET6 in one_sock_name() Chuck Lever
2009-04-23 23:33 ` [PATCH 14/19] SUNRPC: Clean up one_sock_name() Chuck Lever
2009-04-23 23:33 ` [PATCH 15/19] NFSD: Stricter buffer size checking in write_recoverydir() Chuck Lever
2009-04-23 23:33 ` [PATCH 16/19] NFSD: Stricter buffer size checking in write_versions() Chuck Lever
2009-04-23 23:33 ` [PATCH 17/19] NFSD: Stricter buffer size checking in fs/nfsd/nfsctl.c Chuck Lever
[not found] ` <20090423233325.17283.71127.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-28 16:31 ` J. Bruce Fields
2009-04-28 16:36 ` Chuck Lever
2009-04-28 21:30 ` J. Bruce Fields
2009-04-23 23:33 ` [PATCH 18/19] lockd: Update NSM state from SM_MON replies Chuck Lever
[not found] ` <20090423233332.17283.23011.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-28 16:25 ` J. Bruce Fields
2009-04-28 16:34 ` Chuck Lever
2009-04-28 16:38 ` J. Bruce Fields
2009-04-28 19:11 ` Chuck Lever
2009-05-08 15:19 ` Chuck Lever
2009-05-08 15:33 ` J. Bruce Fields
2009-04-23 23:33 ` [PATCH 19/19] lockd: clean up 64-bit alignment fix in nsm_init_private() Chuck Lever
[not found] ` <20090423233340.17283.29580.stgit-07a7zB5ZJzbwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2009-04-28 16:31 ` J. Bruce Fields
2009-04-28 16:35 ` Chuck Lever
2009-04-28 16:40 ` J. Bruce Fields
2009-04-28 17:24 ` Chuck Lever
2009-04-28 21:36 ` J. Bruce Fields
2009-04-28 22:03 ` Måns Rullgård
[not found] ` <yw1x63gozb9f.fsf-O+uoZmgXk1l54TAoqtyWWQ@public.gmane.org>
2009-04-28 22:14 ` Chuck Lever
2009-04-28 22:11 ` Chuck Lever
2009-04-28 22:23 ` J. Bruce Fields
2009-04-28 22:31 ` Måns Rullgård
[not found] ` <yw1xws94xved.fsf-O+uoZmgXk1l54TAoqtyWWQ@public.gmane.org>
2009-04-28 22:43 ` Chuck Lever
2009-04-28 22:52 ` Måns Rullgård
[not found] ` <yw1xskjsxuff.fsf-O+uoZmgXk1l54TAoqtyWWQ@public.gmane.org>
2009-04-29 15:16 ` Chuck Lever
2009-04-29 18:02 ` Måns Rullgård
2009-04-25 22:14 ` [PATCH 00/19] Proposed server-side patches for 2.6.31 J. Bruce Fields
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=20090427235644.GE5108@fieldses.org \
--to=bfields@fieldses.org \
--cc=chuck.lever@oracle.com \
--cc=linux-nfs@vger.kernel.org \
/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