xref: /third_party/openssl/crypto/mem_sec.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci * Copyright 2004-2014, Akamai Technologies. All Rights Reserved.
4e1051a39Sopenharmony_ci *
5e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
6e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
7e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
8e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
9e1051a39Sopenharmony_ci */
10e1051a39Sopenharmony_ci
11e1051a39Sopenharmony_ci/*
12e1051a39Sopenharmony_ci * This file is in two halves. The first half implements the public API
13e1051a39Sopenharmony_ci * to be used by external consumers, and to be used by OpenSSL to store
14e1051a39Sopenharmony_ci * data in a "secure arena." The second half implements the secure arena.
15e1051a39Sopenharmony_ci * For details on that implementation, see below (look for uppercase
16e1051a39Sopenharmony_ci * "SECURE HEAP IMPLEMENTATION").
17e1051a39Sopenharmony_ci */
18e1051a39Sopenharmony_ci#include "e_os.h"
19e1051a39Sopenharmony_ci#include <openssl/crypto.h>
20e1051a39Sopenharmony_ci
21e1051a39Sopenharmony_ci#include <string.h>
22e1051a39Sopenharmony_ci
23e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
24e1051a39Sopenharmony_ci# if defined(_WIN32)
25e1051a39Sopenharmony_ci#  include <windows.h>
26e1051a39Sopenharmony_ci#  if defined(WINAPI_FAMILY_PARTITION)
27e1051a39Sopenharmony_ci#   if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
28e1051a39Sopenharmony_ci/*
29e1051a39Sopenharmony_ci * While VirtualLock is available under the app partition (e.g. UWP),
30e1051a39Sopenharmony_ci * the headers do not define the API. Define it ourselves instead.
31e1051a39Sopenharmony_ci */
32e1051a39Sopenharmony_ciWINBASEAPI
33e1051a39Sopenharmony_ciBOOL
34e1051a39Sopenharmony_ciWINAPI
35e1051a39Sopenharmony_ciVirtualLock(
36e1051a39Sopenharmony_ci    _In_ LPVOID lpAddress,
37e1051a39Sopenharmony_ci    _In_ SIZE_T dwSize
38e1051a39Sopenharmony_ci    );
39e1051a39Sopenharmony_ci#   endif
40e1051a39Sopenharmony_ci#  endif
41e1051a39Sopenharmony_ci# endif
42e1051a39Sopenharmony_ci# include <stdlib.h>
43e1051a39Sopenharmony_ci# include <assert.h>
44e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_UNIX)
45e1051a39Sopenharmony_ci#  include <unistd.h>
46e1051a39Sopenharmony_ci# endif
47e1051a39Sopenharmony_ci# include <sys/types.h>
48e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_UNIX)
49e1051a39Sopenharmony_ci#  include <sys/mman.h>
50e1051a39Sopenharmony_ci#  if defined(__FreeBSD__)
51e1051a39Sopenharmony_ci#    define MADV_DONTDUMP MADV_NOCORE
52e1051a39Sopenharmony_ci#  endif
53e1051a39Sopenharmony_ci#  if !defined(MAP_CONCEAL)
54e1051a39Sopenharmony_ci#    define MAP_CONCEAL 0
55e1051a39Sopenharmony_ci#  endif
56e1051a39Sopenharmony_ci# endif
57e1051a39Sopenharmony_ci# if defined(OPENSSL_SYS_LINUX)
58e1051a39Sopenharmony_ci#  include <sys/syscall.h>
59e1051a39Sopenharmony_ci#  if defined(SYS_mlock2)
60e1051a39Sopenharmony_ci#   include <linux/mman.h>
61e1051a39Sopenharmony_ci#   include <errno.h>
62e1051a39Sopenharmony_ci#  endif
63e1051a39Sopenharmony_ci#  include <sys/param.h>
64e1051a39Sopenharmony_ci# endif
65e1051a39Sopenharmony_ci# include <sys/stat.h>
66e1051a39Sopenharmony_ci# include <fcntl.h>
67e1051a39Sopenharmony_ci#endif
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci#define CLEAR(p, s) OPENSSL_cleanse(p, s)
70e1051a39Sopenharmony_ci#ifndef PAGE_SIZE
71e1051a39Sopenharmony_ci# define PAGE_SIZE    4096
72e1051a39Sopenharmony_ci#endif
73e1051a39Sopenharmony_ci#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
74e1051a39Sopenharmony_ci# define MAP_ANON MAP_ANONYMOUS
75e1051a39Sopenharmony_ci#endif
76e1051a39Sopenharmony_ci
77e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
78e1051a39Sopenharmony_cistatic size_t secure_mem_used;
79e1051a39Sopenharmony_ci
80e1051a39Sopenharmony_cistatic int secure_mem_initialized;
81e1051a39Sopenharmony_ci
82e1051a39Sopenharmony_cistatic CRYPTO_RWLOCK *sec_malloc_lock = NULL;
83e1051a39Sopenharmony_ci
84e1051a39Sopenharmony_ci/*
85e1051a39Sopenharmony_ci * These are the functions that must be implemented by a secure heap (sh).
86e1051a39Sopenharmony_ci */
87e1051a39Sopenharmony_cistatic int sh_init(size_t size, size_t minsize);
88e1051a39Sopenharmony_cistatic void *sh_malloc(size_t size);
89e1051a39Sopenharmony_cistatic void sh_free(void *ptr);
90e1051a39Sopenharmony_cistatic void sh_done(void);
91e1051a39Sopenharmony_cistatic size_t sh_actual_size(char *ptr);
92e1051a39Sopenharmony_cistatic int sh_allocated(const char *ptr);
93e1051a39Sopenharmony_ci#endif
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ciint CRYPTO_secure_malloc_init(size_t size, size_t minsize)
96e1051a39Sopenharmony_ci{
97e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
98e1051a39Sopenharmony_ci    int ret = 0;
99e1051a39Sopenharmony_ci
100e1051a39Sopenharmony_ci    if (!secure_mem_initialized) {
101e1051a39Sopenharmony_ci        sec_malloc_lock = CRYPTO_THREAD_lock_new();
102e1051a39Sopenharmony_ci        if (sec_malloc_lock == NULL)
103e1051a39Sopenharmony_ci            return 0;
104e1051a39Sopenharmony_ci        if ((ret = sh_init(size, minsize)) != 0) {
105e1051a39Sopenharmony_ci            secure_mem_initialized = 1;
106e1051a39Sopenharmony_ci        } else {
107e1051a39Sopenharmony_ci            CRYPTO_THREAD_lock_free(sec_malloc_lock);
108e1051a39Sopenharmony_ci            sec_malloc_lock = NULL;
109e1051a39Sopenharmony_ci        }
110e1051a39Sopenharmony_ci    }
111e1051a39Sopenharmony_ci
112e1051a39Sopenharmony_ci    return ret;
113e1051a39Sopenharmony_ci#else
114e1051a39Sopenharmony_ci    return 0;
115e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
116e1051a39Sopenharmony_ci}
117e1051a39Sopenharmony_ci
118e1051a39Sopenharmony_ciint CRYPTO_secure_malloc_done(void)
119e1051a39Sopenharmony_ci{
120e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
121e1051a39Sopenharmony_ci    if (secure_mem_used == 0) {
122e1051a39Sopenharmony_ci        sh_done();
123e1051a39Sopenharmony_ci        secure_mem_initialized = 0;
124e1051a39Sopenharmony_ci        CRYPTO_THREAD_lock_free(sec_malloc_lock);
125e1051a39Sopenharmony_ci        sec_malloc_lock = NULL;
126e1051a39Sopenharmony_ci        return 1;
127e1051a39Sopenharmony_ci    }
128e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
129e1051a39Sopenharmony_ci    return 0;
130e1051a39Sopenharmony_ci}
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ciint CRYPTO_secure_malloc_initialized(void)
133e1051a39Sopenharmony_ci{
134e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
135e1051a39Sopenharmony_ci    return secure_mem_initialized;
136e1051a39Sopenharmony_ci#else
137e1051a39Sopenharmony_ci    return 0;
138e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
139e1051a39Sopenharmony_ci}
140e1051a39Sopenharmony_ci
141e1051a39Sopenharmony_civoid *CRYPTO_secure_malloc(size_t num, const char *file, int line)
142e1051a39Sopenharmony_ci{
143e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
144e1051a39Sopenharmony_ci    void *ret;
145e1051a39Sopenharmony_ci    size_t actual_size;
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci    if (!secure_mem_initialized) {
148e1051a39Sopenharmony_ci        return CRYPTO_malloc(num, file, line);
149e1051a39Sopenharmony_ci    }
150e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(sec_malloc_lock))
151e1051a39Sopenharmony_ci        return NULL;
152e1051a39Sopenharmony_ci    ret = sh_malloc(num);
153e1051a39Sopenharmony_ci    actual_size = ret ? sh_actual_size(ret) : 0;
154e1051a39Sopenharmony_ci    secure_mem_used += actual_size;
155e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(sec_malloc_lock);
156e1051a39Sopenharmony_ci    return ret;
157e1051a39Sopenharmony_ci#else
158e1051a39Sopenharmony_ci    return CRYPTO_malloc(num, file, line);
159e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
160e1051a39Sopenharmony_ci}
161e1051a39Sopenharmony_ci
162e1051a39Sopenharmony_civoid *CRYPTO_secure_zalloc(size_t num, const char *file, int line)
163e1051a39Sopenharmony_ci{
164e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
165e1051a39Sopenharmony_ci    if (secure_mem_initialized)
166e1051a39Sopenharmony_ci        /* CRYPTO_secure_malloc() zeroes allocations when it is implemented */
167e1051a39Sopenharmony_ci        return CRYPTO_secure_malloc(num, file, line);
168e1051a39Sopenharmony_ci#endif
169e1051a39Sopenharmony_ci    return CRYPTO_zalloc(num, file, line);
170e1051a39Sopenharmony_ci}
171e1051a39Sopenharmony_ci
172e1051a39Sopenharmony_civoid CRYPTO_secure_free(void *ptr, const char *file, int line)
173e1051a39Sopenharmony_ci{
174e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
175e1051a39Sopenharmony_ci    size_t actual_size;
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    if (ptr == NULL)
178e1051a39Sopenharmony_ci        return;
179e1051a39Sopenharmony_ci    if (!CRYPTO_secure_allocated(ptr)) {
180e1051a39Sopenharmony_ci        CRYPTO_free(ptr, file, line);
181e1051a39Sopenharmony_ci        return;
182e1051a39Sopenharmony_ci    }
183e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(sec_malloc_lock))
184e1051a39Sopenharmony_ci        return;
185e1051a39Sopenharmony_ci    actual_size = sh_actual_size(ptr);
186e1051a39Sopenharmony_ci    CLEAR(ptr, actual_size);
187e1051a39Sopenharmony_ci    secure_mem_used -= actual_size;
188e1051a39Sopenharmony_ci    sh_free(ptr);
189e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(sec_malloc_lock);
190e1051a39Sopenharmony_ci#else
191e1051a39Sopenharmony_ci    CRYPTO_free(ptr, file, line);
192e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
193e1051a39Sopenharmony_ci}
194e1051a39Sopenharmony_ci
195e1051a39Sopenharmony_civoid CRYPTO_secure_clear_free(void *ptr, size_t num,
196e1051a39Sopenharmony_ci                              const char *file, int line)
197e1051a39Sopenharmony_ci{
198e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
199e1051a39Sopenharmony_ci    size_t actual_size;
200e1051a39Sopenharmony_ci
201e1051a39Sopenharmony_ci    if (ptr == NULL)
202e1051a39Sopenharmony_ci        return;
203e1051a39Sopenharmony_ci    if (!CRYPTO_secure_allocated(ptr)) {
204e1051a39Sopenharmony_ci        OPENSSL_cleanse(ptr, num);
205e1051a39Sopenharmony_ci        CRYPTO_free(ptr, file, line);
206e1051a39Sopenharmony_ci        return;
207e1051a39Sopenharmony_ci    }
208e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(sec_malloc_lock))
209e1051a39Sopenharmony_ci        return;
210e1051a39Sopenharmony_ci    actual_size = sh_actual_size(ptr);
211e1051a39Sopenharmony_ci    CLEAR(ptr, actual_size);
212e1051a39Sopenharmony_ci    secure_mem_used -= actual_size;
213e1051a39Sopenharmony_ci    sh_free(ptr);
214e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(sec_malloc_lock);
215e1051a39Sopenharmony_ci#else
216e1051a39Sopenharmony_ci    if (ptr == NULL)
217e1051a39Sopenharmony_ci        return;
218e1051a39Sopenharmony_ci    OPENSSL_cleanse(ptr, num);
219e1051a39Sopenharmony_ci    CRYPTO_free(ptr, file, line);
220e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
221e1051a39Sopenharmony_ci}
222e1051a39Sopenharmony_ci
223e1051a39Sopenharmony_ciint CRYPTO_secure_allocated(const void *ptr)
224e1051a39Sopenharmony_ci{
225e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
226e1051a39Sopenharmony_ci    if (!secure_mem_initialized)
227e1051a39Sopenharmony_ci        return 0;
228e1051a39Sopenharmony_ci    /*
229e1051a39Sopenharmony_ci     * Only read accesses to the arena take place in sh_allocated() and this
230e1051a39Sopenharmony_ci     * is only changed by the sh_init() and sh_done() calls which are not
231e1051a39Sopenharmony_ci     * locked.  Hence, it is safe to make this check without a lock too.
232e1051a39Sopenharmony_ci     */
233e1051a39Sopenharmony_ci    return sh_allocated(ptr);
234e1051a39Sopenharmony_ci#else
235e1051a39Sopenharmony_ci    return 0;
236e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
237e1051a39Sopenharmony_ci}
238e1051a39Sopenharmony_ci
239e1051a39Sopenharmony_cisize_t CRYPTO_secure_used(void)
240e1051a39Sopenharmony_ci{
241e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
242e1051a39Sopenharmony_ci    return secure_mem_used;
243e1051a39Sopenharmony_ci#else
244e1051a39Sopenharmony_ci    return 0;
245e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
246e1051a39Sopenharmony_ci}
247e1051a39Sopenharmony_ci
248e1051a39Sopenharmony_cisize_t CRYPTO_secure_actual_size(void *ptr)
249e1051a39Sopenharmony_ci{
250e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
251e1051a39Sopenharmony_ci    size_t actual_size;
252e1051a39Sopenharmony_ci
253e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(sec_malloc_lock))
254e1051a39Sopenharmony_ci        return 0;
255e1051a39Sopenharmony_ci    actual_size = sh_actual_size(ptr);
256e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(sec_malloc_lock);
257e1051a39Sopenharmony_ci    return actual_size;
258e1051a39Sopenharmony_ci#else
259e1051a39Sopenharmony_ci    return 0;
260e1051a39Sopenharmony_ci#endif
261e1051a39Sopenharmony_ci}
262e1051a39Sopenharmony_ci
263e1051a39Sopenharmony_ci/*
264e1051a39Sopenharmony_ci * SECURE HEAP IMPLEMENTATION
265e1051a39Sopenharmony_ci */
266e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_SECURE_MEMORY
267e1051a39Sopenharmony_ci
268e1051a39Sopenharmony_ci
269e1051a39Sopenharmony_ci/*
270e1051a39Sopenharmony_ci * The implementation provided here uses a fixed-sized mmap() heap,
271e1051a39Sopenharmony_ci * which is locked into memory, not written to core files, and protected
272e1051a39Sopenharmony_ci * on either side by an unmapped page, which will catch pointer overruns
273e1051a39Sopenharmony_ci * (or underruns) and an attempt to read data out of the secure heap.
274e1051a39Sopenharmony_ci * Free'd memory is zero'd or otherwise cleansed.
275e1051a39Sopenharmony_ci *
276e1051a39Sopenharmony_ci * This is a pretty standard buddy allocator.  We keep areas in a multiple
277e1051a39Sopenharmony_ci * of "sh.minsize" units.  The freelist and bitmaps are kept separately,
278e1051a39Sopenharmony_ci * so all (and only) data is kept in the mmap'd heap.
279e1051a39Sopenharmony_ci *
280e1051a39Sopenharmony_ci * This code assumes eight-bit bytes.  The numbers 3 and 7 are all over the
281e1051a39Sopenharmony_ci * place.
282e1051a39Sopenharmony_ci */
283e1051a39Sopenharmony_ci
284e1051a39Sopenharmony_ci#define ONE ((size_t)1)
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_ci# define TESTBIT(t, b)  (t[(b) >> 3] &  (ONE << ((b) & 7)))
287e1051a39Sopenharmony_ci# define SETBIT(t, b)   (t[(b) >> 3] |= (ONE << ((b) & 7)))
288e1051a39Sopenharmony_ci# define CLEARBIT(t, b) (t[(b) >> 3] &= (0xFF & ~(ONE << ((b) & 7))))
289e1051a39Sopenharmony_ci
290e1051a39Sopenharmony_ci#define WITHIN_ARENA(p) \
291e1051a39Sopenharmony_ci    ((char*)(p) >= sh.arena && (char*)(p) < &sh.arena[sh.arena_size])
292e1051a39Sopenharmony_ci#define WITHIN_FREELIST(p) \
293e1051a39Sopenharmony_ci    ((char*)(p) >= (char*)sh.freelist && (char*)(p) < (char*)&sh.freelist[sh.freelist_size])
294e1051a39Sopenharmony_ci
295e1051a39Sopenharmony_ci
296e1051a39Sopenharmony_citypedef struct sh_list_st
297e1051a39Sopenharmony_ci{
298e1051a39Sopenharmony_ci    struct sh_list_st *next;
299e1051a39Sopenharmony_ci    struct sh_list_st **p_next;
300e1051a39Sopenharmony_ci} SH_LIST;
301e1051a39Sopenharmony_ci
302e1051a39Sopenharmony_citypedef struct sh_st
303e1051a39Sopenharmony_ci{
304e1051a39Sopenharmony_ci    char* map_result;
305e1051a39Sopenharmony_ci    size_t map_size;
306e1051a39Sopenharmony_ci    char *arena;
307e1051a39Sopenharmony_ci    size_t arena_size;
308e1051a39Sopenharmony_ci    char **freelist;
309e1051a39Sopenharmony_ci    ossl_ssize_t freelist_size;
310e1051a39Sopenharmony_ci    size_t minsize;
311e1051a39Sopenharmony_ci    unsigned char *bittable;
312e1051a39Sopenharmony_ci    unsigned char *bitmalloc;
313e1051a39Sopenharmony_ci    size_t bittable_size; /* size in bits */
314e1051a39Sopenharmony_ci} SH;
315e1051a39Sopenharmony_ci
316e1051a39Sopenharmony_cistatic SH sh;
317e1051a39Sopenharmony_ci
318e1051a39Sopenharmony_cistatic size_t sh_getlist(char *ptr)
319e1051a39Sopenharmony_ci{
320e1051a39Sopenharmony_ci    ossl_ssize_t list = sh.freelist_size - 1;
321e1051a39Sopenharmony_ci    size_t bit = (sh.arena_size + ptr - sh.arena) / sh.minsize;
322e1051a39Sopenharmony_ci
323e1051a39Sopenharmony_ci    for (; bit; bit >>= 1, list--) {
324e1051a39Sopenharmony_ci        if (TESTBIT(sh.bittable, bit))
325e1051a39Sopenharmony_ci            break;
326e1051a39Sopenharmony_ci        OPENSSL_assert((bit & 1) == 0);
327e1051a39Sopenharmony_ci    }
328e1051a39Sopenharmony_ci
329e1051a39Sopenharmony_ci    return list;
330e1051a39Sopenharmony_ci}
331e1051a39Sopenharmony_ci
332e1051a39Sopenharmony_ci
333e1051a39Sopenharmony_cistatic int sh_testbit(char *ptr, int list, unsigned char *table)
334e1051a39Sopenharmony_ci{
335e1051a39Sopenharmony_ci    size_t bit;
336e1051a39Sopenharmony_ci
337e1051a39Sopenharmony_ci    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
338e1051a39Sopenharmony_ci    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
339e1051a39Sopenharmony_ci    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
340e1051a39Sopenharmony_ci    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
341e1051a39Sopenharmony_ci    return TESTBIT(table, bit);
342e1051a39Sopenharmony_ci}
343e1051a39Sopenharmony_ci
344e1051a39Sopenharmony_cistatic void sh_clearbit(char *ptr, int list, unsigned char *table)
345e1051a39Sopenharmony_ci{
346e1051a39Sopenharmony_ci    size_t bit;
347e1051a39Sopenharmony_ci
348e1051a39Sopenharmony_ci    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
349e1051a39Sopenharmony_ci    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
350e1051a39Sopenharmony_ci    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
351e1051a39Sopenharmony_ci    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
352e1051a39Sopenharmony_ci    OPENSSL_assert(TESTBIT(table, bit));
353e1051a39Sopenharmony_ci    CLEARBIT(table, bit);
354e1051a39Sopenharmony_ci}
355e1051a39Sopenharmony_ci
356e1051a39Sopenharmony_cistatic void sh_setbit(char *ptr, int list, unsigned char *table)
357e1051a39Sopenharmony_ci{
358e1051a39Sopenharmony_ci    size_t bit;
359e1051a39Sopenharmony_ci
360e1051a39Sopenharmony_ci    OPENSSL_assert(list >= 0 && list < sh.freelist_size);
361e1051a39Sopenharmony_ci    OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
362e1051a39Sopenharmony_ci    bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
363e1051a39Sopenharmony_ci    OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
364e1051a39Sopenharmony_ci    OPENSSL_assert(!TESTBIT(table, bit));
365e1051a39Sopenharmony_ci    SETBIT(table, bit);
366e1051a39Sopenharmony_ci}
367e1051a39Sopenharmony_ci
368e1051a39Sopenharmony_cistatic void sh_add_to_list(char **list, char *ptr)
369e1051a39Sopenharmony_ci{
370e1051a39Sopenharmony_ci    SH_LIST *temp;
371e1051a39Sopenharmony_ci
372e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_FREELIST(list));
373e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_ARENA(ptr));
374e1051a39Sopenharmony_ci
375e1051a39Sopenharmony_ci    temp = (SH_LIST *)ptr;
376e1051a39Sopenharmony_ci    temp->next = *(SH_LIST **)list;
377e1051a39Sopenharmony_ci    OPENSSL_assert(temp->next == NULL || WITHIN_ARENA(temp->next));
378e1051a39Sopenharmony_ci    temp->p_next = (SH_LIST **)list;
379e1051a39Sopenharmony_ci
380e1051a39Sopenharmony_ci    if (temp->next != NULL) {
381e1051a39Sopenharmony_ci        OPENSSL_assert((char **)temp->next->p_next == list);
382e1051a39Sopenharmony_ci        temp->next->p_next = &(temp->next);
383e1051a39Sopenharmony_ci    }
384e1051a39Sopenharmony_ci
385e1051a39Sopenharmony_ci    *list = ptr;
386e1051a39Sopenharmony_ci}
387e1051a39Sopenharmony_ci
388e1051a39Sopenharmony_cistatic void sh_remove_from_list(char *ptr)
389e1051a39Sopenharmony_ci{
390e1051a39Sopenharmony_ci    SH_LIST *temp, *temp2;
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ci    temp = (SH_LIST *)ptr;
393e1051a39Sopenharmony_ci    if (temp->next != NULL)
394e1051a39Sopenharmony_ci        temp->next->p_next = temp->p_next;
395e1051a39Sopenharmony_ci    *temp->p_next = temp->next;
396e1051a39Sopenharmony_ci    if (temp->next == NULL)
397e1051a39Sopenharmony_ci        return;
398e1051a39Sopenharmony_ci
399e1051a39Sopenharmony_ci    temp2 = temp->next;
400e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_FREELIST(temp2->p_next) || WITHIN_ARENA(temp2->p_next));
401e1051a39Sopenharmony_ci}
402e1051a39Sopenharmony_ci
403e1051a39Sopenharmony_ci
404e1051a39Sopenharmony_cistatic int sh_init(size_t size, size_t minsize)
405e1051a39Sopenharmony_ci{
406e1051a39Sopenharmony_ci    int ret;
407e1051a39Sopenharmony_ci    size_t i;
408e1051a39Sopenharmony_ci    size_t pgsize;
409e1051a39Sopenharmony_ci    size_t aligned;
410e1051a39Sopenharmony_ci#if defined(_WIN32)
411e1051a39Sopenharmony_ci    DWORD flOldProtect;
412e1051a39Sopenharmony_ci    SYSTEM_INFO systemInfo;
413e1051a39Sopenharmony_ci#endif
414e1051a39Sopenharmony_ci
415e1051a39Sopenharmony_ci    memset(&sh, 0, sizeof(sh));
416e1051a39Sopenharmony_ci
417e1051a39Sopenharmony_ci    /* make sure size is a powers of 2 */
418e1051a39Sopenharmony_ci    OPENSSL_assert(size > 0);
419e1051a39Sopenharmony_ci    OPENSSL_assert((size & (size - 1)) == 0);
420e1051a39Sopenharmony_ci    if (size == 0 || (size & (size - 1)) != 0)
421e1051a39Sopenharmony_ci        goto err;
422e1051a39Sopenharmony_ci
423e1051a39Sopenharmony_ci    if (minsize <= sizeof(SH_LIST)) {
424e1051a39Sopenharmony_ci        OPENSSL_assert(sizeof(SH_LIST) <= 65536);
425e1051a39Sopenharmony_ci        /*
426e1051a39Sopenharmony_ci         * Compute the minimum possible allocation size.
427e1051a39Sopenharmony_ci         * This must be a power of 2 and at least as large as the SH_LIST
428e1051a39Sopenharmony_ci         * structure.
429e1051a39Sopenharmony_ci         */
430e1051a39Sopenharmony_ci        minsize = sizeof(SH_LIST) - 1;
431e1051a39Sopenharmony_ci        minsize |= minsize >> 1;
432e1051a39Sopenharmony_ci        minsize |= minsize >> 2;
433e1051a39Sopenharmony_ci        if (sizeof(SH_LIST) > 16)
434e1051a39Sopenharmony_ci            minsize |= minsize >> 4;
435e1051a39Sopenharmony_ci        if (sizeof(SH_LIST) > 256)
436e1051a39Sopenharmony_ci            minsize |= minsize >> 8;
437e1051a39Sopenharmony_ci        minsize++;
438e1051a39Sopenharmony_ci    } else {
439e1051a39Sopenharmony_ci        /* make sure minsize is a powers of 2 */
440e1051a39Sopenharmony_ci          OPENSSL_assert((minsize & (minsize - 1)) == 0);
441e1051a39Sopenharmony_ci          if ((minsize & (minsize - 1)) != 0)
442e1051a39Sopenharmony_ci              goto err;
443e1051a39Sopenharmony_ci    }
444e1051a39Sopenharmony_ci
445e1051a39Sopenharmony_ci    sh.arena_size = size;
446e1051a39Sopenharmony_ci    sh.minsize = minsize;
447e1051a39Sopenharmony_ci    sh.bittable_size = (sh.arena_size / sh.minsize) * 2;
448e1051a39Sopenharmony_ci
449e1051a39Sopenharmony_ci    /* Prevent allocations of size 0 later on */
450e1051a39Sopenharmony_ci    if (sh.bittable_size >> 3 == 0)
451e1051a39Sopenharmony_ci        goto err;
452e1051a39Sopenharmony_ci
453e1051a39Sopenharmony_ci    sh.freelist_size = -1;
454e1051a39Sopenharmony_ci    for (i = sh.bittable_size; i; i >>= 1)
455e1051a39Sopenharmony_ci        sh.freelist_size++;
456e1051a39Sopenharmony_ci
457e1051a39Sopenharmony_ci    sh.freelist = OPENSSL_zalloc(sh.freelist_size * sizeof(char *));
458e1051a39Sopenharmony_ci    OPENSSL_assert(sh.freelist != NULL);
459e1051a39Sopenharmony_ci    if (sh.freelist == NULL)
460e1051a39Sopenharmony_ci        goto err;
461e1051a39Sopenharmony_ci
462e1051a39Sopenharmony_ci    sh.bittable = OPENSSL_zalloc(sh.bittable_size >> 3);
463e1051a39Sopenharmony_ci    OPENSSL_assert(sh.bittable != NULL);
464e1051a39Sopenharmony_ci    if (sh.bittable == NULL)
465e1051a39Sopenharmony_ci        goto err;
466e1051a39Sopenharmony_ci
467e1051a39Sopenharmony_ci    sh.bitmalloc = OPENSSL_zalloc(sh.bittable_size >> 3);
468e1051a39Sopenharmony_ci    OPENSSL_assert(sh.bitmalloc != NULL);
469e1051a39Sopenharmony_ci    if (sh.bitmalloc == NULL)
470e1051a39Sopenharmony_ci        goto err;
471e1051a39Sopenharmony_ci
472e1051a39Sopenharmony_ci    /* Allocate space for heap, and two extra pages as guards */
473e1051a39Sopenharmony_ci#if defined(_SC_PAGE_SIZE) || defined (_SC_PAGESIZE)
474e1051a39Sopenharmony_ci    {
475e1051a39Sopenharmony_ci# if defined(_SC_PAGE_SIZE)
476e1051a39Sopenharmony_ci        long tmppgsize = sysconf(_SC_PAGE_SIZE);
477e1051a39Sopenharmony_ci# else
478e1051a39Sopenharmony_ci        long tmppgsize = sysconf(_SC_PAGESIZE);
479e1051a39Sopenharmony_ci# endif
480e1051a39Sopenharmony_ci        if (tmppgsize < 1)
481e1051a39Sopenharmony_ci            pgsize = PAGE_SIZE;
482e1051a39Sopenharmony_ci        else
483e1051a39Sopenharmony_ci            pgsize = (size_t)tmppgsize;
484e1051a39Sopenharmony_ci    }
485e1051a39Sopenharmony_ci#elif defined(_WIN32)
486e1051a39Sopenharmony_ci    GetSystemInfo(&systemInfo);
487e1051a39Sopenharmony_ci    pgsize = (size_t)systemInfo.dwPageSize;
488e1051a39Sopenharmony_ci#else
489e1051a39Sopenharmony_ci    pgsize = PAGE_SIZE;
490e1051a39Sopenharmony_ci#endif
491e1051a39Sopenharmony_ci    sh.map_size = pgsize + sh.arena_size + pgsize;
492e1051a39Sopenharmony_ci
493e1051a39Sopenharmony_ci#if !defined(_WIN32)
494e1051a39Sopenharmony_ci# ifdef MAP_ANON
495e1051a39Sopenharmony_ci    sh.map_result = mmap(NULL, sh.map_size,
496e1051a39Sopenharmony_ci                         PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_CONCEAL, -1, 0);
497e1051a39Sopenharmony_ci# else
498e1051a39Sopenharmony_ci    {
499e1051a39Sopenharmony_ci        int fd;
500e1051a39Sopenharmony_ci
501e1051a39Sopenharmony_ci        sh.map_result = MAP_FAILED;
502e1051a39Sopenharmony_ci        if ((fd = open("/dev/zero", O_RDWR)) >= 0) {
503e1051a39Sopenharmony_ci            sh.map_result = mmap(NULL, sh.map_size,
504e1051a39Sopenharmony_ci                                 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
505e1051a39Sopenharmony_ci            close(fd);
506e1051a39Sopenharmony_ci        }
507e1051a39Sopenharmony_ci    }
508e1051a39Sopenharmony_ci# endif
509e1051a39Sopenharmony_ci    if (sh.map_result == MAP_FAILED)
510e1051a39Sopenharmony_ci        goto err;
511e1051a39Sopenharmony_ci#else
512e1051a39Sopenharmony_ci    sh.map_result = VirtualAlloc(NULL, sh.map_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
513e1051a39Sopenharmony_ci
514e1051a39Sopenharmony_ci    if (sh.map_result == NULL)
515e1051a39Sopenharmony_ci            goto err;
516e1051a39Sopenharmony_ci#endif
517e1051a39Sopenharmony_ci
518e1051a39Sopenharmony_ci    sh.arena = (char *)(sh.map_result + pgsize);
519e1051a39Sopenharmony_ci    sh_setbit(sh.arena, 0, sh.bittable);
520e1051a39Sopenharmony_ci    sh_add_to_list(&sh.freelist[0], sh.arena);
521e1051a39Sopenharmony_ci
522e1051a39Sopenharmony_ci    /* Now try to add guard pages and lock into memory. */
523e1051a39Sopenharmony_ci    ret = 1;
524e1051a39Sopenharmony_ci
525e1051a39Sopenharmony_ci#if !defined(_WIN32)
526e1051a39Sopenharmony_ci    /* Starting guard is already aligned from mmap. */
527e1051a39Sopenharmony_ci    if (mprotect(sh.map_result, pgsize, PROT_NONE) < 0)
528e1051a39Sopenharmony_ci        ret = 2;
529e1051a39Sopenharmony_ci#else
530e1051a39Sopenharmony_ci    if (VirtualProtect(sh.map_result, pgsize, PAGE_NOACCESS, &flOldProtect) == FALSE)
531e1051a39Sopenharmony_ci        ret = 2;
532e1051a39Sopenharmony_ci#endif
533e1051a39Sopenharmony_ci
534e1051a39Sopenharmony_ci    /* Ending guard page - need to round up to page boundary */
535e1051a39Sopenharmony_ci    aligned = (pgsize + sh.arena_size + (pgsize - 1)) & ~(pgsize - 1);
536e1051a39Sopenharmony_ci#if !defined(_WIN32)
537e1051a39Sopenharmony_ci    if (mprotect(sh.map_result + aligned, pgsize, PROT_NONE) < 0)
538e1051a39Sopenharmony_ci        ret = 2;
539e1051a39Sopenharmony_ci#else
540e1051a39Sopenharmony_ci    if (VirtualProtect(sh.map_result + aligned, pgsize, PAGE_NOACCESS, &flOldProtect) == FALSE)
541e1051a39Sopenharmony_ci        ret = 2;
542e1051a39Sopenharmony_ci#endif
543e1051a39Sopenharmony_ci
544e1051a39Sopenharmony_ci#if defined(OPENSSL_SYS_LINUX) && defined(MLOCK_ONFAULT) && defined(SYS_mlock2)
545e1051a39Sopenharmony_ci    if (syscall(SYS_mlock2, sh.arena, sh.arena_size, MLOCK_ONFAULT) < 0) {
546e1051a39Sopenharmony_ci        if (errno == ENOSYS) {
547e1051a39Sopenharmony_ci            if (mlock(sh.arena, sh.arena_size) < 0)
548e1051a39Sopenharmony_ci                ret = 2;
549e1051a39Sopenharmony_ci        } else {
550e1051a39Sopenharmony_ci            ret = 2;
551e1051a39Sopenharmony_ci        }
552e1051a39Sopenharmony_ci    }
553e1051a39Sopenharmony_ci#elif defined(_WIN32)
554e1051a39Sopenharmony_ci    if (VirtualLock(sh.arena, sh.arena_size) == FALSE)
555e1051a39Sopenharmony_ci        ret = 2;
556e1051a39Sopenharmony_ci#else
557e1051a39Sopenharmony_ci    if (mlock(sh.arena, sh.arena_size) < 0)
558e1051a39Sopenharmony_ci        ret = 2;
559e1051a39Sopenharmony_ci#endif
560e1051a39Sopenharmony_ci#ifdef MADV_DONTDUMP
561e1051a39Sopenharmony_ci    if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0)
562e1051a39Sopenharmony_ci        ret = 2;
563e1051a39Sopenharmony_ci#endif
564e1051a39Sopenharmony_ci
565e1051a39Sopenharmony_ci    return ret;
566e1051a39Sopenharmony_ci
567e1051a39Sopenharmony_ci err:
568e1051a39Sopenharmony_ci    sh_done();
569e1051a39Sopenharmony_ci    return 0;
570e1051a39Sopenharmony_ci}
571e1051a39Sopenharmony_ci
572e1051a39Sopenharmony_cistatic void sh_done(void)
573e1051a39Sopenharmony_ci{
574e1051a39Sopenharmony_ci    OPENSSL_free(sh.freelist);
575e1051a39Sopenharmony_ci    OPENSSL_free(sh.bittable);
576e1051a39Sopenharmony_ci    OPENSSL_free(sh.bitmalloc);
577e1051a39Sopenharmony_ci#if !defined(_WIN32)
578e1051a39Sopenharmony_ci    if (sh.map_result != MAP_FAILED && sh.map_size)
579e1051a39Sopenharmony_ci        munmap(sh.map_result, sh.map_size);
580e1051a39Sopenharmony_ci#else
581e1051a39Sopenharmony_ci    if (sh.map_result != NULL && sh.map_size)
582e1051a39Sopenharmony_ci        VirtualFree(sh.map_result, 0, MEM_RELEASE);
583e1051a39Sopenharmony_ci#endif
584e1051a39Sopenharmony_ci    memset(&sh, 0, sizeof(sh));
585e1051a39Sopenharmony_ci}
586e1051a39Sopenharmony_ci
587e1051a39Sopenharmony_cistatic int sh_allocated(const char *ptr)
588e1051a39Sopenharmony_ci{
589e1051a39Sopenharmony_ci    return WITHIN_ARENA(ptr) ? 1 : 0;
590e1051a39Sopenharmony_ci}
591e1051a39Sopenharmony_ci
592e1051a39Sopenharmony_cistatic char *sh_find_my_buddy(char *ptr, int list)
593e1051a39Sopenharmony_ci{
594e1051a39Sopenharmony_ci    size_t bit;
595e1051a39Sopenharmony_ci    char *chunk = NULL;
596e1051a39Sopenharmony_ci
597e1051a39Sopenharmony_ci    bit = (ONE << list) + (ptr - sh.arena) / (sh.arena_size >> list);
598e1051a39Sopenharmony_ci    bit ^= 1;
599e1051a39Sopenharmony_ci
600e1051a39Sopenharmony_ci    if (TESTBIT(sh.bittable, bit) && !TESTBIT(sh.bitmalloc, bit))
601e1051a39Sopenharmony_ci        chunk = sh.arena + ((bit & ((ONE << list) - 1)) * (sh.arena_size >> list));
602e1051a39Sopenharmony_ci
603e1051a39Sopenharmony_ci    return chunk;
604e1051a39Sopenharmony_ci}
605e1051a39Sopenharmony_ci
606e1051a39Sopenharmony_cistatic void *sh_malloc(size_t size)
607e1051a39Sopenharmony_ci{
608e1051a39Sopenharmony_ci    ossl_ssize_t list, slist;
609e1051a39Sopenharmony_ci    size_t i;
610e1051a39Sopenharmony_ci    char *chunk;
611e1051a39Sopenharmony_ci
612e1051a39Sopenharmony_ci    if (size > sh.arena_size)
613e1051a39Sopenharmony_ci        return NULL;
614e1051a39Sopenharmony_ci
615e1051a39Sopenharmony_ci    list = sh.freelist_size - 1;
616e1051a39Sopenharmony_ci    for (i = sh.minsize; i < size; i <<= 1)
617e1051a39Sopenharmony_ci        list--;
618e1051a39Sopenharmony_ci    if (list < 0)
619e1051a39Sopenharmony_ci        return NULL;
620e1051a39Sopenharmony_ci
621e1051a39Sopenharmony_ci    /* try to find a larger entry to split */
622e1051a39Sopenharmony_ci    for (slist = list; slist >= 0; slist--)
623e1051a39Sopenharmony_ci        if (sh.freelist[slist] != NULL)
624e1051a39Sopenharmony_ci            break;
625e1051a39Sopenharmony_ci    if (slist < 0)
626e1051a39Sopenharmony_ci        return NULL;
627e1051a39Sopenharmony_ci
628e1051a39Sopenharmony_ci    /* split larger entry */
629e1051a39Sopenharmony_ci    while (slist != list) {
630e1051a39Sopenharmony_ci        char *temp = sh.freelist[slist];
631e1051a39Sopenharmony_ci
632e1051a39Sopenharmony_ci        /* remove from bigger list */
633e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
634e1051a39Sopenharmony_ci        sh_clearbit(temp, slist, sh.bittable);
635e1051a39Sopenharmony_ci        sh_remove_from_list(temp);
636e1051a39Sopenharmony_ci        OPENSSL_assert(temp != sh.freelist[slist]);
637e1051a39Sopenharmony_ci
638e1051a39Sopenharmony_ci        /* done with bigger list */
639e1051a39Sopenharmony_ci        slist++;
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci        /* add to smaller list */
642e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
643e1051a39Sopenharmony_ci        sh_setbit(temp, slist, sh.bittable);
644e1051a39Sopenharmony_ci        sh_add_to_list(&sh.freelist[slist], temp);
645e1051a39Sopenharmony_ci        OPENSSL_assert(sh.freelist[slist] == temp);
646e1051a39Sopenharmony_ci
647e1051a39Sopenharmony_ci        /* split in 2 */
648e1051a39Sopenharmony_ci        temp += sh.arena_size >> slist;
649e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
650e1051a39Sopenharmony_ci        sh_setbit(temp, slist, sh.bittable);
651e1051a39Sopenharmony_ci        sh_add_to_list(&sh.freelist[slist], temp);
652e1051a39Sopenharmony_ci        OPENSSL_assert(sh.freelist[slist] == temp);
653e1051a39Sopenharmony_ci
654e1051a39Sopenharmony_ci        OPENSSL_assert(temp-(sh.arena_size >> slist) == sh_find_my_buddy(temp, slist));
655e1051a39Sopenharmony_ci    }
656e1051a39Sopenharmony_ci
657e1051a39Sopenharmony_ci    /* peel off memory to hand back */
658e1051a39Sopenharmony_ci    chunk = sh.freelist[list];
659e1051a39Sopenharmony_ci    OPENSSL_assert(sh_testbit(chunk, list, sh.bittable));
660e1051a39Sopenharmony_ci    sh_setbit(chunk, list, sh.bitmalloc);
661e1051a39Sopenharmony_ci    sh_remove_from_list(chunk);
662e1051a39Sopenharmony_ci
663e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_ARENA(chunk));
664e1051a39Sopenharmony_ci
665e1051a39Sopenharmony_ci    /* zero the free list header as a precaution against information leakage */
666e1051a39Sopenharmony_ci    memset(chunk, 0, sizeof(SH_LIST));
667e1051a39Sopenharmony_ci
668e1051a39Sopenharmony_ci    return chunk;
669e1051a39Sopenharmony_ci}
670e1051a39Sopenharmony_ci
671e1051a39Sopenharmony_cistatic void sh_free(void *ptr)
672e1051a39Sopenharmony_ci{
673e1051a39Sopenharmony_ci    size_t list;
674e1051a39Sopenharmony_ci    void *buddy;
675e1051a39Sopenharmony_ci
676e1051a39Sopenharmony_ci    if (ptr == NULL)
677e1051a39Sopenharmony_ci        return;
678e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_ARENA(ptr));
679e1051a39Sopenharmony_ci    if (!WITHIN_ARENA(ptr))
680e1051a39Sopenharmony_ci        return;
681e1051a39Sopenharmony_ci
682e1051a39Sopenharmony_ci    list = sh_getlist(ptr);
683e1051a39Sopenharmony_ci    OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
684e1051a39Sopenharmony_ci    sh_clearbit(ptr, list, sh.bitmalloc);
685e1051a39Sopenharmony_ci    sh_add_to_list(&sh.freelist[list], ptr);
686e1051a39Sopenharmony_ci
687e1051a39Sopenharmony_ci    /* Try to coalesce two adjacent free areas. */
688e1051a39Sopenharmony_ci    while ((buddy = sh_find_my_buddy(ptr, list)) != NULL) {
689e1051a39Sopenharmony_ci        OPENSSL_assert(ptr == sh_find_my_buddy(buddy, list));
690e1051a39Sopenharmony_ci        OPENSSL_assert(ptr != NULL);
691e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
692e1051a39Sopenharmony_ci        sh_clearbit(ptr, list, sh.bittable);
693e1051a39Sopenharmony_ci        sh_remove_from_list(ptr);
694e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
695e1051a39Sopenharmony_ci        sh_clearbit(buddy, list, sh.bittable);
696e1051a39Sopenharmony_ci        sh_remove_from_list(buddy);
697e1051a39Sopenharmony_ci
698e1051a39Sopenharmony_ci        list--;
699e1051a39Sopenharmony_ci
700e1051a39Sopenharmony_ci        /* Zero the higher addressed block's free list pointers */
701e1051a39Sopenharmony_ci        memset(ptr > buddy ? ptr : buddy, 0, sizeof(SH_LIST));
702e1051a39Sopenharmony_ci        if (ptr > buddy)
703e1051a39Sopenharmony_ci            ptr = buddy;
704e1051a39Sopenharmony_ci
705e1051a39Sopenharmony_ci        OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
706e1051a39Sopenharmony_ci        sh_setbit(ptr, list, sh.bittable);
707e1051a39Sopenharmony_ci        sh_add_to_list(&sh.freelist[list], ptr);
708e1051a39Sopenharmony_ci        OPENSSL_assert(sh.freelist[list] == ptr);
709e1051a39Sopenharmony_ci    }
710e1051a39Sopenharmony_ci}
711e1051a39Sopenharmony_ci
712e1051a39Sopenharmony_cistatic size_t sh_actual_size(char *ptr)
713e1051a39Sopenharmony_ci{
714e1051a39Sopenharmony_ci    int list;
715e1051a39Sopenharmony_ci
716e1051a39Sopenharmony_ci    OPENSSL_assert(WITHIN_ARENA(ptr));
717e1051a39Sopenharmony_ci    if (!WITHIN_ARENA(ptr))
718e1051a39Sopenharmony_ci        return 0;
719e1051a39Sopenharmony_ci    list = sh_getlist(ptr);
720e1051a39Sopenharmony_ci    OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
721e1051a39Sopenharmony_ci    return sh.arena_size / (ONE << list);
722e1051a39Sopenharmony_ci}
723e1051a39Sopenharmony_ci#endif /* OPENSSL_NO_SECURE_MEMORY */
724