diff options
| author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2025-07-30 01:55:22 +0200 |
|---|---|---|
| committer | Wilco Dijkstra <wilco.dijkstra@arm.com> | 2025-08-11 14:33:30 +0000 |
| commit | a96a82c4a5efd3139e75cd11fd2a5554164dd5a0 (patch) | |
| tree | 27140c5fe4c4b62a1d6e2465522abaac8cd1a4df | |
| parent | c491dabd8a3de090d1ccb4589421a44e79c5b185 (diff) | |
malloc: Make sure tcache_key is odd enough
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)
| -rw-r--r-- | malloc/malloc.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/malloc/malloc.c b/malloc/malloc.c index b89b654f17..e4e2f03600 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -230,6 +230,9 @@ /* 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 |
