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