There are various build options to make mimalloc more secure.
With -DMI_SECURE_ENV=ON, only MIMALLOC_SHOW_STATS, MIMALLOC_VERBOSE, and MIMALLOC_ALLOW_THP are accepted from the environment – all other options are ignored.
This is by default enabled for secure mode, MTE, and PAC. This can be overridden by explicitly building with -DMI_SECURE_ENV=OFF. Note: even with OFF, an elevated process ignores all environment options. Moreover, on platforms with guard pages, a program built with secure mode always ignores settings for large or huge OS pages (as pinned memory cannot be guarded). You can still set options programmatically for trusted programs.
mimalloc can be built in secure mode using -DMI_SECURE=OFF|MINIMAL|CHECKED|ON|FULL with CMake. These modes enable software mitigations to make mimalloc more robust against exploits.
With MINIMAL, only mitigations with a small performance impact are added (usually 1-3%):
With CHECKED (the default with -DMI_MTE or -DMI_PAC), the performance and memory impact is still relatively small (usually less than 10%, but can be 2x slower):
With ON, performance and memory usage are impacted further (usually less than 25%, but can be 2 to 3x slower):
The FULL mode additionally places a guard page at the end of each mimalloc page (normally 64 KiB) and checks for byte-precise heap block overflows when freeing. This mode is generally not recommended because it costs more time and memory, and large heaps can reach the maximum VMA limit on Linux.
As always, evaluate with care as part of an overall security strategy as all of the above are mitigations but not guarantees.
(v3 only, experimental)
On recent arm64 hardware with the memory tagging extension (MTE), build with -DMI_MTE=ON to give heap blocks randomized memory tags. Memory can only be accessed through a pointer with the matching tag. Adjacent blocks almost always receive different tags, and freed blocks are retagged, causing most double-free and use-after-free accesses to fault. Tags are chosen from 15 values, excluding the tags of neighboring blocks. Blocks up to 512 KiB are tagged; larger blocks use a trailing guard page because tagging takes time proportional to the block size.
Performance depends on the hardware and workload. On an M5, an MTE build is usually within about 15% of a release build, but can be 2 to 3x slower. -DMI_MTE=ON requires CPU and OS support at runtime and aborts at initialization otherwise. On Linux, this also requires enabling tag checking for all threads. -DMI_MTE=PREFER uses tagging when available and otherwise runs untagged, with performance close to a regular release build. MTE builds have an -mte library suffix, for example mimalloc-mte.o.
MTE enables -DMI_SECURE=CHECKED and -DMI_SECURE_ENV=ON by default. It provides similar and often stronger mitigations than -DMI_SECURE=ON, so combining the two is generally unnecessary.
(v3 only, experimental)
On arm64 hardware with pointer authentication (PAC), build with -DMI_PAC=ON. Mimalloc uses secret hardware keys to sign pointers and validates them on access to detect tampering. On an M5, the overhead is usually about 10%, but can be 1 to 2x slower.
Combining -DMI_MTE=ON -DMI_PAC=ON provides strong mitigation against common heap exploitation techniques. Combined performance is usually within 5% of MTE alone. Mimalloc signs:
Authentication failures abort the process. PAC enables -DMI_SECURE=CHECKED and -DMI_SECURE_ENV=ON by default. -DMI_PAC=ON requires CPU and OS support at runtime and aborts at initialization otherwise. On other platforms, or with MSVC, -DMI_PAC=WEAK signs pointers using a random software process key. An attacker who can read memory may recover that key, but it still prevents forging pointers through blind overwrites.
PAC is part of Armv8.3-A and later. Supported examples include:
Older cores such as Cortex-A76/A78/X1, AWS Graviton2, Ampere Altra, and Raspberry Pi 4 and 5 do not support it.
(v3 only, experimental)
CHERI extends an architecture with capabilities: 128-bit pointers carrying bounds, permissions, and an unforgeable validity tag. Integers cannot be turned into valid pointers. Mimalloc supports the pure-capability ABI, bounding allocated blocks and keeping internal metadata unreachable through user capabilities. The default secure level is 3: CHECKED plus zeroing the first 1 KiB on free and double-free detection. Unlike MTE, CHERI does not prevent use-after-free by itself; that requires capability revocation.
CHERI is available on the Arm Morello research platform and some CHERI RISC-V cores, such as the Codasip X730, running CheriBSD. For a native pure-capability CheriBSD build, use cmake ../.. && make -j. Cross-compilation with CHERI LLVM requires the pure-capability flags, for example:
We thank ARM and Ian Stark for providing a Morello system to test CHERI with mimalloc.