]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
malloc: Make sure tcache_key is odd enough
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Tue, 29 Jul 2025 23:55:22 +0000 (01:55 +0200)
committerWilco Dijkstra <wilco.dijkstra@arm.com>
Mon, 11 Aug 2025 14:33:30 +0000 (14:33 +0000)
We want tcache_key not to be a commonly-occurring value in memory, so ensure
a minimum amount of one and zero bits.

And we need it non-zero, otherwise even if tcache_double_free_verify sets
e->key to 0 before calling __libc_free, it gets called again by __libc_free,
thus looping indefinitely.

Fixes: c968fe50628db74b52124d863cd828225a1d305c ("malloc: Use tailcalls in __libc_free")
(cherry picked from commit 2536c4f8584082a1ac4c5e0a2a6222e290d43983)

malloc/malloc.c

index b89b654f17fe243989e305b348fefac7e9b0ccb2..e4e2f03600b5019209dc6b30bad7a4c106778db6 100644 (file)
 /* For uintptr_t.  */
 #include <stdint.h>
 
+/* For stdc_count_ones.  */
+#include <stdbit.h>
+
 /* For va_arg, va_start, va_end.  */
 #include <stdarg.h>
 
@@ -3152,6 +3155,19 @@ tcache_key_initialize (void)
   if (__getrandom_nocancel_nostatus_direct (&tcache_key, sizeof(tcache_key),
                                            GRND_NONBLOCK)
       != sizeof (tcache_key))
+    tcache_key = 0;
+
+  /* We need tcache_key to be non-zero (otherwise tcache_double_free_verify's
+     clearing of e->key would go unnoticed and it would loop getting called
+     through __libc_free), and we want tcache_key not to be a
+     commonly-occurring value in memory, so ensure a minimum amount of one and
+     zero bits.  */
+  int minimum_bits = __WORDSIZE / 4;
+  int maximum_bits = __WORDSIZE - minimum_bits;
+
+  while (labs (tcache_key) <= 0x1000000
+      || stdc_count_ones (tcache_key) < minimum_bits
+      || stdc_count_ones (tcache_key) > maximum_bits)
     {
       tcache_key = random_bits ();
 #if __WORDSIZE == 64