blob: 959c63714f32d40427c8a3375b79cab080f6ff63 [file] [log] [blame]
Rich Salz74924dc2015-04-24 16:39:40 -04001/*
Richard Levitte48e51192018-01-19 10:49:22 +01002 * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
Rich Salz624265c2017-06-15 12:03:40 -04003 * Copyright 2004-2014, Akamai Technologies. All Rights Reserved.
Rich Salz4f22f402016-05-17 14:51:04 -04004 *
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/*
Rich Salz74924dc2015-04-24 16:39:40 -040012 * 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 */
Rich Salzbef7a812017-08-22 11:07:56 -040018#include "e_os.h"
Pauli07016a82017-08-24 09:05:07 +100019#include <openssl/crypto.h>
Rich Salz74924dc2015-04-24 16:39:40 -040020
Richard Levitte183733f2016-02-10 03:54:45 +010021#include <string.h>
22
Richard Levittee44c7d02018-01-18 14:05:33 +010023/* e_os.h includes unistd.h, which defines _POSIX_VERSION */
Bernd Edlinger154d8c12018-01-19 14:00:14 +010024#if !defined(OPENSSL_NO_SECURE_MEMORY) && defined(OPENSSL_SYS_UNIX) \
Andy Polyakov58391852018-02-25 16:56:26 +010025 && ( (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
26 || defined(__sun) || defined(__hpux) || defined(__sgi) \
27 || defined(__osf__) )
Rich Salz74924dc2015-04-24 16:39:40 -040028# define IMPLEMENTED
Rich Salzd4dfb0b2015-06-23 18:33:02 -040029# include <stdlib.h>
Rich Salzd4dfb0b2015-06-23 18:33:02 -040030# include <assert.h>
31# include <unistd.h>
Andy Polyakov27186da2015-11-13 21:30:44 +010032# include <sys/types.h>
Rich Salz74924dc2015-04-24 16:39:40 -040033# include <sys/mman.h>
Todd Short9dfc5b92017-03-23 12:56:22 -040034# if defined(OPENSSL_SYS_LINUX)
35# include <sys/syscall.h>
Andy Polyakovf1c00b92018-03-10 19:38:28 +010036# if defined(SYS_mlock2)
37# include <linux/mman.h>
38# include <errno.h>
39# endif
Todd Short9dfc5b92017-03-23 12:56:22 -040040# endif
Rich Salz74924dc2015-04-24 16:39:40 -040041# include <sys/param.h>
Andy Polyakov27186da2015-11-13 21:30:44 +010042# include <sys/stat.h>
43# include <fcntl.h>
Rich Salz74924dc2015-04-24 16:39:40 -040044#endif
45
Rich Salz74924dc2015-04-24 16:39:40 -040046#define CLEAR(p, s) OPENSSL_cleanse(p, s)
Ben Laurie34750dc2015-07-31 09:49:20 +010047#ifndef PAGE_SIZE
48# define PAGE_SIZE 4096
49#endif
Andy Polyakov014cc4b2018-03-02 16:50:11 +010050#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
51# define MAP_ANON MAP_ANONYMOUS
52#endif
Rich Salz74924dc2015-04-24 16:39:40 -040053
54#ifdef IMPLEMENTED
Ben Lauriedf2ee0e2015-09-05 13:32:58 +010055static size_t secure_mem_used;
Rich Salz74924dc2015-04-24 16:39:40 -040056
57static int secure_mem_initialized;
Rich Salz74924dc2015-04-24 16:39:40 -040058
Matt Caswell9471f772016-03-08 15:44:05 +000059static CRYPTO_RWLOCK *sec_malloc_lock = NULL;
60
Rich Salz74924dc2015-04-24 16:39:40 -040061/*
62 * These are the functions that must be implemented by a secure heap (sh).
63 */
64static int sh_init(size_t size, int minsize);
Rich Salz332dc4f2017-03-02 19:16:57 -050065static void *sh_malloc(size_t size);
66static void sh_free(void *ptr);
Rich Salz74924dc2015-04-24 16:39:40 -040067static void sh_done(void);
Todd Shorte8408682016-04-11 16:03:42 -040068static size_t sh_actual_size(char *ptr);
Rich Salz74924dc2015-04-24 16:39:40 -040069static int sh_allocated(const char *ptr);
70#endif
71
72int CRYPTO_secure_malloc_init(size_t size, int minsize)
73{
74#ifdef IMPLEMENTED
75 int ret = 0;
76
Rich Salz74924dc2015-04-24 16:39:40 -040077 if (!secure_mem_initialized) {
Benjamin Kaduk63ab5ea2018-01-16 09:49:54 -060078 sec_malloc_lock = CRYPTO_THREAD_lock_new();
Matt Caswell9471f772016-03-08 15:44:05 +000079 if (sec_malloc_lock == NULL)
80 return 0;
Todd Short7031dda2017-05-11 15:48:10 -040081 if ((ret = sh_init(size, minsize)) != 0) {
82 secure_mem_initialized = 1;
83 } else {
84 CRYPTO_THREAD_lock_free(sec_malloc_lock);
85 sec_malloc_lock = NULL;
86 }
Rich Salz74924dc2015-04-24 16:39:40 -040087 }
Matt Caswell9471f772016-03-08 15:44:05 +000088
Rich Salz74924dc2015-04-24 16:39:40 -040089 return ret;
90#else
91 return 0;
92#endif /* IMPLEMENTED */
93}
94
Kurt Roeckx3cb7c5c2018-05-09 17:09:50 +020095int CRYPTO_secure_malloc_done(void)
Rich Salz74924dc2015-04-24 16:39:40 -040096{
97#ifdef IMPLEMENTED
Todd Shorte8408682016-04-11 16:03:42 -040098 if (secure_mem_used == 0) {
99 sh_done();
100 secure_mem_initialized = 0;
101 CRYPTO_THREAD_lock_free(sec_malloc_lock);
Todd Short7031dda2017-05-11 15:48:10 -0400102 sec_malloc_lock = NULL;
Todd Shorte8408682016-04-11 16:03:42 -0400103 return 1;
104 }
Rich Salz74924dc2015-04-24 16:39:40 -0400105#endif /* IMPLEMENTED */
Todd Shorte8408682016-04-11 16:03:42 -0400106 return 0;
Rich Salz74924dc2015-04-24 16:39:40 -0400107}
108
Kurt Roeckx3cb7c5c2018-05-09 17:09:50 +0200109int CRYPTO_secure_malloc_initialized(void)
Rich Salz74924dc2015-04-24 16:39:40 -0400110{
111#ifdef IMPLEMENTED
112 return secure_mem_initialized;
113#else
114 return 0;
115#endif /* IMPLEMENTED */
116}
117
Richard Levitteff842852015-12-17 08:24:26 +0100118void *CRYPTO_secure_malloc(size_t num, const char *file, int line)
Rich Salz74924dc2015-04-24 16:39:40 -0400119{
120#ifdef IMPLEMENTED
121 void *ret;
122 size_t actual_size;
123
124 if (!secure_mem_initialized) {
Rich Salz74924dc2015-04-24 16:39:40 -0400125 return CRYPTO_malloc(num, file, line);
126 }
Matt Caswell9471f772016-03-08 15:44:05 +0000127 CRYPTO_THREAD_write_lock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400128 ret = sh_malloc(num);
129 actual_size = ret ? sh_actual_size(ret) : 0;
130 secure_mem_used += actual_size;
Matt Caswell9471f772016-03-08 15:44:05 +0000131 CRYPTO_THREAD_unlock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400132 return ret;
133#else
134 return CRYPTO_malloc(num, file, line);
135#endif /* IMPLEMENTED */
136}
137
Rich Salz3538c7d2016-01-27 23:16:47 -0500138void *CRYPTO_secure_zalloc(size_t num, const char *file, int line)
139{
140 void *ret = CRYPTO_secure_malloc(num, file, line);
141
142 if (ret != NULL)
143 memset(ret, 0, num);
144 return ret;
145}
146
Richard Levitte05c7b162016-02-17 02:24:25 +0100147void CRYPTO_secure_free(void *ptr, const char *file, int line)
Rich Salz74924dc2015-04-24 16:39:40 -0400148{
149#ifdef IMPLEMENTED
150 size_t actual_size;
151
152 if (ptr == NULL)
153 return;
Todd Shorte8408682016-04-11 16:03:42 -0400154 if (!CRYPTO_secure_allocated(ptr)) {
Richard Levitte05c7b162016-02-17 02:24:25 +0100155 CRYPTO_free(ptr, file, line);
Rich Salz74924dc2015-04-24 16:39:40 -0400156 return;
157 }
Matt Caswell9471f772016-03-08 15:44:05 +0000158 CRYPTO_THREAD_write_lock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400159 actual_size = sh_actual_size(ptr);
160 CLEAR(ptr, actual_size);
161 secure_mem_used -= actual_size;
162 sh_free(ptr);
Matt Caswell9471f772016-03-08 15:44:05 +0000163 CRYPTO_THREAD_unlock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400164#else
David Woodhouse6a78ae22016-02-17 13:41:26 +0000165 CRYPTO_free(ptr, file, line);
Rich Salz74924dc2015-04-24 16:39:40 -0400166#endif /* IMPLEMENTED */
167}
168
Bernd Edlinger4dae7cd2017-07-28 21:24:02 +0200169void CRYPTO_secure_clear_free(void *ptr, size_t num,
170 const char *file, int line)
171{
172#ifdef IMPLEMENTED
173 size_t actual_size;
174
175 if (ptr == NULL)
176 return;
177 if (!CRYPTO_secure_allocated(ptr)) {
178 OPENSSL_cleanse(ptr, num);
179 CRYPTO_free(ptr, file, line);
180 return;
181 }
182 CRYPTO_THREAD_write_lock(sec_malloc_lock);
183 actual_size = sh_actual_size(ptr);
184 CLEAR(ptr, actual_size);
185 secure_mem_used -= actual_size;
186 sh_free(ptr);
187 CRYPTO_THREAD_unlock(sec_malloc_lock);
188#else
189 if (ptr == NULL)
190 return;
191 OPENSSL_cleanse(ptr, num);
192 CRYPTO_free(ptr, file, line);
193#endif /* IMPLEMENTED */
194}
195
Rich Salz74924dc2015-04-24 16:39:40 -0400196int CRYPTO_secure_allocated(const void *ptr)
197{
198#ifdef IMPLEMENTED
199 int ret;
200
201 if (!secure_mem_initialized)
202 return 0;
Matt Caswell9471f772016-03-08 15:44:05 +0000203 CRYPTO_THREAD_write_lock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400204 ret = sh_allocated(ptr);
Matt Caswell9471f772016-03-08 15:44:05 +0000205 CRYPTO_THREAD_unlock(sec_malloc_lock);
Rich Salz74924dc2015-04-24 16:39:40 -0400206 return ret;
207#else
208 return 0;
209#endif /* IMPLEMENTED */
210}
211
Kurt Roeckx3cb7c5c2018-05-09 17:09:50 +0200212size_t CRYPTO_secure_used(void)
Rich Salzbbd86bf2016-01-07 15:06:38 -0500213{
214#ifdef IMPLEMENTED
215 return secure_mem_used;
216#else
217 return 0;
218#endif /* IMPLEMENTED */
219}
220
Rich Salzd5941992016-01-07 16:05:45 -0500221size_t CRYPTO_secure_actual_size(void *ptr)
222{
223#ifdef IMPLEMENTED
224 size_t actual_size;
225
Matt Caswell9471f772016-03-08 15:44:05 +0000226 CRYPTO_THREAD_write_lock(sec_malloc_lock);
Rich Salzd5941992016-01-07 16:05:45 -0500227 actual_size = sh_actual_size(ptr);
Matt Caswell9471f772016-03-08 15:44:05 +0000228 CRYPTO_THREAD_unlock(sec_malloc_lock);
Rich Salzd5941992016-01-07 16:05:45 -0500229 return actual_size;
230#else
231 return 0;
232#endif
233}
Rich Salz74924dc2015-04-24 16:39:40 -0400234/* END OF PAGE ...
235
236 ... START OF PAGE */
237
238/*
239 * SECURE HEAP IMPLEMENTATION
240 */
241#ifdef IMPLEMENTED
242
243
244/*
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.
250 *
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.
254 *
255 * This code assumes eight-bit bytes. The numbers 3 and 7 are all over the
256 * place.
257 */
258
Todd Shorte8408682016-04-11 16:03:42 -0400259#define ONE ((size_t)1)
260
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))))
Rich Salz74924dc2015-04-24 16:39:40 -0400264
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])
269
270
271typedef struct sh_list_st
272{
273 struct sh_list_st *next;
274 struct sh_list_st **p_next;
275} SH_LIST;
276
277typedef struct sh_st
278{
279 char* map_result;
280 size_t map_size;
281 char *arena;
Todd Shorte8408682016-04-11 16:03:42 -0400282 size_t arena_size;
Rich Salz74924dc2015-04-24 16:39:40 -0400283 char **freelist;
Todd Shorte8408682016-04-11 16:03:42 -0400284 ossl_ssize_t freelist_size;
285 size_t minsize;
Rich Salz74924dc2015-04-24 16:39:40 -0400286 unsigned char *bittable;
287 unsigned char *bitmalloc;
Todd Shorte8408682016-04-11 16:03:42 -0400288 size_t bittable_size; /* size in bits */
Rich Salz74924dc2015-04-24 16:39:40 -0400289} SH;
290
291static SH sh;
292
Todd Shorte8408682016-04-11 16:03:42 -0400293static size_t sh_getlist(char *ptr)
Rich Salz74924dc2015-04-24 16:39:40 -0400294{
Todd Shorte8408682016-04-11 16:03:42 -0400295 ossl_ssize_t list = sh.freelist_size - 1;
296 size_t bit = (sh.arena_size + ptr - sh.arena) / sh.minsize;
Rich Salz74924dc2015-04-24 16:39:40 -0400297
298 for (; bit; bit >>= 1, list--) {
299 if (TESTBIT(sh.bittable, bit))
300 break;
301 OPENSSL_assert((bit & 1) == 0);
302 }
303
304 return list;
305}
306
307
308static int sh_testbit(char *ptr, int list, unsigned char *table)
309{
Todd Shorte8408682016-04-11 16:03:42 -0400310 size_t bit;
Rich Salz74924dc2015-04-24 16:39:40 -0400311
312 OPENSSL_assert(list >= 0 && list < sh.freelist_size);
313 OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
Todd Shorte8408682016-04-11 16:03:42 -0400314 bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
Rich Salz74924dc2015-04-24 16:39:40 -0400315 OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
316 return TESTBIT(table, bit);
317}
318
319static void sh_clearbit(char *ptr, int list, unsigned char *table)
320{
Todd Shorte8408682016-04-11 16:03:42 -0400321 size_t bit;
Rich Salz74924dc2015-04-24 16:39:40 -0400322
323 OPENSSL_assert(list >= 0 && list < sh.freelist_size);
324 OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
Todd Shorte8408682016-04-11 16:03:42 -0400325 bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
Rich Salz74924dc2015-04-24 16:39:40 -0400326 OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
327 OPENSSL_assert(TESTBIT(table, bit));
328 CLEARBIT(table, bit);
329}
330
331static void sh_setbit(char *ptr, int list, unsigned char *table)
332{
Todd Shorte8408682016-04-11 16:03:42 -0400333 size_t bit;
Rich Salz74924dc2015-04-24 16:39:40 -0400334
335 OPENSSL_assert(list >= 0 && list < sh.freelist_size);
336 OPENSSL_assert(((ptr - sh.arena) & ((sh.arena_size >> list) - 1)) == 0);
Todd Shorte8408682016-04-11 16:03:42 -0400337 bit = (ONE << list) + ((ptr - sh.arena) / (sh.arena_size >> list));
Rich Salz74924dc2015-04-24 16:39:40 -0400338 OPENSSL_assert(bit > 0 && bit < sh.bittable_size);
339 OPENSSL_assert(!TESTBIT(table, bit));
340 SETBIT(table, bit);
341}
342
343static void sh_add_to_list(char **list, char *ptr)
344{
345 SH_LIST *temp;
346
347 OPENSSL_assert(WITHIN_FREELIST(list));
348 OPENSSL_assert(WITHIN_ARENA(ptr));
349
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;
354
355 if (temp->next != NULL) {
356 OPENSSL_assert((char **)temp->next->p_next == list);
357 temp->next->p_next = &(temp->next);
358 }
359
360 *list = ptr;
361}
362
Rich Salza773b522016-02-13 22:33:56 -0500363static void sh_remove_from_list(char *ptr)
Rich Salz74924dc2015-04-24 16:39:40 -0400364{
365 SH_LIST *temp, *temp2;
366
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)
372 return;
373
374 temp2 = temp->next;
375 OPENSSL_assert(WITHIN_FREELIST(temp2->p_next) || WITHIN_ARENA(temp2->p_next));
376}
377
378
379static int sh_init(size_t size, int minsize)
380{
Todd Short7031dda2017-05-11 15:48:10 -0400381 int ret;
382 size_t i;
Rich Salz74924dc2015-04-24 16:39:40 -0400383 size_t pgsize;
384 size_t aligned;
385
Rich Salzcbe29642017-12-07 13:39:34 -0500386 memset(&sh, 0, sizeof(sh));
Rich Salz74924dc2015-04-24 16:39:40 -0400387
388 /* make sure size and minsize are powers of 2 */
389 OPENSSL_assert(size > 0);
390 OPENSSL_assert((size & (size - 1)) == 0);
391 OPENSSL_assert(minsize > 0);
392 OPENSSL_assert((minsize & (minsize - 1)) == 0);
393 if (size <= 0 || (size & (size - 1)) != 0)
394 goto err;
395 if (minsize <= 0 || (minsize & (minsize - 1)) != 0)
396 goto err;
397
Pauli70e14ff2017-02-17 10:39:20 +1000398 while (minsize < (int)sizeof(SH_LIST))
399 minsize *= 2;
400
Rich Salz74924dc2015-04-24 16:39:40 -0400401 sh.arena_size = size;
402 sh.minsize = minsize;
403 sh.bittable_size = (sh.arena_size / sh.minsize) * 2;
404
Guido Vranken7f071492017-02-13 01:36:43 +0100405 /* Prevent allocations of size 0 later on */
406 if (sh.bittable_size >> 3 == 0)
407 goto err;
408
Rich Salz74924dc2015-04-24 16:39:40 -0400409 sh.freelist_size = -1;
410 for (i = sh.bittable_size; i; i >>= 1)
411 sh.freelist_size++;
412
Rich Salzcbe29642017-12-07 13:39:34 -0500413 sh.freelist = OPENSSL_zalloc(sh.freelist_size * sizeof(char *));
Rich Salz74924dc2015-04-24 16:39:40 -0400414 OPENSSL_assert(sh.freelist != NULL);
415 if (sh.freelist == NULL)
416 goto err;
Rich Salz74924dc2015-04-24 16:39:40 -0400417
Rich Salzb51bce92015-08-25 13:25:58 -0400418 sh.bittable = OPENSSL_zalloc(sh.bittable_size >> 3);
Rich Salz74924dc2015-04-24 16:39:40 -0400419 OPENSSL_assert(sh.bittable != NULL);
420 if (sh.bittable == NULL)
421 goto err;
Rich Salz74924dc2015-04-24 16:39:40 -0400422
Rich Salzb51bce92015-08-25 13:25:58 -0400423 sh.bitmalloc = OPENSSL_zalloc(sh.bittable_size >> 3);
Rich Salz74924dc2015-04-24 16:39:40 -0400424 OPENSSL_assert(sh.bitmalloc != NULL);
425 if (sh.bitmalloc == NULL)
426 goto err;
Rich Salz74924dc2015-04-24 16:39:40 -0400427
428 /* Allocate space for heap, and two extra pages as guards */
Matt Caswell9ae720b2015-11-12 15:11:34 +0000429#if defined(_SC_PAGE_SIZE) || defined (_SC_PAGESIZE)
430 {
431# if defined(_SC_PAGE_SIZE)
432 long tmppgsize = sysconf(_SC_PAGE_SIZE);
433# else
434 long tmppgsize = sysconf(_SC_PAGESIZE);
435# endif
436 if (tmppgsize < 1)
437 pgsize = PAGE_SIZE;
438 else
439 pgsize = (size_t)tmppgsize;
440 }
Rich Salz74924dc2015-04-24 16:39:40 -0400441#else
442 pgsize = PAGE_SIZE;
443#endif
444 sh.map_size = pgsize + sh.arena_size + pgsize;
Andy Polyakov27186da2015-11-13 21:30:44 +0100445 if (1) {
446#ifdef MAP_ANON
447 sh.map_result = mmap(NULL, sh.map_size,
448 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
449 } else {
450#endif
451 int fd;
452
453 sh.map_result = MAP_FAILED;
454 if ((fd = open("/dev/zero", O_RDWR)) >= 0) {
455 sh.map_result = mmap(NULL, sh.map_size,
456 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
457 close(fd);
458 }
459 }
Rich Salz74924dc2015-04-24 16:39:40 -0400460 if (sh.map_result == MAP_FAILED)
461 goto err;
462 sh.arena = (char *)(sh.map_result + pgsize);
463 sh_setbit(sh.arena, 0, sh.bittable);
464 sh_add_to_list(&sh.freelist[0], sh.arena);
465
466 /* Now try to add guard pages and lock into memory. */
467 ret = 1;
468
469 /* Starting guard is already aligned from mmap. */
470 if (mprotect(sh.map_result, pgsize, PROT_NONE) < 0)
471 ret = 2;
472
473 /* Ending guard page - need to round up to page boundary */
474 aligned = (pgsize + sh.arena_size + (pgsize - 1)) & ~(pgsize - 1);
475 if (mprotect(sh.map_result + aligned, pgsize, PROT_NONE) < 0)
476 ret = 2;
477
Todd Short9dfc5b92017-03-23 12:56:22 -0400478#if defined(OPENSSL_SYS_LINUX) && defined(MLOCK_ONFAULT) && defined(SYS_mlock2)
479 if (syscall(SYS_mlock2, sh.arena, sh.arena_size, MLOCK_ONFAULT) < 0) {
480 if (errno == ENOSYS) {
481 if (mlock(sh.arena, sh.arena_size) < 0)
482 ret = 2;
483 } else {
484 ret = 2;
485 }
486 }
487#else
Rich Salz74924dc2015-04-24 16:39:40 -0400488 if (mlock(sh.arena, sh.arena_size) < 0)
489 ret = 2;
Todd Short9dfc5b92017-03-23 12:56:22 -0400490#endif
Rich Salz74924dc2015-04-24 16:39:40 -0400491#ifdef MADV_DONTDUMP
492 if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0)
493 ret = 2;
494#endif
495
496 return ret;
497
498 err:
499 sh_done();
500 return 0;
501}
502
Kurt Roeckx3cb7c5c2018-05-09 17:09:50 +0200503static void sh_done(void)
Rich Salz74924dc2015-04-24 16:39:40 -0400504{
505 OPENSSL_free(sh.freelist);
506 OPENSSL_free(sh.bittable);
507 OPENSSL_free(sh.bitmalloc);
508 if (sh.map_result != NULL && sh.map_size)
509 munmap(sh.map_result, sh.map_size);
Rich Salzcbe29642017-12-07 13:39:34 -0500510 memset(&sh, 0, sizeof(sh));
Rich Salz74924dc2015-04-24 16:39:40 -0400511}
512
513static int sh_allocated(const char *ptr)
514{
515 return WITHIN_ARENA(ptr) ? 1 : 0;
516}
517
518static char *sh_find_my_buddy(char *ptr, int list)
519{
Todd Shorte8408682016-04-11 16:03:42 -0400520 size_t bit;
Rich Salz74924dc2015-04-24 16:39:40 -0400521 char *chunk = NULL;
522
Todd Shorte8408682016-04-11 16:03:42 -0400523 bit = (ONE << list) + (ptr - sh.arena) / (sh.arena_size >> list);
Rich Salz74924dc2015-04-24 16:39:40 -0400524 bit ^= 1;
525
526 if (TESTBIT(sh.bittable, bit) && !TESTBIT(sh.bitmalloc, bit))
Todd Shorte8408682016-04-11 16:03:42 -0400527 chunk = sh.arena + ((bit & ((ONE << list) - 1)) * (sh.arena_size >> list));
Rich Salz74924dc2015-04-24 16:39:40 -0400528
529 return chunk;
530}
531
Rich Salz332dc4f2017-03-02 19:16:57 -0500532static void *sh_malloc(size_t size)
Rich Salz74924dc2015-04-24 16:39:40 -0400533{
Todd Shorte8408682016-04-11 16:03:42 -0400534 ossl_ssize_t list, slist;
Rich Salz74924dc2015-04-24 16:39:40 -0400535 size_t i;
536 char *chunk;
537
Todd Short7031dda2017-05-11 15:48:10 -0400538 if (size > sh.arena_size)
539 return NULL;
540
Rich Salz74924dc2015-04-24 16:39:40 -0400541 list = sh.freelist_size - 1;
542 for (i = sh.minsize; i < size; i <<= 1)
543 list--;
544 if (list < 0)
545 return NULL;
546
547 /* try to find a larger entry to split */
548 for (slist = list; slist >= 0; slist--)
549 if (sh.freelist[slist] != NULL)
550 break;
551 if (slist < 0)
552 return NULL;
553
554 /* split larger entry */
555 while (slist != list) {
556 char *temp = sh.freelist[slist];
557
558 /* remove from bigger list */
559 OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
560 sh_clearbit(temp, slist, sh.bittable);
Rich Salza773b522016-02-13 22:33:56 -0500561 sh_remove_from_list(temp);
Rich Salz74924dc2015-04-24 16:39:40 -0400562 OPENSSL_assert(temp != sh.freelist[slist]);
563
564 /* done with bigger list */
565 slist++;
566
567 /* add to smaller list */
568 OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
569 sh_setbit(temp, slist, sh.bittable);
570 sh_add_to_list(&sh.freelist[slist], temp);
571 OPENSSL_assert(sh.freelist[slist] == temp);
572
573 /* split in 2 */
574 temp += sh.arena_size >> slist;
575 OPENSSL_assert(!sh_testbit(temp, slist, sh.bitmalloc));
576 sh_setbit(temp, slist, sh.bittable);
577 sh_add_to_list(&sh.freelist[slist], temp);
578 OPENSSL_assert(sh.freelist[slist] == temp);
579
580 OPENSSL_assert(temp-(sh.arena_size >> slist) == sh_find_my_buddy(temp, slist));
581 }
582
583 /* peel off memory to hand back */
584 chunk = sh.freelist[list];
585 OPENSSL_assert(sh_testbit(chunk, list, sh.bittable));
586 sh_setbit(chunk, list, sh.bitmalloc);
Rich Salza773b522016-02-13 22:33:56 -0500587 sh_remove_from_list(chunk);
Rich Salz74924dc2015-04-24 16:39:40 -0400588
589 OPENSSL_assert(WITHIN_ARENA(chunk));
590
591 return chunk;
592}
593
Rich Salz332dc4f2017-03-02 19:16:57 -0500594static void sh_free(void *ptr)
Rich Salz74924dc2015-04-24 16:39:40 -0400595{
Todd Shorte8408682016-04-11 16:03:42 -0400596 size_t list;
Rich Salz332dc4f2017-03-02 19:16:57 -0500597 void *buddy;
Rich Salz74924dc2015-04-24 16:39:40 -0400598
599 if (ptr == NULL)
600 return;
601 OPENSSL_assert(WITHIN_ARENA(ptr));
602 if (!WITHIN_ARENA(ptr))
603 return;
604
605 list = sh_getlist(ptr);
606 OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
607 sh_clearbit(ptr, list, sh.bitmalloc);
608 sh_add_to_list(&sh.freelist[list], ptr);
609
610 /* Try to coalesce two adjacent free areas. */
611 while ((buddy = sh_find_my_buddy(ptr, list)) != NULL) {
612 OPENSSL_assert(ptr == sh_find_my_buddy(buddy, list));
613 OPENSSL_assert(ptr != NULL);
614 OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
615 sh_clearbit(ptr, list, sh.bittable);
Rich Salza773b522016-02-13 22:33:56 -0500616 sh_remove_from_list(ptr);
Rich Salz74924dc2015-04-24 16:39:40 -0400617 OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
618 sh_clearbit(buddy, list, sh.bittable);
Rich Salza773b522016-02-13 22:33:56 -0500619 sh_remove_from_list(buddy);
Rich Salz74924dc2015-04-24 16:39:40 -0400620
621 list--;
622
623 if (ptr > buddy)
624 ptr = buddy;
625
626 OPENSSL_assert(!sh_testbit(ptr, list, sh.bitmalloc));
627 sh_setbit(ptr, list, sh.bittable);
628 sh_add_to_list(&sh.freelist[list], ptr);
629 OPENSSL_assert(sh.freelist[list] == ptr);
630 }
631}
632
Todd Shorte8408682016-04-11 16:03:42 -0400633static size_t sh_actual_size(char *ptr)
Rich Salz74924dc2015-04-24 16:39:40 -0400634{
635 int list;
636
637 OPENSSL_assert(WITHIN_ARENA(ptr));
638 if (!WITHIN_ARENA(ptr))
639 return 0;
640 list = sh_getlist(ptr);
641 OPENSSL_assert(sh_testbit(ptr, list, sh.bittable));
Todd Shorte8408682016-04-11 16:03:42 -0400642 return sh.arena_size / (ONE << list);
Rich Salz74924dc2015-04-24 16:39:40 -0400643}
644#endif /* IMPLEMENTED */