VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1k/crypto/mem_sec.c@ 91789

最後變更 在這個檔案從91789是 90293,由 vboxsync 提交於 3 年 前

openssl-1.1.1k: Applied and adjusted our OpenSSL changes to 1.1.1k. bugref:10072

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

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