aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/mem_sec.c
diff options
context:
space:
mode:
authorTodd Short <tshort@akamai.com>2017-05-11 15:48:10 -0400
committerRichard Levitte <levitte@openssl.org>2017-05-11 22:35:21 +0200
commit7031ddac94d0ae616d1b0670263a9265ce672cd2 (patch)
tree291ee3feddc4a98ea47522b9ae94069821759d42 /crypto/mem_sec.c
parentb57f0c598bde43e147a886c9ffb0d6fdb3141d72 (diff)
downloadopenssl-7031ddac94d0ae616d1b0670263a9265ce672cd2.tar.gz
Fix infinite loops in secure memory allocation.
Issue 1: sh.bittable_size is a size_t but i is and int, which can result in freelist == -1 if sh.bittable_size exceeds an int. This seems to result in an OPENSSL_assert due to invalid allocation size, so maybe that is "ok." Worse, if sh.bittable_size is exactly 1<<31, then this becomes an infinite loop (because 1<<31 is a negative int, so it can be shifted right forever and sticks at -1). Issue 2: CRYPTO_secure_malloc_init() sets secure_mem_initialized=1 even when sh_init() returns 0. If sh_init() fails, we end up with secure_mem_initialized=1 but sh.minsize=0. If you then call secure_malloc(), which then calls, sh_malloc(), this then enters an infite loop since 0 << anything will never be larger than size. Issue 3: That same sh_malloc loop will loop forever for a size greater than size_t/2 because i will proceed (assuming sh.minsize=16): i=16, 32, 64, ..., size_t/8, size_t/4, size_t/2, 0, 0, 0, 0, .... This sequence will never be larger than "size". Reviewed-by: Rich Salz <rsalz@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3449)
Diffstat (limited to 'crypto/mem_sec.c')
-rw-r--r--crypto/mem_sec.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/crypto/mem_sec.c b/crypto/mem_sec.c
index 351dec43bc..774b696057 100644
--- a/crypto/mem_sec.c
+++ b/crypto/mem_sec.c
@@ -73,8 +73,12 @@ int CRYPTO_secure_malloc_init(size_t size, int minsize)
sec_malloc_lock = CRYPTO_THREAD_lock_new();
if (sec_malloc_lock == NULL)
return 0;
- ret = sh_init(size, minsize);
- secure_mem_initialized = 1;
+ if ((ret = sh_init(size, minsize)) != 0) {
+ secure_mem_initialized = 1;
+ } else {
+ CRYPTO_THREAD_lock_free(sec_malloc_lock);
+ sec_malloc_lock = NULL;
+ }
}
return ret;
@@ -90,6 +94,7 @@ int CRYPTO_secure_malloc_done()
sh_done();
secure_mem_initialized = 0;
CRYPTO_THREAD_lock_free(sec_malloc_lock);
+ sec_malloc_lock = NULL;
return 1;
}
#endif /* IMPLEMENTED */
@@ -341,7 +346,8 @@ static void sh_remove_from_list(char *ptr)
static int sh_init(size_t size, int minsize)
{
- int i, ret;
+ int ret;
+ size_t i;
size_t pgsize;
size_t aligned;
@@ -498,6 +504,9 @@ static void *sh_malloc(size_t size)
size_t i;
char *chunk;
+ if (size > sh.arena_size)
+ return NULL;
+
list = sh.freelist_size - 1;
for (i = sh.minsize; i < size; i <<= 1)
list--;