From: ebiederm@xmission.com (Eric W. Biederman)
To: Christian Brauner <christian@brauner.io>
Cc: keescook@chromium.org, linux-kernel@vger.kernel.org,
mcgrof@kernel.org, akpm@linux-foundation.org,
joe.lawrence@redhat.com, longman@redhat.com,
linux@dominikbrodowski.net, viro@zeniv.linux.org.uk,
adobriyan@gmail.com, linux-api@vger.kernel.org
Subject: Re: [PATCH v3 1/2] sysctl: handle overflow in proc_get_long
Date: Tue, 16 Oct 2018 18:45:44 -0500 [thread overview]
Message-ID: <877eihjw0n.fsf@xmission.com> (raw)
In-Reply-To: <20181016223322.16844-2-christian@brauner.io> (Christian Brauner's message of "Wed, 17 Oct 2018 00:33:21 +0200")
Christian Brauner <christian@brauner.io> writes:
> proc_get_long() is a funny function. It uses simple_strtoul() and for a
> good reason. proc_get_long() wants to always succeed the parse and return
> the maybe incorrect value and the trailing characters to check against a
> pre-defined list of acceptable trailing values.
> However, simple_strtoul() explicitly ignores overflows which can cause
> funny things like the following to happen:
>
> echo 18446744073709551616 > /proc/sys/fs/file-max
> cat /proc/sys/fs/file-max
> 0
>
> (Which will cause your system to silently die behind your back.)
>
> On the other hand kstrtoul() does do overflow detection but does not return
> the trailing characters, and also fails the parse when anything other than
> '\n' is a trailing character whereas proc_get_long() wants to be more
> lenient.
>
> Now, before adding another kstrtoul() function let's simply add a static
> parse strtoul_lenient() which:
> - fails on overflow with -ERANGE
> - returns the trailing characters to the caller
>
> The reason why we should fail on ERANGE is that we already do a partial
> fail on overflow right now. Namely, when the TMPBUFLEN is exceeded. So we
> already reject values such as 184467440737095516160 (21 chars) but accept
> values such as 18446744073709551616 (20 chars) but both are overflows. So
> we should just always reject 64bit overflows and not special-case this
> based on the number of chars.
>
> Acked-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Christian Brauner <christian@brauner.io>
> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
> ---
> v2->v3:
> - (Kees) s/#include <../lib/kstrtox.h>/#include "../lib/kstrtox.h"/g
> - (Kees) document strtoul_lenient()
>
> v1->v2:
> - s/sysctl_cap_erange/sysctl_lenient/g
> - consistenly fail on overflow
>
> v0->v1:
> - s/sysctl_strtoul_lenient/strtoul_cap_erange/g
> - (Al) remove bool overflow return argument from strtoul_cap_erange
> - (Al) return ULONG_MAX on ERANGE from strtoul_cap_erange
> - (Dominik) fix spelling in commit message
> ---
> kernel/sysctl.c | 40 +++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 39 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index cc02050fd0c4..102aa7a65687 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -68,6 +68,8 @@
> #include <linux/mount.h>
> #include <linux/pipe_fs_i.h>
>
> +#include "../lib/kstrtox.h"
> +
> #include <linux/uaccess.h>
> #include <asm/processor.h>
>
> @@ -2065,6 +2067,41 @@ static void proc_skip_char(char **buf, size_t *size, const char v)
> }
> }
>
> +/**
> + * strtoul_lenient - parse an ASCII formatted integer from a buffer and only
> + * fail on overflow
> + *
> + * @cp: kernel buffer containing the string to parse
> + * @endp: pointer to store the trailing characters
> + * @base: the base to use
> + * @res: where the parsed integer will be stored
> + *
> + * In case of success 0 is returned and @res will contain the parsed integer,
> + * @endp will hold any trailing characters.
> + * This function will fail the parse on overflow. If there wasn't an overflow
> + * the function will defer the decision what characters count as invalid to the
> + * caller.
> + */
> +static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
> + unsigned long *res)
> +{
> + unsigned long long result;
> + unsigned int rv;
> +
> + cp = _parse_integer_fixup_radix(cp, &base);
> + rv = _parse_integer(cp, base, &result);
> + if ((rv & KSTRTOX_OVERFLOW) || (result != (unsigned long)result))
> + return -ERANGE;
> +
> + cp += rv;
> +
> + if (endp)
> + *endp = (char *)cp;
> +
> + *res = (unsigned long)result;
> + return 0;
> +}
> +
> #define TMPBUFLEN 22
> /**
> * proc_get_long - reads an ASCII formatted integer from a user buffer
> @@ -2108,7 +2145,8 @@ static int proc_get_long(char **buf, size_t *size,
> if (!isdigit(*p))
> return -EINVAL;
>
> - *val = simple_strtoul(p, &p, 0);
> + if (strtoul_lenient(p, &p, 0, val))
> + return -EINVAL;
Is it deliberate that on an error stroul_lenient returns -ERANGE but
then proc_get_long returns -EINVAL? That feels wrong. The write system
call does not permit -ERANGE or -EINVAL for the contents of the data
so both options appear equally bad from a standards point of view.
I am just wondering what the thinking is here.
> len = p - tmp;
next prev parent reply other threads:[~2018-10-16 23:46 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-16 22:33 [PATCH v3 0/2] sysctl: handle overflow for file-max Christian Brauner
2018-10-16 22:33 ` [PATCH v3 1/2] sysctl: handle overflow in proc_get_long Christian Brauner
2018-10-16 23:45 ` Eric W. Biederman [this message]
2018-10-17 0:24 ` Christian Brauner
2018-10-17 2:19 ` Kees Cook
2018-10-16 22:33 ` [PATCH v3 2/2] sysctl: handle overflow for file-max Christian Brauner
2018-10-17 0:35 ` Al Viro
2018-10-17 9:57 ` Christian Brauner
2018-10-18 21:58 ` Andrea Arcangeli
2018-10-16 22:36 ` [PATCH v3 0/2] " Kees Cook
2018-10-29 14:58 ` Christian Brauner
2018-10-29 21:44 ` Kees Cook
2018-12-09 16:40 ` Christian Brauner
2018-12-10 17:51 ` Kees Cook
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=877eihjw0n.fsf@xmission.com \
--to=ebiederm@xmission.com \
--cc=adobriyan@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=christian@brauner.io \
--cc=joe.lawrence@redhat.com \
--cc=keescook@chromium.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@dominikbrodowski.net \
--cc=longman@redhat.com \
--cc=mcgrof@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/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