libisoalloc-sys 0.3.0

Security oriented allocator
Documentation
/* iso_alloc_internal.h - A secure memory allocator
 * Copyright 2023 - chris.rohlf@gmail.com */

#pragma once

/* Modifying the values in this configuration header
 * can significantly improve the performance of your
 * workload, or the security of your runtime. Please
 * read the comments and documentation carefully before
 * modifying these values as many of them are core to
 * how the underlying memory allocator functions */

/* This controls what % of chunks are canaries in a
 * zone. For example, if a zone holds 128 byte chunks
 * then it has (ZONE_USER_SIZE / 128) = 32768 total
 * chunks available for it. The number of canaries is
 * calculated as (32768 / CANARY_COUNT_DIV) = 327.
 * When CANARY_COUNT_DIV = 7 we set aside < %1 of user
 * chunks as canaries because we right shift zone
 * chunk count by this value, e.g. (65535 >> 7 = 511) */
#define CANARY_COUNT_DIV 7

/* The minimum number of free bit slots needed in the
 * cache in order to randomize it. RANDOMIZE_FREELIST
 * must be enabled for this to be used */
#define MIN_RAND_FREELIST 4

/* If you're compiling for Android and want custom names
 * for internal mappings that are viewable from procfs
 * (i.e. /proc/pid/maps) you can modify those names here */
#if NAMED_MAPPINGS
#define SAMPLED_ALLOC_NAME "isoalloc sampled allocation"
#define BIG_ZONE_UD_NAME "isoalloc big zone user data"
#define BIG_ZONE_MD_NAME "isoalloc big zone metadata"
#define GUARD_PAGE_NAME "guard page"
#define ROOT_NAME "isoalloc root"
#define ZONE_BITMAP_NAME "isoalloc zone bitmap"
#define INTERNAL_UZ_NAME "internal isoalloc user zone"
#define PRIVATE_UZ_NAME "private isoalloc user zone"
#define MEM_TAG_NAME "isoalloc zone mem tags"
#define PREALLOC_BITMAPS "isoalloc small bitmaps"
#endif

/* If you're using the UAF_PTR_PAGE functionality and
 * want to change the frequency it is triggered or the
 * magic value that is written */
#if UAF_PTR_PAGE
#define UAF_PTR_PAGE_ODDS 1000000
#endif

/* Zones can be retired after a certain number of
 * allocations. This is computed as the total count
 * of chunks the zone can hold multiplied by this
 * value. The zone is replaced at that point if all
 * of its current chunks are free */
#define ZONE_ALLOC_RETIRE 32

/* This byte value will overwrite the contents
 * of all free'd user chunks if -DSANITIZE_CHUNKS
 * is enabled in the Makefile. The value is completely
 * arbitrary, but non-zero since this could mask
 * some bugs. */
#define POISON_BYTE 0xde

/* See PERFORMANCE.md for notes on huge page sizes.
 * If your system uses a non-default value for huge
 * page sizes you will need to adjust that here */
#if(__linux__ && MAP_HUGETLB) || (__APPLE__ && VM_FLAGS_SUPERPAGE_SIZE_2MB) || (__FreeBSD__ && MAP_HUGETLB) && HUGE_PAGES
#define HUGE_PAGE_SZ 2097152
#endif

/* Size of the zone cache documented in PERFORMANCE.md */
#define ZONE_CACHE_SZ 8

/* Size of the chunk quarantine cache documented in PERFORMANCE.md */
#define CHUNK_QUARANTINE_SZ 64

/* This is the maximum number of zones iso_alloc can
 * create. This is a completely arbitrary number but
 * it does correspond to the size of the _root.zones
 * array. Currently the iso_alloc_zone_t structure is
 * roughly 2112 bytes so this results in 17301504 bytes
 * (~17 MB) for zone meta data. See PERFORMANCE.md for
 * more information on this value. Max is 65535 */
#define MAX_ZONES 8192

/* Anything above this size will need to go through the
 * big zone path. Maximum value here is 131072 due to how
 * we construct the zone bitmap. You can think of this
 * value as roughly equivalent to M_MMAP_THRESHOLD. Valid
 * values for SMALL_SIZE_MAX are powers of 2 through 131072 */
#define SMALL_SIZE_MAX 65536

/* Big zones are for any allocation bigger than SMALL_SIZE_MAX.
 * We reuse them when possible but not if the reuse would
 * result in unused memory that exceeds this value */
#define BIG_ZONE_WASTE 8192

/* The maximum number of big zone free list entries.
 * We want to limit the number of these because they
 * are often backed by a large number of pages */
#define BIG_ZONE_MAX_FREE_LIST 64

/* Big zones can be retired after a certain number of
 * allocations. Big zones pages will be unmapped and
 * not added to the free list after being used N times */
#define BIG_ZONE_ALLOC_RETIRE 16

/* We allocate zones at startup for common sizes.
 * Each of these default zones is 4mb (ZONE_USER_SIZE)
 * so ZONE_8192 would hold less chunks than ZONE_128 */
#define ZONE_16 16
#define ZONE_32 32
#define ZONE_64 64
#define ZONE_128 128
#define ZONE_256 256
#define ZONE_512 512
#define ZONE_1024 1024
#define ZONE_2048 2048
#define ZONE_4096 4096
#define ZONE_8192 8192

/* Default zones should ideally never be above 8192
 * bytes in size. This is because the allocator makes
 * certain decisions based on this value such as the
 * number of canary values in a zone. It is safe to
 * modify to a larger value but you will likely be
 * wasting memory by doing so. */
#define MAX_DEFAULT_ZONE_SZ ZONE_8192

/* If you have specific allocation pattern requirements
 * then you may want a custom set of default zones. These
 * example are provided to get you started. Zone creation
 * at runtime is *not* limited to these sizes, this defines
 * the default zones that will be created at startup time.
 * Each of these examples is 4 default zones which will
 * consume 16 mb of memory for user chunks, plus 2 guard
 * pages per zone, a bitmap, and 2 guard pages per bitmap.
 * You also need to define SMALLEST_CHUNK_SZ which should
 * correspond to the smallest value in your default_zones
 * array. It's value should never be less than 16 */
#if SMALL_MEM_STARTUP
/* ZONE_USER_SIZE * sizeof(default_zones) = ~16 mb */
/* SZ_ALIGNMENT = 32 */
#define SMALLEST_CHUNK_SZ SZ_ALIGNMENT
const static uint64_t default_zones[] = {ZONE_64, ZONE_256, ZONE_512, ZONE_1024};
#else
/* ZONE_USER_SIZE * sizeof(default_zones) = ~40 mb */
#define SMALLEST_CHUNK_SZ SZ_ALIGNMENT
const static uint64_t default_zones[] = {ZONE_32, ZONE_64, ZONE_128, ZONE_256, ZONE_512,
                                         ZONE_1024, ZONE_2048, ZONE_4096, ZONE_8192};
#endif

/* Additional default zone example configurations are below */

#if 0
/* Only small allocations between 16 and 28 bytes are expected */
#define SMALLEST_CHUNK_SZ ZONE_16
static uint64_t default_zones[] = {ZONE_32, ZONE_32, ZONE_64, ZONE_64, ZONE_128, ZONE_128};
#endif

#if 0
/* Large allocations but smaller than a page */
#define SMALLEST_CHUNK_SZ ZONE_512
static uint64_t default_zones[] = {ZONE_512, ZONE_1024, ZONE_2048, ZONE_4096};
#endif