2 * Copyright 2015-2020 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright 2004-2014, Akamai Technologies. All Rights Reserved.
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
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").
19 #include <openssl/crypto.h>
23 #ifndef OPENSSL_NO_SECURE_MEMORY
29 # if defined(OPENSSL_SYS_UNIX)
32 # include <sys/types.h>
33 # if defined(OPENSSL_SYS_UNIX)
34 # include <sys/mman.h>
36 # if defined(OPENSSL_SYS_LINUX)
37 # include <sys/syscall.h>
38 # if defined(SYS_mlock2)
39 # include <linux/mman.h>
42 # include <sys/param.h>
44 # include <sys/stat.h>
48 #define CLEAR(p, s) OPENSSL_cleanse(p, s)
50 # define PAGE_SIZE 4096
52 #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
53 # define MAP_ANON MAP_ANONYMOUS
56 #ifndef OPENSSL_NO_SECURE_MEMORY
57 static size_t secure_mem_used
;
59 static int secure_mem_initialized
;
61 static CRYPTO_RWLOCK
*sec_malloc_lock
= NULL
;
64 * These are the functions that must be implemented by a secure heap (sh).
66 static int sh_init(size_t size
, size_t minsize
);
67 static void *sh_malloc(size_t size
);
68 static void sh_free(void *ptr
);
69 static void sh_done(void);
70 static size_t sh_actual_size(char *ptr
);
71 static int sh_allocated(const char *ptr
);
74 int CRYPTO_secure_malloc_init(size_t size
, size_t minsize
)
76 #ifndef OPENSSL_NO_SECURE_MEMORY
79 if (!secure_mem_initialized
) {
80 sec_malloc_lock
= CRYPTO_THREAD_lock_new();
81 if (sec_malloc_lock
== NULL
)
83 if ((ret
= sh_init(size
, minsize
)) != 0) {
84 secure_mem_initialized
= 1;
86 CRYPTO_THREAD_lock_free(sec_malloc_lock
);
87 sec_malloc_lock
= NULL
;
94 #endif /* OPENSSL_NO_SECURE_MEMORY */
97 int CRYPTO_secure_malloc_done(void)
99 #ifndef OPENSSL_NO_SECURE_MEMORY
100 if (secure_mem_used
== 0) {
102 secure_mem_initialized
= 0;
103 CRYPTO_THREAD_lock_free(sec_malloc_lock
);
104 sec_malloc_lock
= NULL
;
107 #endif /* OPENSSL_NO_SECURE_MEMORY */
111 int CRYPTO_secure_malloc_initialized(void)
113 #ifndef OPENSSL_NO_SECURE_MEMORY
114 return secure_mem_initialized
;
117 #endif /* OPENSSL_NO_SECURE_MEMORY */
120 void *CRYPTO_secure_malloc(size_t num
, const char *file
, int line
)
122 #ifndef OPENSSL_NO_SECURE_MEMORY
126 if (!secure_mem_initialized
) {
127 return CRYPTO_malloc(num
, file
, line
);
129 CRYPTO_THREAD_write_lock(sec_malloc_lock
);
130 ret
= sh_malloc(num
);
131 actual_size
= ret
? sh_actual_size(ret
) : 0;
132 secure_mem_used
+= actual_size
;
133 CRYPTO_THREAD_unlock(sec_malloc_lock
);
136 return CRYPTO_malloc(num
, file
, line
);
137 #endif /* OPENSSL_NO_SECURE_MEMORY */
140 void *CRYPTO_secure_zalloc(size_t num
, const char *file
, int line
)
142 #ifndef OPENSSL_NO_SECURE_MEMORY
143 if (secure_mem_initialized
)
144 /* CRYPTO_secure_malloc() zeroes allocations when it is implemented */
145 return CRYPTO_secure_malloc(num
, file
, line
);
147 return CRYPTO_zalloc(num
, file
, line
);
150 void CRYPTO_secure_free(void *ptr
, const char *file
, int line
)
152 #ifndef OPENSSL_NO_SECURE_MEMORY
157 if (!CRYPTO_secure_allocated(ptr
)) {
158 CRYPTO_free(ptr
, file
, line
);
161 CRYPTO_THREAD_write_lock(sec_malloc_lock
);
162 actual_size
= sh_actual_size(ptr
);
163 CLEAR(ptr
, actual_size
);
164 secure_mem_used
-= actual_size
;
166 CRYPTO_THREAD_unlock(sec_malloc_lock
);
168 CRYPTO_free(ptr
, file
, line
);
169 #endif /* OPENSSL_NO_SECURE_MEMORY */
172 void CRYPTO_secure_clear_free(void *ptr
, size_t num
,
173 const char *file
, int line
)
175 #ifndef OPENSSL_NO_SECURE_MEMORY
180 if (!CRYPTO_secure_allocated(ptr
)) {
181 OPENSSL_cleanse(ptr
, num
);
182 CRYPTO_free(ptr
, file
, line
);
185 CRYPTO_THREAD_write_lock(sec_malloc_lock
);
186 actual_size
= sh_actual_size(ptr
);
187 CLEAR(ptr
, actual_size
);
188 secure_mem_used
-= actual_size
;
190 CRYPTO_THREAD_unlock(sec_malloc_lock
);
194 OPENSSL_cleanse(ptr
, num
);
195 CRYPTO_free(ptr
, file
, line
);
196 #endif /* OPENSSL_NO_SECURE_MEMORY */
199 int CRYPTO_secure_allocated(const void *ptr
)
201 #ifndef OPENSSL_NO_SECURE_MEMORY
204 if (!secure_mem_initialized
)
206 CRYPTO_THREAD_write_lock(sec_malloc_lock
);
207 ret
= sh_allocated(ptr
);
208 CRYPTO_THREAD_unlock(sec_malloc_lock
);
212 #endif /* OPENSSL_NO_SECURE_MEMORY */
215 size_t CRYPTO_secure_used(void)
217 #ifndef OPENSSL_NO_SECURE_MEMORY
218 return secure_mem_used
;
221 #endif /* OPENSSL_NO_SECURE_MEMORY */
224 size_t CRYPTO_secure_actual_size(void *ptr
)
226 #ifndef OPENSSL_NO_SECURE_MEMORY
229 CRYPTO_THREAD_write_lock(sec_malloc_lock
);
230 actual_size
= sh_actual_size(ptr
);
231 CRYPTO_THREAD_unlock(sec_malloc_lock
);
239 * SECURE HEAP IMPLEMENTATION
241 #ifndef OPENSSL_NO_SECURE_MEMORY
245 * The implementation provided here uses a fixed-sized mmap() heap,
246 * which is locked into memory, not written to core files, and protected
247 * on either side by an unmapped page, which will catch pointer overruns
248 * (or underruns) and an attempt to read data out of the secure heap.
249 * Free'd memory is zero'd or otherwise cleansed.
251 * This is a pretty standard buddy allocator. We keep areas in a multiple
252 * of "sh.minsize" units. The freelist and bitmaps are kept separately,
253 * so all (and only) data is kept in the mmap'd heap.
255 * This code assumes eight-bit bytes. The numbers 3 and 7 are all over the
259 #define ONE ((size_t)1)
261 # define TESTBIT(t, b) (t[(b) >> 3] & (ONE << ((b) & 7)))
262 # define SETBIT(t, b) (t[(b) >> 3] |= (ONE << ((b) & 7)))
263 # define CLEARBIT(t, b) (t[(b) >> 3] &= (0xFF & ~(ONE << ((b) & 7))))
265 #define WITHIN_ARENA(p) \
266 ((char*)(p) >= sh.arena && (char*)(p) < &sh.arena[sh.arena_size])
267 #define WITHIN_FREELIST(p) \
268 ((char*)(p) >= (char*)sh.freelist && (char*)(p) < (char*)&sh.freelist[sh.freelist_size])
271 typedef struct sh_list_st
273 struct sh_list_st
*next
;
274 struct sh_list_st
**p_next
;
284 ossl_ssize_t freelist_size
;
286 unsigned char *bittable
;
287 unsigned char *bitmalloc
;
288 size_t bittable_size
; /* size in bits */
293 static size_t sh_getlist(char *ptr
)
295 ossl_ssize_t list
= sh
.freelist_size
- 1;
296 size_t bit
= (sh
.arena_size
+ ptr
- sh
.arena
) / sh
.minsize
;
298 for (; bit
; bit
>>= 1, list
--) {
299 if (TESTBIT(sh
.bittable
, bit
))
301 OPENSSL_assert((bit
& 1) == 0);
308 static int sh_testbit(char *ptr
, int list
, unsigned char *table
)
312 OPENSSL_assert(list
>= 0 && list
< sh
.freelist_size
);
313 OPENSSL_assert(((ptr
- sh
.arena
) & ((sh
.arena_size
>> list
) - 1)) == 0);
314 bit
= (ONE
<< list
) + ((ptr
- sh
.arena
) / (sh
.arena_size
>> list
));
315 OPENSSL_assert(bit
> 0 && bit
< sh
.bittable_size
);
316 return TESTBIT(table
, bit
);
319 static void sh_clearbit(char *ptr
, int list
, unsigned char *table
)
323 OPENSSL_assert(list
>= 0 && list
< sh
.freelist_size
);
324 OPENSSL_assert(((ptr
- sh
.arena
) & ((sh
.arena_size
>> list
) - 1)) == 0);
325 bit
= (ONE
<< list
) + ((ptr
- sh
.arena
) / (sh
.arena_size
>> list
));
326 OPENSSL_assert(bit
> 0 && bit
< sh
.bittable_size
);
327 OPENSSL_assert(TESTBIT(table
, bit
));
328 CLEARBIT(table
, bit
);
331 static void sh_setbit(char *ptr
, int list
, unsigned char *table
)
335 OPENSSL_assert(list
>= 0 && list
< sh
.freelist_size
);
336 OPENSSL_assert(((ptr
- sh
.arena
) & ((sh
.arena_size
>> list
) - 1)) == 0);
337 bit
= (ONE
<< list
) + ((ptr
- sh
.arena
) / (sh
.arena_size
>> list
));
338 OPENSSL_assert(bit
> 0 && bit
< sh
.bittable_size
);
339 OPENSSL_assert(!TESTBIT(table
, bit
));
343 static void sh_add_to_list(char **list
, char *ptr
)
347 OPENSSL_assert(WITHIN_FREELIST(list
));
348 OPENSSL_assert(WITHIN_ARENA(ptr
));
350 temp
= (SH_LIST
*)ptr
;
351 temp
->next
= *(SH_LIST
**)list
;
352 OPENSSL_assert(temp
->next
== NULL
|| WITHIN_ARENA(temp
->next
));
353 temp
->p_next
= (SH_LIST
**)list
;
355 if (temp
->next
!= NULL
) {
356 OPENSSL_assert((char **)temp
->next
->p_next
== list
);
357 temp
->next
->p_next
= &(temp
->next
);
363 static void sh_remove_from_list(char *ptr
)
365 SH_LIST
*temp
, *temp2
;
367 temp
= (SH_LIST
*)ptr
;
368 if (temp
->next
!= NULL
)
369 temp
->next
->p_next
= temp
->p_next
;
370 *temp
->p_next
= temp
->next
;
371 if (temp
->next
== NULL
)
375 OPENSSL_assert(WITHIN_FREELIST(temp2
->p_next
) || WITHIN_ARENA(temp2
->p_next
));
379 static int sh_init(size_t size
, size_t minsize
)
387 SYSTEM_INFO systemInfo
;
390 memset(&sh
, 0, sizeof(sh
));
392 /* make sure size is a powers of 2 */
393 OPENSSL_assert(size
> 0);
394 OPENSSL_assert((size
& (size
- 1)) == 0);
395 if (size
== 0 || (size
& (size
- 1)) != 0)
398 if (minsize
<= sizeof(SH_LIST
)) {
399 OPENSSL_assert(sizeof(SH_LIST
) <= 65536);
401 * Compute the minimum possible allocation size.
402 * This must be a power of 2 and at least as large as the SH_LIST
405 minsize
= sizeof(SH_LIST
) - 1;
406 minsize
|= minsize
>> 1;
407 minsize
|= minsize
>> 2;
408 if (sizeof(SH_LIST
) > 16)
409 minsize
|= minsize
>> 4;
410 if (sizeof(SH_LIST
) > 256)
411 minsize
|= minsize
>> 8;
414 /* make sure minsize is a powers of 2 */
415 OPENSSL_assert((minsize
& (minsize
- 1)) == 0);
416 if ((minsize
& (minsize
- 1)) != 0)
420 sh
.arena_size
= size
;
421 sh
.minsize
= minsize
;
422 sh
.bittable_size
= (sh
.arena_size
/ sh
.minsize
) * 2;
424 /* Prevent allocations of size 0 later on */
425 if (sh
.bittable_size
>> 3 == 0)
428 sh
.freelist_size
= -1;
429 for (i
= sh
.bittable_size
; i
; i
>>= 1)
432 sh
.freelist
= OPENSSL_zalloc(sh
.freelist_size
* sizeof(char *));
433 OPENSSL_assert(sh
.freelist
!= NULL
);
434 if (sh
.freelist
== NULL
)
437 sh
.bittable
= OPENSSL_zalloc(sh
.bittable_size
>> 3);
438 OPENSSL_assert(sh
.bittable
!= NULL
);
439 if (sh
.bittable
== NULL
)
442 sh
.bitmalloc
= OPENSSL_zalloc(sh
.bittable_size
>> 3);
443 OPENSSL_assert(sh
.bitmalloc
!= NULL
);
444 if (sh
.bitmalloc
== NULL
)
447 /* Allocate space for heap, and two extra pages as guards */
448 #if defined(_SC_PAGE_SIZE) || defined (_SC_PAGESIZE)
450 # if defined(_SC_PAGE_SIZE)
451 long tmppgsize
= sysconf(_SC_PAGE_SIZE
);
453 long tmppgsize
= sysconf(_SC_PAGESIZE
);
458 pgsize
= (size_t)tmppgsize
;
460 #elif defined(_WIN32)
461 GetSystemInfo(&systemInfo
);
462 pgsize
= (size_t)systemInfo
.dwPageSize
;
466 sh
.map_size
= pgsize
+ sh
.arena_size
+ pgsize
;
470 sh
.map_result
= mmap(NULL
, sh
.map_size
,
471 PROT_READ
|PROT_WRITE
, MAP_ANON
|MAP_PRIVATE
, -1, 0);
476 sh
.map_result
= MAP_FAILED
;
477 if ((fd
= open("/dev/zero", O_RDWR
)) >= 0) {
478 sh
.map_result
= mmap(NULL
, sh
.map_size
,
479 PROT_READ
|PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
484 if (sh
.map_result
== MAP_FAILED
)
487 sh
.map_result
= VirtualAlloc(NULL
, sh
.map_size
, MEM_COMMIT
| MEM_RESERVE
, PAGE_READWRITE
);
489 if (sh
.map_result
== NULL
)
493 sh
.arena
= (char *)(sh
.map_result
+ pgsize
);
494 sh_setbit(sh
.arena
, 0, sh
.bittable
);
495 sh_add_to_list(&sh
.freelist
[0], sh
.arena
);
497 /* Now try to add guard pages and lock into memory. */
501 /* Starting guard is already aligned from mmap. */
502 if (mprotect(sh
.map_result
, pgsize
, PROT_NONE
) < 0)
505 if (VirtualProtect(sh
.map_result
, pgsize
, PAGE_NOACCESS
, &flOldProtect
) == FALSE
)
509 /* Ending guard page - need to round up to page boundary */
510 aligned
= (pgsize
+ sh
.arena_size
+ (pgsize
- 1)) & ~(pgsize
- 1);
512 if (mprotect(sh
.map_result
+ aligned
, pgsize
, PROT_NONE
) < 0)
515 if (VirtualProtect(sh
.map_result
+ aligned
, pgsize
, PAGE_NOACCESS
, &flOldProtect
) == FALSE
)
519 #if defined(OPENSSL_SYS_LINUX) && defined(MLOCK_ONFAULT) && defined(SYS_mlock2)
520 if (syscall(SYS_mlock2
, sh
.arena
, sh
.arena_size
, MLOCK_ONFAULT
) < 0) {
521 if (errno
== ENOSYS
) {
522 if (mlock(sh
.arena
, sh
.arena_size
) < 0)
528 #elif defined(_WIN32)
529 if (VirtualLock(sh
.arena
, sh
.arena_size
) == FALSE
)
532 if (mlock(sh
.arena
, sh
.arena_size
) < 0)
536 if (madvise(sh
.arena
, sh
.arena_size
, MADV_DONTDUMP
) < 0)
547 static void sh_done(void)
549 OPENSSL_free(sh
.freelist
);
550 OPENSSL_free(sh
.bittable
);
551 OPENSSL_free(sh
.bitmalloc
);
553 if (sh
.map_result
!= MAP_FAILED
&& sh
.map_size
)
554 munmap(sh
.map_result
, sh
.map_size
);
556 if (sh
.map_result
!= NULL
&& sh
.map_size
)
557 VirtualFree(sh
.map_result
, 0, MEM_RELEASE
);
559 memset(&sh
, 0, sizeof(sh
));
562 static int sh_allocated(const char *ptr
)
564 return WITHIN_ARENA(ptr
) ? 1 : 0;
567 static char *sh_find_my_buddy(char *ptr
, int list
)
572 bit
= (ONE
<< list
) + (ptr
- sh
.arena
) / (sh
.arena_size
>> list
);
575 if (TESTBIT(sh
.bittable
, bit
) && !TESTBIT(sh
.bitmalloc
, bit
))
576 chunk
= sh
.arena
+ ((bit
& ((ONE
<< list
) - 1)) * (sh
.arena_size
>> list
));
581 static void *sh_malloc(size_t size
)
583 ossl_ssize_t list
, slist
;
587 if (size
> sh
.arena_size
)
590 list
= sh
.freelist_size
- 1;
591 for (i
= sh
.minsize
; i
< size
; i
<<= 1)
596 /* try to find a larger entry to split */
597 for (slist
= list
; slist
>= 0; slist
--)
598 if (sh
.freelist
[slist
] != NULL
)
603 /* split larger entry */
604 while (slist
!= list
) {
605 char *temp
= sh
.freelist
[slist
];
607 /* remove from bigger list */
608 OPENSSL_assert(!sh_testbit(temp
, slist
, sh
.bitmalloc
));
609 sh_clearbit(temp
, slist
, sh
.bittable
);
610 sh_remove_from_list(temp
);
611 OPENSSL_assert(temp
!= sh
.freelist
[slist
]);
613 /* done with bigger list */
616 /* add to smaller list */
617 OPENSSL_assert(!sh_testbit(temp
, slist
, sh
.bitmalloc
));
618 sh_setbit(temp
, slist
, sh
.bittable
);
619 sh_add_to_list(&sh
.freelist
[slist
], temp
);
620 OPENSSL_assert(sh
.freelist
[slist
] == temp
);
623 temp
+= sh
.arena_size
>> slist
;
624 OPENSSL_assert(!sh_testbit(temp
, slist
, sh
.bitmalloc
));
625 sh_setbit(temp
, slist
, sh
.bittable
);
626 sh_add_to_list(&sh
.freelist
[slist
], temp
);
627 OPENSSL_assert(sh
.freelist
[slist
] == temp
);
629 OPENSSL_assert(temp
-(sh
.arena_size
>> slist
) == sh_find_my_buddy(temp
, slist
));
632 /* peel off memory to hand back */
633 chunk
= sh
.freelist
[list
];
634 OPENSSL_assert(sh_testbit(chunk
, list
, sh
.bittable
));
635 sh_setbit(chunk
, list
, sh
.bitmalloc
);
636 sh_remove_from_list(chunk
);
638 OPENSSL_assert(WITHIN_ARENA(chunk
));
640 /* zero the free list header as a precaution against information leakage */
641 memset(chunk
, 0, sizeof(SH_LIST
));
646 static void sh_free(void *ptr
)
653 OPENSSL_assert(WITHIN_ARENA(ptr
));
654 if (!WITHIN_ARENA(ptr
))
657 list
= sh_getlist(ptr
);
658 OPENSSL_assert(sh_testbit(ptr
, list
, sh
.bittable
));
659 sh_clearbit(ptr
, list
, sh
.bitmalloc
);
660 sh_add_to_list(&sh
.freelist
[list
], ptr
);
662 /* Try to coalesce two adjacent free areas. */
663 while ((buddy
= sh_find_my_buddy(ptr
, list
)) != NULL
) {
664 OPENSSL_assert(ptr
== sh_find_my_buddy(buddy
, list
));
665 OPENSSL_assert(ptr
!= NULL
);
666 OPENSSL_assert(!sh_testbit(ptr
, list
, sh
.bitmalloc
));
667 sh_clearbit(ptr
, list
, sh
.bittable
);
668 sh_remove_from_list(ptr
);
669 OPENSSL_assert(!sh_testbit(ptr
, list
, sh
.bitmalloc
));
670 sh_clearbit(buddy
, list
, sh
.bittable
);
671 sh_remove_from_list(buddy
);
675 /* Zero the higher addressed block's free list pointers */
676 memset(ptr
> buddy
? ptr
: buddy
, 0, sizeof(SH_LIST
));
680 OPENSSL_assert(!sh_testbit(ptr
, list
, sh
.bitmalloc
));
681 sh_setbit(ptr
, list
, sh
.bittable
);
682 sh_add_to_list(&sh
.freelist
[list
], ptr
);
683 OPENSSL_assert(sh
.freelist
[list
] == ptr
);
687 static size_t sh_actual_size(char *ptr
)
691 OPENSSL_assert(WITHIN_ARENA(ptr
));
692 if (!WITHIN_ARENA(ptr
))
694 list
= sh_getlist(ptr
);
695 OPENSSL_assert(sh_testbit(ptr
, list
, sh
.bittable
));
696 return sh
.arena_size
/ (ONE
<< list
);
698 #endif /* OPENSSL_NO_SECURE_MEMORY */