How Hard is it to Adapt a Memory Allocator to CHERI?

submited by
Style Pass
2023-09-18 10:00:03

In this post I'm going to flesh out an observation I made in that post, which is that some software needs thoughtful adaption to CHERI if we want to get the security advantages we hope for. Exactly what that thoughtful adaption might look like will vary, probably substantially, between different pieces of software. What, for instance, might it look like for critical, widely used, components? In this post I'm going to look at how memory allocators (henceforth "allocators"), one of software's most fundamental building blocks, can be adapted to CHERI. If you find this interesting, but want greater depth than I'll go into here, you might be interested in the paper Picking a CHERI Allocator: Security and Performance Considerations that this post is based upon. A Simple Allocator It is a truism that virtually every program needs to dynamically allocate memory. Our collective folklore tells us that allocators like dlmalloc or jemalloc are impressive pieces of software that improve on their predecessors, but very few of us can really explain why. We call malloc, realloc, and free and magically chunks of memory are allocated, resized, or freed on our behalf.

As is often the case, one can get a useful insight into allocators by stripping away as much of the cleverness as possible. It turns out that we can write an allocator sufficient to run some real programs in just 25 lines of C: #include <stddef.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> static char *heap_start; static char *heap; static size_t HEAP_SIZE = 1024 * 1024 * 1024; void *malloc(size_t sz) { if (!heap) heap = heap_start = mmap(NULL, HEAP_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,-1,0); sz = __builtin_align_up(sz, _Alignof(max_align_t)); if (heap + sz > heap_start + HEAP_SIZE) return NULL; heap += sz; return heap - sz; } void free(void *ptr) { } void *realloc(void *ptr, size_t sz) { void *new_ptr = malloc(sz); if (ptr && new_ptr) memmove(new_ptr, ptr, sz); return new_ptr; } What we've implemented is a "bump allocator": every time we want to allocate or reallocate a block of memory, we "bump" (i.e. increment) the pointer stored in the variable heap.

Leave a Comment