[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240902.090015-soviet.bowling.selfish.chin-kvAI3lnuyqH@cyphar.com>
Date: Tue, 3 Sep 2024 02:02:39 +1000
From: Aleksa Sarai <cyphar@...har.com>
To: Arnd Bergmann <arnd@...db.de>
Cc: Ingo Molnar <mingo@...hat.com>, Peter Zijlstra <peterz@...radead.org>,
Juri Lelli <juri.lelli@...hat.com>, Vincent Guittot <vincent.guittot@...aro.org>,
Dietmar Eggemann <dietmar.eggemann@....com>, Steven Rostedt <rostedt@...dmis.org>,
Benjamin Segall <bsegall@...gle.com>, Mel Gorman <mgorman@...e.de>,
Valentin Schneider <vschneid@...hat.com>, Alexander Viro <viro@...iv.linux.org.uk>,
Christian Brauner <brauner@...nel.org>, Jan Kara <jack@...e.cz>, shuah <shuah@...nel.org>,
Kees Cook <kees@...nel.org>, Florian Weimer <fweimer@...hat.com>,
Mark Rutland <mark.rutland@....com>, linux-kernel@...r.kernel.org, linux-api@...r.kernel.org,
linux-fsdevel@...r.kernel.org, Linux-Arch <linux-arch@...r.kernel.org>,
linux-kselftest@...r.kernel.org
Subject: Re: [PATCH RFC 1/8] uaccess: add copy_struct_to_user helper
On 2024-09-02, Arnd Bergmann <arnd@...db.de> wrote:
> On Mon, Sep 2, 2024, at 07:06, Aleksa Sarai wrote:
> > This is based on copy_struct_from_user(), but there is one additional
> > case to consider when creating a syscall that returns an
> > extensible-struct to userspace -- how should data in the struct that
> > cannot fit into the userspace struct be handled (ksize > usize)?
> >
> > There are three possibilies:
> >
> > 1. The interface is like sched_getattr(2), where new information will
> > be silently not provided to userspace. This is probably what most
> > interfaces will want to do, as it provides the most possible
> > backwards-compatibility.
> >
> > 2. The interface is like lsm_list_modules(2), where you want to return
> > an error like -EMSGSIZE if not providing information could result in
> > the userspace program making a serious mistake (such as one that
> > could lead to a security problem) or if you want to provide some
> > flag to userspace so they know that they are missing some
> > information.
>
> I'm not sure if EMSGSIZE is the best choice here, my feeling is that
> the kernel should instead try to behave the same way as an older kernel
> that did not know about the extra fields:
I agree this API is not ideal for syscalls because it can lead to
backward-compatibility issues, but that is how lsm_list_modules(2)
works. I suspect most syscalls will go with designs (1) or (3).
> - if the structure has always been longer than the provided buffer,
> -EMSGSIZE should likely have been returned all along. If older
> kernels just provided a short buffer, changing it now is an ABI
> change that would only affect intentionally broken callers, and
> I think keeping the behavior unchanged is more consistent.
>
> - if an extra flag was added along with the larger buffer size,
> the old kernel would likely have rejected the new flag with -EINVAL,
> so I think returning the same thing for userspace built against
> the old kernel headers is more consistent.
>
>
> > +static __always_inline __must_check int
> > +copy_struct_to_user(void __user *dst, size_t usize, const void *src,
> > + size_t ksize, bool *ignored_trailing)
>
> This feels like the kind of function that doesn't need to be inline
> at all and could be moved to lib/usercopy.c instead. It should clearly
> stay in the same place as copy_struct_from_user(), but we could move
> that as well.
IIRC Kees suggested copy_struct_from_user() be inline when I first
included it, though I would have to dig through the old threads to find
the reasoning. __builtin_object_size() was added some time after it was
merged so that wasn't the original reason.
> > +{
> > + size_t size = min(ksize, usize);
> > + size_t rest = max(ksize, usize) - size;
> > +
> > + /* Double check if ksize is larger than a known object size. */
> > + if (WARN_ON_ONCE(ksize > __builtin_object_size(src, 1)))
> > + return -E2BIG;
>
> I guess the __builtin_object_size() check is the reason for making
> it __always_inline, but that could be done in a trivial inline
> wrapper around the extern function. If ksize is always expected
> to be a constant for all callers, the check could even become a
> compile-time check instead of a WARN_ON_ONCE() that feels wrong
> here: if there is a code path where this can get triggered, there
> is clearly a kernel bug, but the only way to find out is to have
> a userspace caller that triggers the code path.
>
> Again, the same code is already in copy_struct_from_user(), so
> this is not something you are adding but rather something we
> may want to change for both.
>
> Arnd
--
Aleksa Sarai
Senior Software Engineer (Containers)
SUSE Linux GmbH
<https://www.cyphar.com/>
Download attachment "signature.asc" of type "application/pgp-signature" (229 bytes)
Powered by blists - more mailing lists