Coverage Report

Created: 2026-07-16 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/include/haproxy/pool-os.h
Line
Count
Source
1
/*
2
 * include/haproxy/pool-os.h
3
 * OS-level interface for memory management
4
 *
5
 * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation, version 2.1
10
 * exclusively.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
 */
21
22
#ifndef _HAPROXY_POOL_OS_H
23
#define _HAPROXY_POOL_OS_H
24
25
#include <sys/mman.h>
26
#include <stdlib.h>
27
#include <haproxy/api.h>
28
#include <haproxy/tools.h>
29
30
31
/************* normal allocator *************/
32
33
/* allocates an area of size <size> and returns it. The semantics are similar
34
 * to those of malloc().
35
 */
36
static forceinline void *pool_alloc_area(size_t size, size_t align)
37
644
{
38
644
  return ha_aligned_alloc(align, size);
39
644
}
40
41
/* frees an area <area> of size <size> allocated by pool_alloc_area(). The
42
 * semantics are identical to free() except that the size is specified and
43
 * may be ignored.
44
 */
45
static forceinline void pool_free_area(void *area, size_t __maybe_unused size)
46
644
{
47
644
  ha_aligned_free_size(area, size);
48
644
}
49
50
/************* use-after-free allocator *************/
51
52
/* allocates an area of size <size> and returns it. The semantics are similar
53
 * to those of malloc(). However the allocation is rounded up to 4kB so that a
54
 * full page is allocated. This ensures the object can be freed alone so that
55
 * future dereferences are easily detected. The returned object is always at
56
 * least 16-bytes aligned to avoid issues with unaligned structure objects, and
57
 * in any case, is always at least aligned as required by the pool, though no
58
 * more than 4096. In case some padding is added, the area's start address is
59
 * copied at the end of the padding to help detect underflows.
60
 */
61
static inline void *pool_alloc_area_uaf(size_t size, size_t align)
62
0
{
63
0
  size_t pad = (4096 - size) & 0xFF0 & -align;
64
0
  void *ret;
65
66
0
  ret = mmap(NULL, (size + 4095) & -4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
67
0
  if (ret != MAP_FAILED) {
68
    /* let's dereference the page before returning so that the real
69
     * allocation in the system is performed without holding the lock.
70
     */
71
0
    *(int *)ret = 0;
72
0
    if (pad >= sizeof(void *))
73
0
      *(void **)(ret + pad - sizeof(void *)) = ret + pad;
74
0
    ret += pad;
75
0
  } else {
76
0
    ret = NULL;
77
0
  }
78
0
  return ret;
79
0
}
80
81
/* frees an area <area> of size <size> allocated by pool_alloc_area_uaf(). The
82
 * semantics are identical to free() except that the size must absolutely match
83
 * the one passed to pool_alloc_area_uaf(). In case some padding is added, the
84
 * area's start address is compared to the one at the end of the padding, and
85
 * a segfault is triggered if they don't match, indicating an underflow.
86
 */
87
static inline void pool_free_area_uaf(void *area, size_t size)
88
0
{
89
0
  size_t pad = (uintptr_t)area & 4095;
90
91
  /* This object will be released for real in order to detect a use after
92
   * free. We also force a write to the area to ensure we crash on double
93
   * free or free of a const area.
94
   */
95
0
  *(uint32_t *)area = 0xDEADADD4;
96
97
0
  if (pad >= sizeof(void *) && *(void **)(area - sizeof(void *)) != area)
98
0
    ABORT_NOW();
99
100
  /* better know immediately if an address calculation was wrong! */
101
0
  BUG_ON(munmap(area - pad, (size + 4095) & -4096) == -1);
102
0
}
103
104
#endif /* _HAPROXY_POOL_OS_H */
105
106
/*
107
 * Local variables:
108
 *  c-indent-level: 8
109
 *  c-basic-offset: 8
110
 * End:
111
 */