universalisos/docs/HARDENED_MALLOC.md

8.8 KiB

hardened_malloc in UniversalisOS — Config Matrix, Page-Size Contract & Integration

Track: T8 (hardened_malloc Import & Separation-Model Adoption) Source: universalisos/third_party/hardened_malloc/ (see PROVENANCE.md) Status: T8-1.1 (vendored) · T8-1.3 host build + make test 51/51 · T8-1.2 (musl personality) greenfield — see §4

hardened_malloc is the designated stepping stone to running multiple concurrent hardened Android/AOSP/LineageOS/GrapheneOS guests inside UniversalisOS. It is the only GrapheneOS component portable across the guest/host boundary (Bionic/musl/glibc). Master plan §0.14 + TRACK T8.


1. What was built and verified (2026-07-11)

Artifact Result
out/libhardened_malloc.so (VARIANT=default) Built clean — 53 KB, C23, -O3 -flto -fPIC, all hardening flags active
make test (acceptance gate) 51/51 OK (double-free, overflow, quarantine, canary, usable-size, object-size, realloc/calloc edge cases)
Exported malloc API surface malloc calloc realloc free aligned_alloc posix_memalign memalign cfree reallocarray + hardened extensions malloc_object_size{,_fast} free_sized free_aligned_sized malloc_usable_size malloc_stats malloc_info malloc_trim
Live LD_PRELOAD smoke test PASS — real program allocates/uses/frees correctly under LD_PRELOAD=out/libhardened_malloc.so

Build host: GCC 16.1.1 / Clang 22.1.8 (both C23-capable). CONFIG_NATIVE=true-march=native.


2. Config matrix — default vs light (from config/{default,light}.mk)

Flag default light Meaning
CONFIG_ZERO_ON_FREE true true Clear memory on free (anti data-leak)
CONFIG_WRITE_AFTER_FREE_CHECK true false Detect write-after-free via canary
CONFIG_SLOT_RANDOMIZE true false Randomize slot allocation order
CONFIG_SLAB_CANARY true true Per-allocation canary
CONFIG_SLAB_QUARANTINE_RANDOM_LENGTH 1 0 Random quarantine (use-after-free detection)
CONFIG_SLAB_QUARANTINE_QUEUE_LENGTH 1 0 FIFO quarantine
CONFIG_GUARD_SLABS_INTERVAL 1 8 How often slabs get guard pages
CONFIG_EXTENDED_SIZE_CLASSES true true Finer-grained size classes
CONFIG_LARGE_SIZE_CLASSES true true Large-allocation size classes
CONFIG_REGION_QUARANTINE_RANDOM_LENGTH 256 256 Large-region quarantine
CONFIG_REGION_QUARANTINE_QUEUE_LENGTH 1024 1024 Large-region FIFO quarantine
CONFIG_CLASS_REGION_SIZE 32 GiB 32 GiB Per-size-class virtual region
CONFIG_N_ARENA 4 4 Independent arenas (scalability/isolation)
CONFIG_SELF_INIT true true Self-initializing via constructor(101) (correct for musl/standalone)
CONFIG_STATS false false Runtime stats (enable for debugging)

Selection guidance (T8-1.4):

  • musl POSIX personality (primary target): default — full hardening; the personality is a controlled, trusted environment where the overhead is acceptable and the isolation value is highest.
  • Constrained / RTOS-class guests: light — drops write-after-free check, slot randomization, and slab quarantine for lower overhead while keeping zero-on-free + canary + region quarantine.
  • Host dev tools (opportunistic, glibc): default via preload.sh LD_PRELOAD.
  • Android guests: inherited — Bionic ships its own hardened_malloc build (platform_bionic h_malloc_wrapper.cpp, Android.bp with CONFIG_SELF_INIT=false, N_ARENA=1). UniversalisOS does not rebuild it; it provides the Stage-2 MM features (§5).

Build a variant: make VARIANT=default (or light) → out/libhardened_malloc.so (or out-light/libhardened_malloc-light.so).


3. Page-size contract (HARD)

hardened_malloc assumes a 4 KiB page size, enforced at compile time:

// h_malloc.c:326
static_assert(PAGE_SIZE == 4096, "bitmap handling will need adjustment for other page sizes");

(The subagent noted a runtime sysconf(_SC_PAGESIZE) check; the binding constraint is actually this compile-time static_assert plus the runtime sysconf guard.)

Consequence for UniversalisOS: any personality linking hardened_malloc must use 4 KiB pages.

  • AArch64: 4 KiB translation granule is the common case → compatible. (UOS Stage-2 uses 4 KiB.)
  • riscv64 / armv7: must confirm 4 KiB granule; 16 KiB/64 KiB granule configs are incompatible without porting the bitmap handling.
  • This is a hard contract — a personality reporting a non-4 KiB page size will fail to build/boot with hardened_malloc.

4. T8-1.2 — musl POSIX personality baseline (GREENFIELD)

Current state (verified 2026-07-11): universalisos/kernel/src/core/posix/ contains only config stubs (posix_config.c/h). There is no musl/libc userspace personality yet. The existing guests (guests/linux-aarch64, riscv-sampling, wasm3-app) are full OS guests, not a libc-bearing POSIX personality. So T8-1.2 is genuinely greenfield.

Why musl: hardened_malloc explicitly prefers musl ("a much more robust and cleaner base", README.md:38). A musl-based personality also gives UniversalisOS a clean, non-Google libc story — fits the "freedom from technology" north star.

Path to stand it up (next actions, in order):

  1. Toolchain: obtain an aarch64-linux-musl cross toolchain (buildroot can emit one — the existing guests/linux-aarch64/buildroot-* trees support BR2_TOOLCHAIN_BUILDROOT_LIBC="musl"; or use a prebuilt musl-cross). Host currently has only aarch64-linux-gnu-* (glibc).
  2. Personality skeleton: a minimal EL1/EL0 userspace that the UOS kernel loads as a partition (reuse the guests/ boot path + partition.h), with musl as its libc and a hello-world that calls malloc/printf.
  3. Wire hardened_malloc: link libhardened_malloc.so (built for musl/aarch64 via the standalone Makefile, CONFIG_SELF_INIT=true) ahead of musl's malloc so it becomes the system allocator.
  4. Gate: personality boots under UOS, hello-world allocates/frees via hardened_malloc, and hardened_malloc's make test (cross-built) passes in the personality.

This is the next concrete T8 milestone after the host proof (done).


5. KERNEL_FEATURE_WISHLIST.md → UniversalisOS personality-MM (T8-2.1)

UniversalisOS is the kernel, so it can natively provide what hardened_malloc merely wishes Linux had:

Wishlist item (KERNEL_FEATURE_WISHLIST.md) UOS opportunity
much higher vm.max_map_count hardened_malloc creates many VMAs (guard + per-class regions); UOS personality MM sets a high count natively
disable brk heap / mmap grows upwards from-scratch personality simply doesn't provide brk
alternative to RLIMIT_AS for accountable mappings map to the partition memory domain (partition.h memory partitioning)
MREMAP_DONTUNMAP with expansion memory.c:92-110 uses mremap under HAVE_COMPATIBLE_MREMAP; UOS implements the exact semantics
first-class arbitrarily-sized guard pages hardened_malloc emulates them with separate PROT_NONE VMAs (pages.c:13-30); UOS Stage-2/personality MMU provides them natively — halves VMA count + syscalls
virtual memory quarantine UOS quarantines freed virtual regions at the personality level

Design consequence: treat KERNEL_FEATURE_WISHLIST.md as a requirements document for the UOS personality-MM/syscall layer. UOS can give hardened_malloc a better substrate than Linux — a genuine differentiator and a concrete T8-2 workstream.


6. Why this is the stepping stone to multi-Android guests (recap)

  1. Only portable component: hardened_malloc is the sole GrapheneOS component that crosses the guest/host boundary (Bionic/musl/glibc). Importing it into the musl POSIX personality proves the toolchain + CMake integration + musl personality + MM-feature substrate before a full Android guest.
  2. Per-partition hardening = the separation model made concrete: each PikeOS partition gets its own hardened_malloc instance (independent random bases, quarantine queues, guard regions). A heap-corruption exploit in one guest is contained by (a) isolated Stage-2 address spaces and (b) independently-randomized allocator metadata. Two independent layers.
  3. Forces the MM substrate early: guard pages, high map counts, mremap — exactly what a multi-guest hypervisor needs anyway. Building it for hardened_malloc first de-risks the multi-guest Stage-2 work.

7. Acceptance status

  • T8-1.1 vendor + provenance — DONE (third_party/hardened_malloc/, PROVENANCE.md)
  • T8-1.3 host build libhardened_malloc.so + make test 51/51 + LD_PRELOAD smoke — DONE (host proof)
  • T8-1.4 config matrix + page-size contract + this doc — DONE
  • T8-1.2 musl POSIX personality baseline — GREENFIELD, next milestone (§4)