All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <kees@kernel.org>
To: Jann Horn <jannh@google.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
	Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
	linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-hardening@vger.kernel.org
Subject: Re: [PATCH] fs: Keep long filenames in isolated slab buckets
Date: Tue, 10 Feb 2026 17:41:43 -0800	[thread overview]
Message-ID: <202602101736.80F1783@keescook> (raw)
In-Reply-To: <CAG48ez1GYR+6kZHDmy4CTZvEfdyUySCxhZaXRo1S=YyN=Fsp8Q@mail.gmail.com>

On Wed, Feb 11, 2026 at 02:28:53AM +0100, Jann Horn wrote:
> On Wed, Feb 11, 2026 at 1:48 AM Kees Cook <kees@kernel.org> wrote:
> > A building block of Use-After-Free heap memory corruption attacks is
> > using userspace controllable kernel allocations to fill specifically sized
> > kmalloc regions with specific contents. The most powerful of these kinds
> > of primitives is arbitrarily controllable contents with arbitrary size.
> > Keeping these kinds of allocations out of the general kmalloc buckets is
> > needed to harden the kernel against such manipulations, so this is why
> > these sorts of "copy data from userspace into kernel heap" situations are
> > expected to use things like memdup_user(), which keeps the allocations
> > in their own set of slab buckets. However, using memdup_user() is not
> > always appropriate, so in those cases, kmem_buckets can used directly.
> >
> > Filenames used to be isolated in their own (fixed size) slab cache so
> > they would not end up in the general kmalloc buckets (which made them
> > unusable for the heap grooming method described above). After commit
> > 8c888b31903c ("struct filename: saner handling of long names"), filenames
> > were being copied into arbitrarily sized kmalloc regions in the general
> > kmalloc buckets. Instead, like memdup_user(), use a dedicated set of
> > kmem buckets for long filenames so we do not introduce a new way for
> > attackers to place arbitrary contents into the general kmalloc buckets.
> >
> > Fixes: 8c888b31903c ("struct filename: saner handling of long names")
> > Signed-off-by: Kees Cook <kees@kernel.org>
> > ---
> > Also, from the same commit, is the loss of SLAB_HWCACHE_ALIGN|SLAB_PANIC
> > for filename allocations relavant at all? It could be added back for
> > these buckets if desired, but I left it default in this patch.
> >
> > Cc: Al Viro <viro@zeniv.linux.org.uk>
> > Cc: Christian Brauner <brauner@kernel.org>
> > Cc: Jan Kara <jack@suse.cz>
> > Cc: <linux-fsdevel@vger.kernel.org>
> > ---
> >  fs/namei.c | 10 +++++++---
> >  1 file changed, 7 insertions(+), 3 deletions(-)
> >
> > diff --git a/fs/namei.c b/fs/namei.c
> > index 8e7792de0000..a901733380cd 100644
> > --- a/fs/namei.c
> > +++ b/fs/namei.c
> > @@ -128,6 +128,8 @@
> >  /* SLAB cache for struct filename instances */
> >  static struct kmem_cache *__names_cache __ro_after_init;
> >  #define names_cache    runtime_const_ptr(__names_cache)
> > +/* SLAB buckets for long names */
> > +static kmem_buckets *names_buckets __ro_after_init;
> >
> >  void __init filename_init(void)
> >  {
> > @@ -135,6 +137,8 @@ void __init filename_init(void)
> >                          SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname),
> >                          EMBEDDED_NAME_MAX, NULL);
> >         runtime_const_init(ptr, __names_cache);
> > +
> > +       names_buckets = kmem_buckets_create("names_bucket", 0, 0, PATH_MAX, NULL);
> >  }
> >
> >  static inline struct filename *alloc_filename(void)
> > @@ -156,7 +160,7 @@ static inline void initname(struct filename *name)
> >  static int getname_long(struct filename *name, const char __user *filename)
> >  {
> >         int len;
> > -       char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL);
> > +       char *p __free(kfree) = kmem_buckets_alloc(names_buckets, PATH_MAX, GFP_KERNEL);
> >         if (unlikely(!p))
> >                 return -ENOMEM;
> 
> I think this path, where we always do maximally-sized allocations, is
> the normal case where we're handling paths coming from userspace...

Actually, is there any reason we can't use strnlen_user() in
do_getname(), and then just use strndup_user() in the long case?

> > @@ -264,14 +268,14 @@ static struct filename *do_getname_kernel(const char *filename, bool incomplete)
> >
> >         if (len <= EMBEDDED_NAME_MAX) {
> >                 p = (char *)result->iname;
> > -               memcpy(p, filename, len);
> >         } else {
> > -               p = kmemdup(filename, len, GFP_KERNEL);
> > +               p = kmem_buckets_alloc(names_buckets, len, GFP_KERNEL);
> 
> ... while this is kind of the exceptional case, where paths are coming
> from kernelspace.
> 
> So you might want to get rid of the bucketing and instead just create
> a single kmem_cache for long paths.

I wasn't sure if there was a controllable way to reach this case or not.

> By the way, did you know that "struct filename" is only used for
> storing fairly-temporary stuff like paths supplied to open(), but not
> for storing the names of directory entries in the dentry cache (which
> are more long-lived)? My understanding is that this is also why the
> kernel doesn't really try to optimize the size of "struct filename" -
> almost all instances of it only exist for the duration of a syscall or
> something like that.

Right, but it was enough of a location change that I felt like it was
worth fixing it up.

> The dentry cache allocates long names as "struct external_name" in
> reclaimable kmalloc slabs, see __d_alloc().

Oh hey, look at that!

                struct external_name *p = kmalloc(size + name->len,
                                                  GFP_KERNEL_ACCOUNT |
                                                  __GFP_RECLAIMABLE);

Yeah, let's put that into dedicated buckets instead?

-Kees

-- 
Kees Cook

  reply	other threads:[~2026-02-11  1:41 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-11  0:48 [PATCH] fs: Keep long filenames in isolated slab buckets Kees Cook
2026-02-11  1:28 ` Jann Horn
2026-02-11  1:41   ` Kees Cook [this message]
2026-02-11  2:06     ` Jann Horn
2026-02-11  2:23       ` Al Viro
2026-02-11 14:13       ` Kees Cook
2026-02-11  2:15     ` Al Viro

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=202602101736.80F1783@keescook \
    --to=kees@kernel.org \
    --cc=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=jannh@google.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.