From 0ae14beb2ac340448e81496948d0f88c8d0ccdc6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 8 May 2025 19:52:16 +0200 Subject: [PATCH] DEBUG: pool: permit per-pool UAF configuration The new MEM_F_UAF flag can be set just after a pool's creation to make this pool UAF for debugging purposes. This allows to maintain a better overall performance required to reproduce issues while still having a chance to catch UAF. It will only be used by developers who will manually add it to areas worth being inspected, though. --- doc/internals/api/pools.txt | 4 +++- include/haproxy/pool-t.h | 1 + src/pool.c | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/internals/api/pools.txt b/doc/internals/api/pools.txt index d84fb9d01..f03144081 100644 --- a/doc/internals/api/pools.txt +++ b/doc/internals/api/pools.txt @@ -342,7 +342,9 @@ struct pool_head *create_pool(char *name, uint size, uint flags) "-dMno-merge" is passed on the executable's command line, the pools also need to have the exact same name to be merged. In addition, unless MEM_F_EXACT is set in , the object size will usually be rounded - up to the size of pointers (16 or 32 bytes). The name that will appear + up to the size of pointers (16 or 32 bytes). MEM_F_UAF may be set on a + per-pool basis to enable the UAF detection only for this specific pool, + saving the massive overhead of global usage. The name that will appear in the pool upon merging is the name of the first created pool. The returned pointer is the new (or reused) pool head, or NULL upon error. Pools created this way must be destroyed using pool_destroy(). diff --git a/include/haproxy/pool-t.h b/include/haproxy/pool-t.h index 35bf7a10a..ac2d77254 100644 --- a/include/haproxy/pool-t.h +++ b/include/haproxy/pool-t.h @@ -27,6 +27,7 @@ #define MEM_F_SHARED 0x1 #define MEM_F_EXACT 0x2 +#define MEM_F_UAF 0x4 /* A special pointer for the pool's free_list that indicates someone is * currently manipulating it. Serves as a short-lived lock. diff --git a/src/pool.c b/src/pool.c index f734e2a6b..b56098014 100644 --- a/src/pool.c +++ b/src/pool.c @@ -440,7 +440,7 @@ void *pool_get_from_os_noinc(struct pool_head *pool) if (!pool->limit || pool_allocated(pool) < pool->limit) { void *ptr; - if (pool_debugging & POOL_DBG_UAF) + if ((pool_debugging & POOL_DBG_UAF) || (pool->flags & MEM_F_UAF)) ptr = pool_alloc_area_uaf(pool->alloc_sz); else ptr = pool_alloc_area(pool->alloc_sz); @@ -459,7 +459,7 @@ void *pool_get_from_os_noinc(struct pool_head *pool) */ void pool_put_to_os_nodec(struct pool_head *pool, void *ptr) { - if (pool_debugging & POOL_DBG_UAF) + if ((pool_debugging & POOL_DBG_UAF) || (pool->flags & MEM_F_UAF)) pool_free_area_uaf(ptr, pool->alloc_sz); else pool_free_area(ptr, pool->alloc_sz); @@ -965,6 +965,7 @@ void __pool_free(struct pool_head *pool, void *ptr) #endif if (unlikely((pool_debugging & POOL_DBG_NO_CACHE) || + (pool->flags & MEM_F_UAF) || global.tune.pool_cache_size < pool->size)) { pool_free_nocache(pool, ptr); return;