All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kees Cook <kees@kernel.org>
To: Jann Horn <jannh@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>,
	Christoph Lameter <cl@linux.com>,
	Pekka Enberg <penberg@kernel.org>,
	David Rientjes <rientjes@google.com>,
	Joonsoo Kim <iamjoonsoo.kim@lge.com>,
	Andrew Morton <akpm@linux-foundation.org>,
	Roman Gushchin <roman.gushchin@linux.dev>,
	Hyeonggon Yoo <42.hyeyoo@gmail.com>,
	linux-mm@kvack.org, Miguel Ojeda <ojeda@kernel.org>,
	Nathan Chancellor <nathan@kernel.org>,
	Marco Elver <elver@google.com>,
	Nick Desaulniers <ndesaulniers@google.com>,
	Przemek Kitszel <przemyslaw.kitszel@intel.com>,
	linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org
Subject: Re: [PATCH 4/5] slab: Set freed variables to NULL by default
Date: Sat, 22 Mar 2025 00:18:49 -0700	[thread overview]
Message-ID: <202503220003.FABF5E82D1@keescook> (raw)
In-Reply-To: <CAG48ez2-stu91bgZawx_AaypEuMnc5=nJQUiDzUCb+CbsJS6kw@mail.gmail.com>

On Sat, Mar 22, 2025 at 02:50:15AM +0100, Jann Horn wrote:
> On Fri, Mar 21, 2025 at 9:41 PM Kees Cook <kees@kernel.org> wrote:
> > To defang a subset of "dangling pointer" use-after-free flaws[1], take the
> > address of any lvalues passed to kfree() and set them to NULL after
> > freeing.
> >
> > To do this manually, kfree_and_null() (and the "sensitive" variant)
> > are introduced.
> 
> Unless callers of kfree() are allowed to rely on this behavior, we
> might want to have an option to use a poison value instead of NULL for
> this in debug builds.

Sure -- we have many to choose from. Is there a specific one you think
would be good?

> 
> Hmm... in theory, we could have an object that points to its own type, like so:
> 
>     struct foo {
>      struct foo *ptr;
>     };
> 
> And if that was initialized like so:
> 
>     struct foo *obj = kmalloc(sizeof(struct foo));
>     obj->ptr = obj;
> 
> Then the following is currently fine, but would turn into UAF with this patch:
> 
>     kfree(obj->ptr);
> 
> That is a fairly contrived example; but maybe it would make sense to
> reorder the NULL assignment and the actual freeing to avoid this
> particular case?

Ew. Yeah. Reordering this looks okay, yes:

diff --git a/include/linux/slab.h b/include/linux/slab.h
index 3f8fb60963e3..8913b05eca33 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -473,13 +473,15 @@ extern atomic_t count_nulled;
 
 static inline void kfree_and_null(void **ptr)
 {
-	__kfree(*ptr);
+	void *addr = *ptr;
 	*ptr = NULL;
+	__kfree(addr);
 }
 static inline void kfree_sensitive_and_null(void **ptr)
 {
-	__kfree_sensitive(*ptr);
+	void *addr = *ptr;
 	*ptr = NULL;
+	__kfree_sensitive(addr);
 }
 
 #define __force_assignable(x)	\

> Another pattern that is theoretically currently fine but would be
> problematic after this would be if code continues to access a pointer
> after the pointed-to object has been freed, but just to check for
> NULL-ness to infer something about the state of the object containing
> the pointer, or to check pointer identity, or something like that. But
> I guess that's probably not very common? Something like:
> 
>     if (ptr) {
>         mutex_lock(&some_lock);
>         ...
>         kfree(ptr);
>     }
>     ...
>     if (ptr) {
>         ...
>         mutex_unlock(&some_lock);
>     }

Yeah, this would be bad form IMO. But it's not impossible. This idea
was mentioned on the Fediverse thread for this RFC too.
https://fosstodon.org/@kees/114202495615591299

> But from scrolling through the kernel sources and glancing at a few
> hundred kfree() calls (not a lot compared to the ~40000 callsites we
> have), I haven't actually found any obvious instances like that. There
> is KMSAN test code that intentionally does a UAF, which might need to
> be adjusted to not hit a NULL deref instead.
> (And just an irrelevant sidenote: snd_gf1_dma_interrupt() has
> commented-out debugging code that would UAF the "block" variable if it
> was not commented out.)

Yeah, the heap LKDTM tests need to switch to __kfree() too. :)

I'm going to see if I can build a sensible Coccinelle script to look for
this. It's currently getting very confused by the may "for_each" helpers,
but here's what I've got currently:

@use_freed@
expression E, RHS;
@@

(
        kfree(E);
        ... when != E
?       E = RHS
|
        kfree(E);
        ...
*       E
)

It is finding a few, though. For example:

--- ./drivers/md/dm-ima.c
+++ /tmp/nothing/drivers/md/dm-ima.c
@@ -584,13 +584,11 @@ error:
 exit:
        kfree(md->ima.active_table.device_metadata);
 
-       if (md->ima.active_table.device_metadata !=
            md->ima.inactive_table.device_metadata)
                kfree(md->ima.inactive_table.device_metadata);


-- 
Kees Cook

  reply	other threads:[~2025-03-22  7:18 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-21 20:40 [RFC 0/5] slab: Set freed variables to NULL by default Kees Cook
2025-03-21 20:40 ` [PATCH 1/5] treewide: Replace kfree() casts with union members Kees Cook
2025-03-23 10:26   ` David Laight
2025-03-21 20:40 ` [PATCH 2/5] treewide: Prepare for kfree() to __kfree() rename Kees Cook
2025-03-21 20:40 ` [PATCH 3/5] compiler_types: Introduce __is_lvalue() Kees Cook
2025-03-22  3:38   ` Jann Horn
2025-03-22  7:03     ` Kees Cook
2025-03-21 20:41 ` [PATCH 4/5] slab: Set freed variables to NULL by default Kees Cook
2025-03-22  1:50   ` Jann Horn
2025-03-22  7:18     ` Kees Cook [this message]
2025-03-27 19:23       ` Jann Horn
2025-03-27 19:42   ` Matthew Wilcox
2025-03-21 20:41 ` [PATCH 5/5] [DEBUG] slab: Report number of NULLings Kees Cook
2025-03-24 16:16   ` Christoph Lameter (Ampere)
2025-03-25 19:45     ` Kees Cook
2025-03-27 13:00 ` [RFC 0/5] slab: Set freed variables to NULL by default Harry Yoo

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=202503220003.FABF5E82D1@keescook \
    --to=kees@kernel.org \
    --cc=42.hyeyoo@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=cl@linux.com \
    --cc=elver@google.com \
    --cc=iamjoonsoo.kim@lge.com \
    --cc=jannh@google.com \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=nathan@kernel.org \
    --cc=ndesaulniers@google.com \
    --cc=ojeda@kernel.org \
    --cc=penberg@kernel.org \
    --cc=przemyslaw.kitszel@intel.com \
    --cc=rientjes@google.com \
    --cc=roman.gushchin@linux.dev \
    --cc=vbabka@suse.cz \
    /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.