]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: pools: respect pool alignment in allocations 20250805-memalign-6c
authorWilly Tarreau <w@1wt.eu>
Tue, 5 Aug 2025 16:12:18 +0000 (18:12 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 6 Aug 2025 17:20:36 +0000 (19:20 +0200)
Now pool_alloc_area() takes the alignment in argument and makes use
of ha_aligned_malloc() instead of malloc(). pool_alloc_area_uaf()
simply applies the alignment before returning the mapped area. The
pool_free() functionn calls ha_aligned_free() so as to permit to use
a specific API for aligned alloc/free like mingw requires.

Note that it's possible to see warnings about mismatching sized
during pool_free() since we know both the pool and the type. In
pool_free, adding just this is sufficient to detect potential
offenders:

WARN_ON(__alignof__(*__ptr) > pool->align);

include/haproxy/pool-os.h
src/pool.c

index cf29c58882d459b9285b4534e29795774e77fb72..db938b06985b94f55651e3ef87d87885afb4e554 100644 (file)
@@ -25,6 +25,7 @@
 #include <sys/mman.h>
 #include <stdlib.h>
 #include <haproxy/api.h>
+#include <haproxy/tools.h>
 
 
 /************* normal allocator *************/
@@ -32,9 +33,9 @@
 /* allocates an area of size <size> and returns it. The semantics are similar
  * to those of malloc().
  */
-static forceinline void *pool_alloc_area(size_t size)
+static forceinline void *pool_alloc_area(size_t size, size_t align)
 {
-       return malloc(size);
+       return ha_aligned_alloc(align, size);
 }
 
 /* frees an area <area> of size <size> allocated by pool_alloc_area(). The
@@ -43,8 +44,7 @@ static forceinline void *pool_alloc_area(size_t size)
  */
 static forceinline void pool_free_area(void *area, size_t __maybe_unused size)
 {
-       will_free(area, size);
-       free(area);
+       ha_aligned_free_size(area, size);
 }
 
 /************* use-after-free allocator *************/
@@ -52,14 +52,15 @@ static forceinline void pool_free_area(void *area, size_t __maybe_unused size)
 /* allocates an area of size <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. In case
- * some padding is added, the area's start address is copied at the end of the
- * padding to help detect underflows.
+ * future dereferences are easily detected. The returned object is always at
+ * least 16-bytes aligned to avoid issues with unaligned structure objects, and
+ * in any case, is always at least aligned as required by the pool, though no
+ * more than 4096. In case some padding is added, the area's start address is
+ * copied at the end of the padding to help detect underflows.
  */
-static inline void *pool_alloc_area_uaf(size_t size)
+static inline void *pool_alloc_area_uaf(size_t size, size_t align)
 {
-       size_t pad = (4096 - size) & 0xFF0;
+       size_t pad = (4096 - size) & 0xFF0 & -align;
        void *ret;
 
        ret = mmap(NULL, (size + 4095) & -4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
index 5fa5e5530b0da7d78a446f6e91f6cb6b2149e4d7..d7f68e69b2ef0dda6ce612722bc18aa4ccc7a200 100644 (file)
@@ -490,9 +490,9 @@ void *pool_get_from_os_noinc(struct pool_head *pool)
                void *ptr;
 
                if ((pool_debugging & POOL_DBG_UAF) || (pool->flags & MEM_F_UAF))
-                       ptr = pool_alloc_area_uaf(pool->alloc_sz);
+                       ptr = pool_alloc_area_uaf(pool->alloc_sz, pool->align);
                else
-                       ptr = pool_alloc_area(pool->alloc_sz);
+                       ptr = pool_alloc_area(pool->alloc_sz, pool->align);
                if (ptr)
                        return ptr;
                _HA_ATOMIC_INC(&pool->buckets[pool_tbucket()].failed);