VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1f/crypto/mem_sec.c@ 83531

Last change on this file since 83531 was 83531, checked in by vboxsync, 5 years ago

setting svn:sync-process=export for openssl-1.1.1f, all files except tests

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette