lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAG48ez1GYR+6kZHDmy4CTZvEfdyUySCxhZaXRo1S=YyN=Fsp8Q@mail.gmail.com>
Date: Wed, 11 Feb 2026 02:28:53 +0100
From: Jann Horn <jannh@...gle.com>
To: Kees Cook <kees@...nel.org>
Cc: Al Viro <viro@...iv.linux.org.uk>, Christian Brauner <brauner@...nel.org>, Jan Kara <jack@...e.cz>, 
	linux-fsdevel@...r.kernel.org, linux-kernel@...r.kernel.org, 
	linux-hardening@...r.kernel.org
Subject: Re: [PATCH] fs: Keep long filenames in isolated slab buckets

On Wed, Feb 11, 2026 at 1:48 AM Kees Cook <kees@...nel.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@...nel.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@...iv.linux.org.uk>
> Cc: Christian Brauner <brauner@...nel.org>
> Cc: Jan Kara <jack@...e.cz>
> Cc: <linux-fsdevel@...r.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...

> @@ -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.


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.

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ