From: Kees Cook <kees@kernel.org>
To: Jan Hendrik Farr <kernel@jfarr.cc>
Cc: Thorsten Blum <thorsten.blum@toblux.com>,
kent.overstreet@linux.dev, regressions@lists.linux.dev,
linux-bcachefs@vger.kernel.org, linux-hardening@vger.kernel.org,
linux-kernel@vger.kernel.org, ardb@kernel.org, morbo@google.com
Subject: Re: [REGRESSION][BISECTED] erroneous buffer overflow detected in bch2_xattr_validate
Date: Fri, 4 Oct 2024 10:13:20 -0700 [thread overview]
Message-ID: <202410040958.C19D3B9E48@keescook> (raw)
In-Reply-To: <Zv8RIs-htdc-PtXB@archlinux>
On Thu, Oct 03, 2024 at 11:48:18PM +0200, Jan Hendrik Farr wrote:
> On 03 14:28:01, Kees Cook wrote:
> > On Thu, Oct 03, 2024 at 05:17:08PM +0200, Jan Hendrik Farr wrote:
> > > gcc currently says that the __bdos of struct containing a flexible array
> > > member is:
> > >
> > > sizeof(<whole struct>) + sizeof(<flexible array element>) * <count>
> > >
> > > clang however does the following:
> > >
> > > max(sizeof(<whole struct>), offsetof(<flexible array member>) + sizeof(<flexible array element>) * <count>)
> >
> > Clang's calculation seems very wrong. I would expect it to match GCC's.
> >
>
> I was on the very same train of thought, but I have since changed my
> mind a bit. A struct containing a flexible array member can be allocated in
> two ways:
>
> (1):
>
> struct posix_acl *acl = malloc(sizeof(struct posix_acl) + sizeof(struct posix_acl_entry) * 1);
> acl.a_count = 1;
>
> or (2):
>
> struct posix_acl *acl = malloc(offsetof(struct posix_acl, a_entries) + sizeof(struct posix_acl_entry) * 1);
> acl.a_count = 1;
>
> Both are valid ways to allocate it. __bdos does not know which of these
> methods was used to allocate the struct whose size it has to determine,
> so it's giving the lower bound that doesn't include the (potential)
> padding at the end.
I want to separate several easily confused issues. Instead of just
saying __bdos, let's clearly refer to what calculation within bdos is
being used. There are 3 choices currently:
- alloc_size attribute
- counted_by attribute
- fallback to __bos (which is similar to sizeof(), except that FAMs are 0 sized)
Additionally there are (for all intents and purposes) 2 size
determinations to be made by __bos and __bdos, via argument 2:
- containing object size (type 0) ("maximum size")
- specific object size (type 1) ("minimum size")
For example, consider:
struct posix_acl *acl = malloc(1024);
acl->a_count = 1;
what should these return:
__bos(acl, 0)
__bos(acl, 1)
__bdos(acl, 0)
__bdos(acl, 1)
__bos(acl->a_entries, 0)
__bos(acl->a_entries, 1)
__bdos(acl->a_entries, 0)
__bdos(acl->a_entries, 1)
> So it comes down to false positives vs false negatives...
> More details here:
> https://github.com/llvm/llvm-project/pull/111015
>
> Clangs current behavior would essentially force kernel code to always
> assume option (2) is used. So
>
> struct posix_acl *
> posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
> {
> struct posix_acl *clone = NULL;
>
> if (acl) {
> int size = sizeof(struct posix_acl) + acl->a_count *
> sizeof(struct posix_acl_entry);
> clone = kmemdup(acl, size, flags);
> if (clone)
> refcount_set(&clone->a_refcount, 1);
> }
> return clone;
> }
> EXPORT_SYMBOL_GPL(posix_acl_clone);
>
> from linux/fs/posix_acl.c would have to turn into something like:
>
> struct posix_acl *
> posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
> {
> struct posix_acl *clone = NULL;
>
> if (acl) {
> int size = offsetof(struct posix_acl, a_entries) + acl->a_count *
> sizeof(struct posix_acl_entry);
> clone = kmemdup(acl, size, flags);
> if (clone)
> refcount_set(&clone->a_refcount, 1);
> }
> return clone;
> }
> EXPORT_SYMBOL_GPL(posix_acl_clone);
>
> Which is actually safer, because can you actually be sure this posix_acl
> wasn't allocated using method (2)?
First, this should not be using an open coded calculation at all; it
should use the struct_size() macro.
Secondly, if we want to change struct_size(), then we must (via
allmodconfig builds) determine all the places in the kernel
where the calculated size changes, and audit those for safety.
Right now, struct_size() over-estimates in the face of padding.
We're already moving the kernel toward not even calling struct_size()
externally from the allocation, and instead using the it within the
allocation macros themselves:
https://lore.kernel.org/lkml/20240822231324.make.666-kees@kernel.org/
> After looking at the assembly produced by gcc more, it actually looks
> like it's using the allocation size if it's known in the current context
> (for example if the struct was just malloced in the same function)
> and otherwise returns INT_MAX for the __bdos of a struct containing a
> flexible array member. It's only returning the size based on the
> __counted_by attribute of you ask it for the __bdos of the flexible
> array member itself.
Here is my test case for all the corner cases we've found so far:
https://github.com/kees/kernel-tools/blob/trunk/fortify/array-bounds.c
I'd prefer we add cases there so we can all be talking about the same
things. :)
-Kees
--
Kees Cook
next prev parent reply other threads:[~2024-10-04 17:13 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-26 15:14 [REGRESSION][BISECTED] erroneous buffer overflow detected in bch2_xattr_validate Jan Hendrik Farr
2024-09-26 15:28 ` Thorsten Blum
2024-09-26 16:09 ` Thorsten Blum
2024-09-26 16:37 ` Jan Hendrik Farr
2024-09-26 17:01 ` Jan Hendrik Farr
2024-09-26 17:45 ` Jan Hendrik Farr
2024-09-26 19:58 ` Ard Biesheuvel
2024-09-26 22:18 ` Bill Wendling
2024-09-27 1:30 ` Bill Wendling
2024-09-27 3:41 ` Jan Hendrik Farr
2024-09-28 20:50 ` Kees Cook
2024-09-28 23:33 ` Jan Hendrik Farr
2024-09-29 19:59 ` Jan Hendrik Farr
2024-09-28 17:36 ` Jan Hendrik Farr
2024-09-28 17:49 ` Jan Hendrik Farr
2024-09-28 20:34 ` Kees Cook
2024-10-02 9:18 ` Thorsten Blum
2024-10-03 11:33 ` Jan Hendrik Farr
2024-10-03 13:07 ` Thorsten Blum
2024-10-03 13:12 ` Jan Hendrik Farr
2024-10-03 15:02 ` Thorsten Blum
2024-10-03 15:22 ` Jan Hendrik Farr
2024-10-03 15:30 ` Thorsten Blum
2024-10-03 15:35 ` Jan Hendrik Farr
2024-10-03 15:43 ` Thorsten Blum
2024-10-03 16:32 ` Jan Hendrik Farr
2024-10-03 15:17 ` Jan Hendrik Farr
2024-10-03 21:28 ` Kees Cook
2024-10-03 21:48 ` Jan Hendrik Farr
2024-10-04 17:13 ` Kees Cook [this message]
2024-10-07 3:56 ` Jan Hendrik Farr
2024-10-07 15:10 ` Jan Hendrik Farr
2024-10-16 21:13 ` Kees Cook
2024-10-16 23:41 ` Bill Wendling
2024-10-17 0:09 ` Bill Wendling
2024-10-17 3:04 ` Jan Hendrik Farr
2024-10-17 16:55 ` Nathan Chancellor
2024-10-17 17:39 ` Miguel Ojeda
2024-10-17 18:55 ` Nathan Chancellor
2024-10-18 11:52 ` Miguel Ojeda
2024-10-21 1:33 ` Jan Hendrik Farr
2024-10-21 6:04 ` Miguel Ojeda
2024-10-21 17:01 ` Jan Hendrik Farr
2024-10-21 19:25 ` Nathan Chancellor
2024-10-24 13:16 ` Jan Hendrik Farr
2024-10-25 1:15 ` Nathan Chancellor
2024-10-25 8:10 ` Miguel Ojeda
2024-10-25 15:27 ` Jan Hendrik Farr
2025-05-01 14:30 ` Alan Huang
2025-05-01 16:45 ` Jan Hendrik Farr
2025-05-01 17:22 ` Jan Hendrik Farr
2025-05-01 17:28 ` Alan Huang
2025-05-01 17:58 ` Jan Hendrik Farr
2025-05-01 18:10 ` Kees Cook
2025-05-01 18:18 ` Alan Huang
2024-10-17 0:41 ` Jan Hendrik Farr
2024-10-14 21:39 ` Bill Wendling
2024-10-16 1:22 ` Bill Wendling
2024-10-16 2:18 ` Jan Hendrik Farr
2024-10-16 20:43 ` Kees Cook
2024-10-03 21:23 ` Kees Cook
2024-10-03 22:05 ` Jan Hendrik Farr
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=202410040958.C19D3B9E48@keescook \
--to=kees@kernel.org \
--cc=ardb@kernel.org \
--cc=kent.overstreet@linux.dev \
--cc=kernel@jfarr.cc \
--cc=linux-bcachefs@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=morbo@google.com \
--cc=regressions@lists.linux.dev \
--cc=thorsten.blum@toblux.com \
/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