X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fmem_sec.c;h=d29f261ec4728303933ca1610b3f56dd306f92fe;hp=6aca27370ea35ea2ede5baa0db7593d61967b56f;hb=HEAD;hpb=34b167625af50a13b8414e11814a795457cb17b0 diff --git a/crypto/mem_sec.c b/crypto/mem_sec.c index 6aca27370e..269c7dcb6d 100644 --- a/crypto/mem_sec.c +++ b/crypto/mem_sec.c @@ -1,5 +1,5 @@ /* - * Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved. * Copyright 2004-2014, Akamai Technologies. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -15,18 +15,46 @@ * For details on that implementation, see below (look for uppercase * "SECURE HEAP IMPLEMENTATION"). */ -#include "e_os.h" +#include "internal/e_os.h" #include +#include #include -/* e_os.h defines OPENSSL_SECURE_MEMORY if secure memory can be implemented */ -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY +# if defined(_WIN32) +# include +# if defined(WINAPI_FAMILY_PARTITION) +# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) +/* + * While VirtualLock is available under the app partition (e.g. UWP), + * the headers do not define the API. Define it ourselves instead. + */ +WINBASEAPI +BOOL +WINAPI +VirtualLock( + _In_ LPVOID lpAddress, + _In_ SIZE_T dwSize + ); +# endif +# endif +# endif # include # include -# include +# if defined(OPENSSL_SYS_UNIX) +# include +# endif # include -# include +# if defined(OPENSSL_SYS_UNIX) +# include +# if defined(__FreeBSD__) +# define MADV_DONTDUMP MADV_NOCORE +# endif +# if !defined(MAP_CONCEAL) +# define MAP_CONCEAL 0 +# endif +# endif # if defined(OPENSSL_SYS_LINUX) # include # if defined(SYS_mlock2) @@ -38,6 +66,18 @@ # include # include #endif +#ifndef HAVE_MADVISE +# if defined(MADV_DONTDUMP) +# define HAVE_MADVISE 1 +# else +# define HAVE_MADVISE 0 +# endif +#endif +#if HAVE_MADVISE +# undef NO_MADVISE +#else +# define NO_MADVISE +#endif #define CLEAR(p, s) OPENSSL_cleanse(p, s) #ifndef PAGE_SIZE @@ -47,7 +87,7 @@ # define MAP_ANON MAP_ANONYMOUS #endif -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY static size_t secure_mem_used; static int secure_mem_initialized; @@ -67,7 +107,7 @@ static int sh_allocated(const char *ptr); int CRYPTO_secure_malloc_init(size_t size, size_t minsize) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY int ret = 0; if (!secure_mem_initialized) { @@ -85,12 +125,12 @@ int CRYPTO_secure_malloc_init(size_t size, size_t minsize) return ret; #else return 0; -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } int CRYPTO_secure_malloc_done(void) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY if (secure_mem_used == 0) { sh_done(); secure_mem_initialized = 0; @@ -98,42 +138,52 @@ int CRYPTO_secure_malloc_done(void) sec_malloc_lock = NULL; return 1; } -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ return 0; } int CRYPTO_secure_malloc_initialized(void) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY return secure_mem_initialized; #else return 0; -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } void *CRYPTO_secure_malloc(size_t num, const char *file, int line) { -#ifdef OPENSSL_SECURE_MEMORY - void *ret; +#ifndef OPENSSL_NO_SECURE_MEMORY + void *ret = NULL; size_t actual_size; + int reason = CRYPTO_R_SECURE_MALLOC_FAILURE; if (!secure_mem_initialized) { return CRYPTO_malloc(num, file, line); } - CRYPTO_THREAD_write_lock(sec_malloc_lock); + if (!CRYPTO_THREAD_write_lock(sec_malloc_lock)) { + reason = ERR_R_CRYPTO_LIB; + goto err; + } ret = sh_malloc(num); actual_size = ret ? sh_actual_size(ret) : 0; secure_mem_used += actual_size; CRYPTO_THREAD_unlock(sec_malloc_lock); + err: + if (ret == NULL && (file != NULL || line != 0)) { + ERR_new(); + ERR_set_debug(file, line, NULL); + ERR_set_error(ERR_LIB_CRYPTO, reason, NULL); + } return ret; #else return CRYPTO_malloc(num, file, line); -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } void *CRYPTO_secure_zalloc(size_t num, const char *file, int line) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY if (secure_mem_initialized) /* CRYPTO_secure_malloc() zeroes allocations when it is implemented */ return CRYPTO_secure_malloc(num, file, line); @@ -143,7 +193,7 @@ void *CRYPTO_secure_zalloc(size_t num, const char *file, int line) void CRYPTO_secure_free(void *ptr, const char *file, int line) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY size_t actual_size; if (ptr == NULL) @@ -152,7 +202,8 @@ void CRYPTO_secure_free(void *ptr, const char *file, int line) CRYPTO_free(ptr, file, line); return; } - CRYPTO_THREAD_write_lock(sec_malloc_lock); + if (!CRYPTO_THREAD_write_lock(sec_malloc_lock)) + return; actual_size = sh_actual_size(ptr); CLEAR(ptr, actual_size); secure_mem_used -= actual_size; @@ -160,13 +211,13 @@ void CRYPTO_secure_free(void *ptr, const char *file, int line) CRYPTO_THREAD_unlock(sec_malloc_lock); #else CRYPTO_free(ptr, file, line); -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } void CRYPTO_secure_clear_free(void *ptr, size_t num, const char *file, int line) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY size_t actual_size; if (ptr == NULL) @@ -176,7 +227,8 @@ void CRYPTO_secure_clear_free(void *ptr, size_t num, CRYPTO_free(ptr, file, line); return; } - CRYPTO_THREAD_write_lock(sec_malloc_lock); + if (!CRYPTO_THREAD_write_lock(sec_malloc_lock)) + return; actual_size = sh_actual_size(ptr); CLEAR(ptr, actual_size); secure_mem_used -= actual_size; @@ -187,40 +239,47 @@ void CRYPTO_secure_clear_free(void *ptr, size_t num, return; OPENSSL_cleanse(ptr, num); CRYPTO_free(ptr, file, line); -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } int CRYPTO_secure_allocated(const void *ptr) { -#ifdef OPENSSL_SECURE_MEMORY - int ret; - +#ifndef OPENSSL_NO_SECURE_MEMORY if (!secure_mem_initialized) return 0; - CRYPTO_THREAD_write_lock(sec_malloc_lock); - ret = sh_allocated(ptr); - CRYPTO_THREAD_unlock(sec_malloc_lock); - return ret; + /* + * Only read accesses to the arena take place in sh_allocated() and this + * is only changed by the sh_init() and sh_done() calls which are not + * locked. Hence, it is safe to make this check without a lock too. + */ + return sh_allocated(ptr); #else return 0; -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */ } size_t CRYPTO_secure_used(void) { -#ifdef OPENSSL_SECURE_MEMORY - return secure_mem_used; -#else - return 0; -#endif /* OPENSSL_SECURE_MEMORY */ + size_t ret = 0; + +#ifndef OPENSSL_NO_SECURE_MEMORY + if (!CRYPTO_THREAD_read_lock(sec_malloc_lock)) + return 0; + + ret = secure_mem_used; + + CRYPTO_THREAD_unlock(sec_malloc_lock); +#endif /* OPENSSL_NO_SECURE_MEMORY */ + return ret; } size_t CRYPTO_secure_actual_size(void *ptr) { -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY size_t actual_size; - CRYPTO_THREAD_write_lock(sec_malloc_lock); + if (!CRYPTO_THREAD_write_lock(sec_malloc_lock)) + return 0; actual_size = sh_actual_size(ptr); CRYPTO_THREAD_unlock(sec_malloc_lock); return actual_size; @@ -228,14 +287,11 @@ size_t CRYPTO_secure_actual_size(void *ptr) return 0; #endif } -/* END OF PAGE ... - - ... START OF PAGE */ /* * SECURE HEAP IMPLEMENTATION */ -#ifdef OPENSSL_SECURE_MEMORY +#ifndef OPENSSL_NO_SECURE_MEMORY /* @@ -379,20 +435,40 @@ static int sh_init(size_t size, size_t minsize) size_t i; size_t pgsize; size_t aligned; +#if defined(_WIN32) + DWORD flOldProtect; + SYSTEM_INFO systemInfo; +#endif memset(&sh, 0, sizeof(sh)); - /* make sure size and minsize are powers of 2 */ + /* make sure size is a powers of 2 */ OPENSSL_assert(size > 0); OPENSSL_assert((size & (size - 1)) == 0); - OPENSSL_assert((minsize & (minsize - 1)) == 0); - if (size <= 0 || (size & (size - 1)) != 0) - goto err; - if (minsize == 0 || (minsize & (minsize - 1)) != 0) + if (size == 0 || (size & (size - 1)) != 0) goto err; - while (minsize < (int)sizeof(SH_LIST)) - minsize *= 2; + if (minsize <= sizeof(SH_LIST)) { + OPENSSL_assert(sizeof(SH_LIST) <= 65536); + /* + * Compute the minimum possible allocation size. + * This must be a power of 2 and at least as large as the SH_LIST + * structure. + */ + minsize = sizeof(SH_LIST) - 1; + minsize |= minsize >> 1; + minsize |= minsize >> 2; + if (sizeof(SH_LIST) > 16) + minsize |= minsize >> 4; + if (sizeof(SH_LIST) > 256) + minsize |= minsize >> 8; + minsize++; + } else { + /* make sure minsize is a powers of 2 */ + OPENSSL_assert((minsize & (minsize - 1)) == 0); + if ((minsize & (minsize - 1)) != 0) + goto err; + } sh.arena_size = size; sh.minsize = minsize; @@ -434,16 +510,20 @@ static int sh_init(size_t size, size_t minsize) else pgsize = (size_t)tmppgsize; } +#elif defined(_WIN32) + GetSystemInfo(&systemInfo); + pgsize = (size_t)systemInfo.dwPageSize; #else pgsize = PAGE_SIZE; #endif sh.map_size = pgsize + sh.arena_size + pgsize; - if (1) { -#ifdef MAP_ANON - sh.map_result = mmap(NULL, sh.map_size, - PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); - } else { -#endif + +#if !defined(_WIN32) +# ifdef MAP_ANON + sh.map_result = mmap(NULL, sh.map_size, + PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_CONCEAL, -1, 0); +# else + { int fd; sh.map_result = MAP_FAILED; @@ -453,8 +533,16 @@ static int sh_init(size_t size, size_t minsize) close(fd); } } +# endif if (sh.map_result == MAP_FAILED) goto err; +#else + sh.map_result = VirtualAlloc(NULL, sh.map_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + if (sh.map_result == NULL) + goto err; +#endif + sh.arena = (char *)(sh.map_result + pgsize); sh_setbit(sh.arena, 0, sh.bittable); sh_add_to_list(&sh.freelist[0], sh.arena); @@ -462,14 +550,24 @@ static int sh_init(size_t size, size_t minsize) /* Now try to add guard pages and lock into memory. */ ret = 1; +#if !defined(_WIN32) /* Starting guard is already aligned from mmap. */ if (mprotect(sh.map_result, pgsize, PROT_NONE) < 0) ret = 2; +#else + if (VirtualProtect(sh.map_result, pgsize, PAGE_NOACCESS, &flOldProtect) == FALSE) + ret = 2; +#endif /* Ending guard page - need to round up to page boundary */ aligned = (pgsize + sh.arena_size + (pgsize - 1)) & ~(pgsize - 1); +#if !defined(_WIN32) if (mprotect(sh.map_result + aligned, pgsize, PROT_NONE) < 0) ret = 2; +#else + if (VirtualProtect(sh.map_result + aligned, pgsize, PAGE_NOACCESS, &flOldProtect) == FALSE) + ret = 2; +#endif #if defined(OPENSSL_SYS_LINUX) && defined(MLOCK_ONFAULT) && defined(SYS_mlock2) if (syscall(SYS_mlock2, sh.arena, sh.arena_size, MLOCK_ONFAULT) < 0) { @@ -480,11 +578,14 @@ static int sh_init(size_t size, size_t minsize) ret = 2; } } +#elif defined(_WIN32) + if (VirtualLock(sh.arena, sh.arena_size) == FALSE) + ret = 2; #else if (mlock(sh.arena, sh.arena_size) < 0) ret = 2; #endif -#ifdef MADV_DONTDUMP +#ifndef NO_MADVISE if (madvise(sh.arena, sh.arena_size, MADV_DONTDUMP) < 0) ret = 2; #endif @@ -501,8 +602,13 @@ static void sh_done(void) OPENSSL_free(sh.freelist); OPENSSL_free(sh.bittable); OPENSSL_free(sh.bitmalloc); - if (sh.map_result != NULL && sh.map_size) +#if !defined(_WIN32) + if (sh.map_result != MAP_FAILED && sh.map_size) munmap(sh.map_result, sh.map_size); +#else + if (sh.map_result != NULL && sh.map_size) + VirtualFree(sh.map_result, 0, MEM_RELEASE); +#endif memset(&sh, 0, sizeof(sh)); } @@ -642,4 +748,4 @@ static size_t sh_actual_size(char *ptr) OPENSSL_assert(sh_testbit(ptr, list, sh.bittable)); return sh.arena_size / (ONE << list); } -#endif /* OPENSSL_SECURE_MEMORY */ +#endif /* OPENSSL_NO_SECURE_MEMORY */