diff --git a/Makefile b/Makefile index 65e305f26a..830306e2d8 100644 --- a/Makefile +++ b/Makefile @@ -167,8 +167,8 @@ SMALL_OPTS = #### Debug settings # You can enable debugging on specific code parts by setting DEBUG=-DDEBUG_xxx. # Currently defined DEBUG macros include DEBUG_FULL, DEBUG_MEMORY, DEBUG_FSM, -# DEBUG_HASH, DEBUG_AUTH, DEBUG_SPOE and DEBUG_THREAD. Please check sources for -# exact meaning or do not use at all. +# DEBUG_HASH, DEBUG_AUTH, DEBUG_SPOE, DEBUG_UAF and DEBUG_THREAD. Please check +# sources for exact meaning or do not use at all. DEBUG = #### Trace options diff --git a/include/common/memory.h b/include/common/memory.h index 9277ab6f41..311354c948 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -22,6 +22,8 @@ #ifndef _COMMON_MEMORY_H #define _COMMON_MEMORY_H +#include + #include #include @@ -155,6 +157,8 @@ static inline void *pool_alloc_dirty(struct pool_head *pool) return p; } +#ifndef DEBUG_UAF /* normal allocator */ + /* allocates an area of size and returns it. The semantics are similar * to those of malloc(). */ @@ -172,6 +176,34 @@ static inline void pool_free_area(void *area, size_t __maybe_unused size) free(area); } +#else /* use-after-free detector */ + +/* allocates an area of size and returns it. The semantics are similar + * to those of malloc(). However the allocation is rounded up to 4kB so that a + * full page is allocated. This ensures the object can be freed alone so that + * future dereferences are easily detected. The returned object is always + * 16-bytes aligned to avoid issues with unaligned structure objects. + */ +static inline void *pool_alloc_area(size_t size) +{ + size_t pad = (4096 - size) & 0xFF0; + + return mmap(NULL, (size + 4095) & -4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0) + pad; +} + +/* frees an area of size allocated by pool_alloc_area(). The + * semantics are identical to free() except that the size must absolutely match + * the one passed to pool_alloc_area(). + */ +static inline void pool_free_area(void *area, size_t size) +{ + size_t pad = (4096 - size) & 0xFF0; + + munmap(area - pad, (size + 4095) & -4096); +} + +#endif /* DEBUG_UAF */ + /* * Returns a pointer to type taken from the pool or * dynamically allocated. In the first case, is updated to point to @@ -215,8 +247,16 @@ static inline void pool_free2(struct pool_head *pool, void *ptr) if (*POOL_LINK(pool, ptr) != (void *)pool) *(int *)0 = 0; #endif + +#ifndef DEBUG_UAF /* normal pool behaviour */ *POOL_LINK(pool, ptr) = (void *)pool->free_list; pool->free_list = (void *)ptr; +#else /* release the entry for real to detect use after free */ + /* ensure we crash on double free or free of a const area*/ + *(uint32_t *)ptr = 0xDEADADD4; + pool_free_area(ptr, pool->size + POOL_EXTRA); + pool->allocated--; +#endif /* DEBUG_UAF */ pool->used--; HA_SPIN_UNLOCK(POOL_LOCK, &pool->lock); }