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