diff --git a/lib/libc/stdlib/malloc/mrs/mrs.c b/lib/libc/stdlib/malloc/mrs/mrs.c index a20f76d1bd4c..cf1f129248ed 100644 --- a/lib/libc/stdlib/malloc/mrs/mrs.c +++ b/lib/libc/stdlib/malloc/mrs/mrs.c @@ -91,14 +91,21 @@ * * 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 - * before the stop-the-world pass. + * 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. */ @@ -132,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. @@ -307,6 +319,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) \ @@ -757,20 +772,19 @@ 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)); + if (allocated_size < MIN_REVOKE_HEAP_SIZE) + return false; -#endif /* !QUARANTINE_HIGHWATER */ + /* + * 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 @@ -1307,6 +1321,50 @@ 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); + } + 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); }