linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] mm/slub: refactor freelist to use custom type
@ 2023-07-04 13:58 Matteo Rizzo
  2023-07-04 17:58 ` David Rientjes
  2023-07-11  9:57 ` Vlastimil Babka
  0 siblings, 2 replies; 3+ messages in thread
From: Matteo Rizzo @ 2023-07-04 13:58 UTC (permalink / raw)
  To: linux-mm, linux-kernel, cl, penberg, rientjes, iamjoonsoo.kim,
	akpm, vbabka, roman.gushchin, 42.hyeyoo
  Cc: jannh, matteorizzo

From: Jann Horn <jannh@google.com>

Currently the SLUB code represents encoded freelist entries as "void*".
That's misleading, those things are encoded under
CONFIG_SLAB_FREELIST_HARDENED so that they're not actually dereferencable.

Give them their own type, and split freelist_ptr() into one function per
direction (one for encoding, one for decoding).

Signed-off-by: Jann Horn <jannh@google.com>
Co-developed-by: Matteo Rizzo <matteorizzo@google.com>
Signed-off-by: Matteo Rizzo <matteorizzo@google.com>
---
v2:
	* Fix compilation error with SLUB_TINY
	* Move the freeptr_t typedef to slub.c

 mm/slub.c | 43 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 11 deletions(-)

diff --git a/mm/slub.c b/mm/slub.c
index e3b5d5c0eb3a..f8cc47eff742 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -360,13 +360,19 @@ static struct workqueue_struct *flushwq;
  * 			Core slab cache functions
  *******************************************************************/

+/*
+ * freeptr_t represents a SLUB freelist pointer, which might be encoded
+ * and not dereferenceable if CONFIG_SLAB_FREELIST_HARDENED is enabled.
+ */
+typedef struct { unsigned long v; } freeptr_t;
+
 /*
  * Returns freelist pointer (ptr). With hardening, this is obfuscated
  * with an XOR of the address where the pointer is held and a per-cache
  * random number.
  */
-static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
-				 unsigned long ptr_addr)
+static inline freeptr_t freelist_ptr_encode(const struct kmem_cache *s,
+					    void *ptr, unsigned long ptr_addr)
 {
 #ifdef CONFIG_SLAB_FREELIST_HARDENED
 	/*
@@ -379,25 +385,40 @@ static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
 	 * calls get_freepointer() with an untagged pointer, which causes the
 	 * freepointer to be restored incorrectly.
 	 */
-	return (void *)((unsigned long)ptr ^ s->random ^
-			swab((unsigned long)kasan_reset_tag((void *)ptr_addr)));
+	return (freeptr_t){.v = (unsigned long)ptr ^ s->random ^
+			swab((unsigned long)kasan_reset_tag((void *)ptr_addr))};
 #else
-	return ptr;
+	return (freeptr_t){.v = (unsigned long)ptr};
 #endif
 }

+static inline void *freelist_ptr_decode(const struct kmem_cache *s,
+					freeptr_t ptr, unsigned long ptr_addr)
+{
+	void *decoded;
+
+#ifdef CONFIG_SLAB_FREELIST_HARDENED
+	/* See the comment in freelist_ptr_encode */
+	decoded = (void *)(ptr.v ^ s->random ^
+		swab((unsigned long)kasan_reset_tag((void *)ptr_addr)));
+#else
+	decoded = (void *)ptr.v;
+#endif
+	return decoded;
+}
+
 /* Returns the freelist pointer recorded at location ptr_addr. */
 static inline void *freelist_dereference(const struct kmem_cache *s,
 					 void *ptr_addr)
 {
-	return freelist_ptr(s, (void *)*(unsigned long *)(ptr_addr),
+	return freelist_ptr_decode(s, *(freeptr_t *)(ptr_addr),
 			    (unsigned long)ptr_addr);
 }

 static inline void *get_freepointer(struct kmem_cache *s, void *object)
 {
 	object = kasan_reset_tag(object);
-	return freelist_dereference(s, object + s->offset);
+	return freelist_dereference(s, (freeptr_t *)(object + s->offset));
 }

 #ifndef CONFIG_SLUB_TINY
@@ -421,15 +442,15 @@ __no_kmsan_checks
 static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
 {
 	unsigned long freepointer_addr;
-	void *p;
+	freeptr_t p;

 	if (!debug_pagealloc_enabled_static())
 		return get_freepointer(s, object);

 	object = kasan_reset_tag(object);
 	freepointer_addr = (unsigned long)object + s->offset;
-	copy_from_kernel_nofault(&p, (void **)freepointer_addr, sizeof(p));
-	return freelist_ptr(s, p, freepointer_addr);
+	copy_from_kernel_nofault(&p, (freeptr_t *)freepointer_addr, sizeof(p));
+	return freelist_ptr_decode(s, p, freepointer_addr);
 }

 static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
@@ -441,7 +462,7 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
 #endif

 	freeptr_addr = (unsigned long)kasan_reset_tag((void *)freeptr_addr);
-	*(void **)freeptr_addr = freelist_ptr(s, fp, freeptr_addr);
+	*(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr);
 }

 /* Loop over all objects in a slab */

base-commit: 24be4d0b46bb0c3c1dc7bacd30957d6144a70dfc
--
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] mm/slub: refactor freelist to use custom type
  2023-07-04 13:58 [PATCH v2] mm/slub: refactor freelist to use custom type Matteo Rizzo
@ 2023-07-04 17:58 ` David Rientjes
  2023-07-11  9:57 ` Vlastimil Babka
  1 sibling, 0 replies; 3+ messages in thread
From: David Rientjes @ 2023-07-04 17:58 UTC (permalink / raw)
  To: Matteo Rizzo
  Cc: linux-mm, linux-kernel, cl, penberg, iamjoonsoo.kim, akpm,
	vbabka, roman.gushchin, 42.hyeyoo, jannh

On Tue, 4 Jul 2023, Matteo Rizzo wrote:

> From: Jann Horn <jannh@google.com>
> 
> Currently the SLUB code represents encoded freelist entries as "void*".
> That's misleading, those things are encoded under
> CONFIG_SLAB_FREELIST_HARDENED so that they're not actually dereferencable.
> 
> Give them their own type, and split freelist_ptr() into one function per
> direction (one for encoding, one for decoding).
> 
> Signed-off-by: Jann Horn <jannh@google.com>
> Co-developed-by: Matteo Rizzo <matteorizzo@google.com>
> Signed-off-by: Matteo Rizzo <matteorizzo@google.com>

Acked-by: David Rientjes <rientjes@google.com>


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] mm/slub: refactor freelist to use custom type
  2023-07-04 13:58 [PATCH v2] mm/slub: refactor freelist to use custom type Matteo Rizzo
  2023-07-04 17:58 ` David Rientjes
@ 2023-07-11  9:57 ` Vlastimil Babka
  1 sibling, 0 replies; 3+ messages in thread
From: Vlastimil Babka @ 2023-07-11  9:57 UTC (permalink / raw)
  To: Matteo Rizzo, linux-mm, linux-kernel, cl, penberg, rientjes,
	iamjoonsoo.kim, akpm, roman.gushchin, 42.hyeyoo
  Cc: jannh

On 7/4/23 15:58, Matteo Rizzo wrote:
> From: Jann Horn <jannh@google.com>
> 
> Currently the SLUB code represents encoded freelist entries as "void*".
> That's misleading, those things are encoded under
> CONFIG_SLAB_FREELIST_HARDENED so that they're not actually dereferencable.
> 
> Give them their own type, and split freelist_ptr() into one function per
> direction (one for encoding, one for decoding).
> 
> Signed-off-by: Jann Horn <jannh@google.com>
> Co-developed-by: Matteo Rizzo <matteorizzo@google.com>
> Signed-off-by: Matteo Rizzo <matteorizzo@google.com>

Thanks, merged:

https://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git/log/?h=slab/for-6.6/cleanup

While reviewing this I think more cleanups are possible but I will post them
on top as it's better for bisection purposes than folding anyway, and should
involve kasan folks.



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2023-07-11  9:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-04 13:58 [PATCH v2] mm/slub: refactor freelist to use custom type Matteo Rizzo
2023-07-04 17:58 ` David Rientjes
2023-07-11  9:57 ` Vlastimil Babka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).