Skip to content

Commit c615edb

Browse files
committed
Add corruption-detection test for probabilistic mitigations
Adds a new functional test, func/corruption_detection, that validates snmalloc's probabilistic memory-safety mitigations actually fire on the corruption patterns they are designed to catch. Without it, regressions that silently weakened a mitigation would be invisible to the existing suite, since every other test exercises only the non-failing arm of the integrity checks. Each scenario runs in a forked child so the expected abort does not kill the harness. Detection is reported as the child being killed by SIGABRT/SIGSEGV/SIGBUS/SIGILL; a clean exit means the corruption went undetected and the test fails. Six scenarios are covered, spanning the local-thread, remote-thread and large-allocation paths: * double_free - small alloc, two local frees of the same slot. Detected by freelist_backward_edge when the resulting cycle is later traversed. * uaf_freelist - small alloc, free, then write garbage into the freed slot's first two words (the obfuscated next/prev). Detected by check_prev on the next freelist consumption. * oob_into_neighbor - tiny allocs, free even slots, overrun from an odd live slot into freed neighbours. Detected by check_prev when the neighbour is later allocated. * remote_double_free - small alloc, free locally, then free again from a different thread (the second free travels via the remote message queue). Detected as !meta->is_unused() in the dealloc path. * remote_uaf - small alloc, free via a different thread, then write garbage through the dangling pointer while the slot sits on the owning allocator's pending-remote queue. Detected by check_prev during handle_message_queue_slow's drain - a code path no other test exercises. * large_double_free - allocation larger than any small sizeclass (handled by the chunk allocator and per-chunk metadata rather than the slab freelist), freed twice. Detected as !meta->is_unused() in the large-dealloc path. The test is Linux-only (uses fork()/waitpid()) and is a no-op when SNMALLOC_CHECK_CLIENT is not defined, since the mitigations it relies on are then compiled out. The test is also instrumented to cooperate with clang source-based coverage: the forked child re-resolves LLVM_PROFILE_FILE with its own pid (the parent's %p expansion is otherwise inherited and all children would write to the same file) and a signal handler flushes .profraw before re-raising the fatal signal. The runtime entry points are declared as weak symbols so the test still links in non-coverage builds. Picked up automatically by make_tests so it runs as both func-corruption_detection-fast and func-corruption_detection-check; the fast variant immediately exits with the "skip" message because the mitigations are off.
1 parent 4e08765 commit c615edb

1 file changed

Lines changed: 401 additions & 0 deletions

File tree

0 commit comments

Comments
 (0)