Index: docs/HardenedAllocator.rst =================================================================== --- docs/HardenedAllocator.rst +++ docs/HardenedAllocator.rst @@ -0,0 +1,110 @@ +======================== +Scudo Hardened Allocator +======================== + +.. contents:: + :local: + :depth: 1 + +Introduction +============ +The Scudo Hardened Allocator is a user-mode allocator based on LLVM Sanitizer's +CombinedAllocator, which aims at providing additional mitigations against heap +based vulnerabilities, while retaining good performances. + +The name "Scudo" has been retained from the initial implementation (Escudo +meaning Shield in Spanish and Portuguese). + +Design +====== +Chunk Header +------------ +Every chunk of heap memory will be preceded by a chunk header. This has two +purposes, the first one being to store various information about the chunk, +the second one being to detect potential heap overflows. In order to achieve +this, the header will be checksumed, involving the pointer to the chunk itself +and a global secret. Any corruption of the header will be detected when said +header is accessed, and the process terminated. + +The following information is stored in the header: + +- the 16-bit checksum; +- the user requested size for that chunk, which is necessary for reallocation + purposes; +- the state of the chunk (available, allocated or quarantined); +- the allocation type (malloc, new, new[] or memalign), to detect potential + mismatches in the allocation APIs used; +- whether or not the chunk is offseted (ie: if the chunk beginning is different + than the backend allocation beginning, which is most often the case with some + aligned allocations); +- the associated offset; +- a 16-bit salt. + +On x64, which is currently the only architecture supported, the header fits +within 16-bytes, which works nicely with the minimum alignment requirements. + +The checksum is computed as a CRC32 (if the associated CPU instructions are +available) of the chunk pointer itself, and the 16 bytes of header with the +checksum field zeroed out. The result is then xored with a global secret. + +The header is atomically loaded and stored to prevent races (this requires +platform support such as the cmpxchg16b intruction). This is important as two +consecutives chunks could belong to different threads. We also want to avoid +any type of double fetches of information located in the header, and use stack +copies of the header for this purpose. + +Delayed Freelist +----------------- +A delayed freelist allows us to not return a chunk directly to the backend, but +to keep it aside for a while. Once a criterion is met, the delayed freelist is +emptied, and the quarantined chunks are returned to the backend. This help +mitigates use-after-free vulnerabilities to reducing the determinism of the +allocation and deallocation patterns. + +This feature is using the Sanitizer's Quarantine as its base, and the amount of +memory that it can hold is configurable by the user (see the Options section +below). + +Randomness +---------- +It is important for the allocator to not make use of fixed addresses. We use +the dynamic base option for the SizeClassAllocator, allowing us to benefit +from the randomness of mmap. + +Usage +===== + +Library +------- +The allocator static library can be built from the LLVM build tree thanks to +the "hardened_library" CMake rule. The associated tests can be exercised thanks +to the "check-hardened_library" CMake rule. + +Linking the static library to your project will likely require the use of the +"whole-archive" linker flag (or equivalent) as we make of the .preinit_array +section to initialize the allocator. Additional linker flags can be required +depending on your project. + +Your linked binary should now make use of the Scudo allocation and deallocation +functions. + +Options +------- +Several aspects of the allocator can be configured through environment options, +following the usual ASan options syntax, through the variable SCUDO_OPTIONS. + +The following options are available: + +- quarantine_size_mb (integer, defaults to -1): the size (in Mb) of quarantine + used to delay the actual deallocation of chunks. Lower value may reduce + memory usage but decrease the effectiveness of the mitigation; + +- alloc_dealloc_mismatch (boolean, defaults to true): whether or not we report + errors on malloc/delete, new/free, new/delete[], etc; + +- new_delete_size_mismatch (boolean, defaults to true): whether or not we + report errors on mismatch between size of new and delete; + +- zero_chunk_contents (boolean, defaults to false): whether or not we zero + chunk contents on allocation and deallocation. +