From 4df1cacea2982a8773024da9a95521172f15037b Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 20 Mar 2025 17:01:26 +0000 Subject: [PATCH 1/4] mrs: drop QUARANTINE_HIGHWATER support If defined at compile time, QUARANTINE_HIGHWATER limited the size of the quarantine to QUARANTINE_HIGHWATER bytes. Given the vast range of working set sizes this isn't particularly useful except perhaps to set it to 0. The environment variable _RUNTIME_REVOCATION_EVERY_FREE_ENABLE and associated sysctl now serves this purpose. --- lib/libc/stdlib/malloc/mrs/mrs.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/libc/stdlib/malloc/mrs/mrs.c b/lib/libc/stdlib/malloc/mrs/mrs.c index a20f76d1bd4c..f203999cf509 100644 --- a/lib/libc/stdlib/malloc/mrs/mrs.c +++ b/lib/libc/stdlib/malloc/mrs/mrs.c @@ -91,8 +91,6 @@ * * Values: * - * QUARANTINE_HIGHWATER: Limit the quarantine size to - * QUARANTINE_HIGHWATER number of bytes. * QUARANTINE_RATIO: Limit the quarantine size to 1 / QUARANTINE_RATIO * times the size of the heap (default 4). * CONCURRENT_REVOCATION_PASSES: Number of concurrent revocation pass @@ -757,20 +755,12 @@ quarantine_should_flush(struct mrs_quarantine *quarantine, bool is_free) return false; #endif -#if defined(QUARANTINE_HIGHWATER) - - return (quarantine->size >= QUARANTINE_HIGHWATER); - -#else /* QUARANTINE_HIGHWATER */ - #if !defined(QUARANTINE_RATIO) # define QUARANTINE_RATIO 4 #endif /* !QUARANTINE_RATIO */ return ((allocated_size >= MIN_REVOKE_HEAP_SIZE) && ((quarantine->size * QUARANTINE_RATIO) >= allocated_size)); - -#endif /* !QUARANTINE_HIGHWATER */ } static void From 86d0427cb38a34b93ea0f05d18cc415be7a14643 Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Mon, 24 Mar 2025 18:07:40 +0000 Subject: [PATCH 2/4] mrs: remove CONCURRENT_REVOCATION_PASSES docs Use of this macro was removed with store-side revocation support. Fixes: 62e91150631b mrs: remove store-side support") --- lib/libc/stdlib/malloc/mrs/mrs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/libc/stdlib/malloc/mrs/mrs.c b/lib/libc/stdlib/malloc/mrs/mrs.c index f203999cf509..38c8dc0812cf 100644 --- a/lib/libc/stdlib/malloc/mrs/mrs.c +++ b/lib/libc/stdlib/malloc/mrs/mrs.c @@ -93,8 +93,6 @@ * * QUARANTINE_RATIO: Limit the quarantine size to 1 / QUARANTINE_RATIO * times the size of the heap (default 4). - * CONCURRENT_REVOCATION_PASSES: Number of concurrent revocation pass - * before the stop-the-world pass. */ #define MALLOCX_LG_ALIGN_BITS 6 From 878ab46701ec33be1418c471646f5a2a59c2322c Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 20 Mar 2025 18:13:58 +0000 Subject: [PATCH 3/4] mrs: replace QUARANTINE_RATIO with a fraction This allow more granularity including allowing quarantine to exceed 1/2 the size of the heap. Replace QUARANTINE_RATIO with QUARANTINE_NUMERATOR and QUARANTINE_DENOMINATOR. The quarantine is flushed when: QUARANTINE_NUMERATOR >= * ---------------------- QUARANTINE_DENOMINATOR The default values are QUARANTINE_NUMERATOR=1 and QUARANTINE_DENOMINATOR=4 respectively giving the same behavior as the previous default QUARANTINE_RATIO=4. --- lib/libc/stdlib/malloc/mrs/mrs.c | 54 +++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/lib/libc/stdlib/malloc/mrs/mrs.c b/lib/libc/stdlib/malloc/mrs/mrs.c index 38c8dc0812cf..8af1bd01522d 100644 --- a/lib/libc/stdlib/malloc/mrs/mrs.c +++ b/lib/libc/stdlib/malloc/mrs/mrs.c @@ -91,10 +91,21 @@ * * Values: * - * QUARANTINE_RATIO: Limit the quarantine size to 1 / QUARANTINE_RATIO - * times the size of the heap (default 4). + * QUARANTINE_NUMERATOR / QUARANTINE_DENOMINATOR: Limit the quarantine + * size to QUARANTINE_NUMERATOR / QUARANTINE_DENOMINATOR times the size + * of the heap (default 1/4). */ +#ifdef QUARANTINE_RATIO +#error QUARANTINE_RATIO is obsolete, use QUARANTINE_NUMERATOR/QUARANTINE_DENOMINATOR +#endif +#ifndef QUARANTINE_DENOMINATOR +#define QUARANTINE_DENOMINATOR 4 +#endif +#ifndef QUARANTINE_NUMERATOR +#define QUARANTINE_NUMERATOR 1 +#endif + #define MALLOCX_LG_ALIGN_BITS 6 #define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) /* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ @@ -303,6 +314,9 @@ static bool bound_pointers = false; static bool abort_on_validation_failure = true; static bool mrs_initialized = false; +static unsigned int quarantine_denominator = QUARANTINE_DENOMINATOR; +static unsigned int quarantine_numerator = QUARANTINE_NUMERATOR; + static spinlock_t mrs_init_lock = _SPINLOCK_INITIALIZER; #define MRS_LOCK(x) __extension__ ({ \ if (__isthreaded) \ @@ -753,12 +767,19 @@ quarantine_should_flush(struct mrs_quarantine *quarantine, bool is_free) return false; #endif -#if !defined(QUARANTINE_RATIO) -# define QUARANTINE_RATIO 4 -#endif /* !QUARANTINE_RATIO */ + if (allocated_size < MIN_REVOKE_HEAP_SIZE) + return false; - return ((allocated_size >= MIN_REVOKE_HEAP_SIZE) && - ((quarantine->size * QUARANTINE_RATIO) >= allocated_size)); + /* + * Flush quarantine if + * quarantine_numerator + * quarantine->size >= allocated_size * ---------------------- + * quarantine_denominator + * + * Avoid division by multiplying both sides by quarantine_numerator. + */ + return (quarantine->size * quarantine_denominator >= + allocated_size * quarantine_numerator); } static void @@ -1295,6 +1316,25 @@ mrs_init_impl_locked(void) exit(7); } + if (quarantine_denominator == 0) { + mrs_puts("quarantine_denominator can not be 0\n"); + exit(7); + } + if (quarantine_denominator > 256) { + /* Could overflow with 56-bits of userspace addresses */ + mrs_puts("quarantine_denominator > 256\n"); + exit(7); + } + if (quarantine_numerator == 0) { + mrs_puts("quarantine_numerator can not be 0\n"); + exit(7); + } + if (quarantine_numerator > 256) { + /* Could overflow with 56-bits of userspace addresses */ + mrs_puts("quarantine_numerator > 256\n"); + exit(7); + } + if (!issetugid()) { mrs_utrace = (getenv(MRS_UTRACE_ENV) != NULL); } From 64947fcb9df9e11bbb743a2a42d5562a5f85150b Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Thu, 20 Mar 2025 19:20:50 +0000 Subject: [PATCH 4/4] mrs: make quarantine size tuneable The environmental variables _RUNTIME_QUARANTINE_NUMERATOR and _RUNTIME_QUARANTINE_DENOMINATOR can now override compiled defaults for QUARANTINE_NUMERATOR and QUARANTINE_DENOMINATOR. --- lib/libc/stdlib/malloc/mrs/mrs.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/libc/stdlib/malloc/mrs/mrs.c b/lib/libc/stdlib/malloc/mrs/mrs.c index 8af1bd01522d..cf1f129248ed 100644 --- a/lib/libc/stdlib/malloc/mrs/mrs.c +++ b/lib/libc/stdlib/malloc/mrs/mrs.c @@ -139,6 +139,11 @@ extern void snmalloc_flush_message_queue(void); #define MALLOC_NOBOUND_CHERI_POINTERS \ "_RUNTIME_NOBOUND_CHERI_POINTERS" +#define MALLOC_QUARANTINE_DENOMINATOR_ENV \ + "_RUNTIME_QUARANTINE_DENOMINATOR" +#define MALLOC_QUARANTINE_NUMERATOR_ENV \ + "_RUNTIME_QUARANTINE_NUMERATOR" + /* * Different allocators give their strong symbols different names. Hide * this implementation detail being the REAL() macro. @@ -1316,6 +1321,31 @@ mrs_init_impl_locked(void) exit(7); } + char *envstr, *end; + if ((envstr = secure_getenv(MALLOC_QUARANTINE_DENOMINATOR_ENV)) != + NULL) { + errno = 0; + quarantine_denominator = strtoul(envstr, &end, 0); + if (*end != '\0' || + (quarantine_denominator == ULONG_MAX && + errno == ERANGE)) { + mrs_puts("invalid " + MALLOC_QUARANTINE_DENOMINATOR_ENV "\n"); + exit(7); + } + } + if ((envstr = secure_getenv(MALLOC_QUARANTINE_NUMERATOR_ENV)) != + NULL) { + errno = 0; + quarantine_numerator = strtoul(envstr, &end, 0); + if (*end != '\0' || + (quarantine_numerator == ULONG_MAX && + errno == ERANGE)) { + mrs_puts("invalid " + MALLOC_QUARANTINE_NUMERATOR_ENV "\n"); + exit(7); + } + } if (quarantine_denominator == 0) { mrs_puts("quarantine_denominator can not be 0\n"); exit(7);