diff --git a/lib/utils.c b/lib/utils.c index e8481703..8fa4242a 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -179,7 +179,7 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile, key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1; unlimited_read = 1; /* use 4k for buffer (page divisor but avoid huge pages) */ - buflen = 4096 - sizeof(size_t); // sizeof(struct safe_allocation); + buflen = 4096 - 16; /* sizeof(struct safe_allocation); */ } else buflen = key_size; diff --git a/lib/utils_safe_memory.c b/lib/utils_safe_memory.c index 56bb7c7a..c46d4764 100644 --- a/lib/utils_safe_memory.c +++ b/lib/utils_safe_memory.c @@ -20,13 +20,17 @@ */ #include +#include #include +#include #include "libcryptsetup.h" struct safe_allocation { - size_t size; - char data[0]; + size_t size; + bool locked; + char data[0] __attribute__((aligned(8))); }; +#define OVERHEAD offsetof(struct safe_allocation, data) /* * Replacement for memset(s, 0, n) on stack that can be optimized out @@ -49,15 +53,19 @@ void *crypt_safe_alloc(size_t size) { struct safe_allocation *alloc; - if (!size || size > (SIZE_MAX - offsetof(struct safe_allocation, data))) + if (!size || size > (SIZE_MAX - OVERHEAD)) return NULL; - alloc = malloc(size + offsetof(struct safe_allocation, data)); + alloc = malloc(size + OVERHEAD); if (!alloc) return NULL; + crypt_safe_memzero(alloc, size + OVERHEAD); alloc->size = size; - crypt_safe_memzero(&alloc->data, size); + + /* Ignore failure if it is over limit. */ + if (!mlock(alloc, size + OVERHEAD)) + alloc->locked = true; /* coverity[leaked_storage] */ return &alloc->data; @@ -72,11 +80,16 @@ void crypt_safe_free(void *data) if (!data) return; - p = (char *)data - offsetof(struct safe_allocation, data); + p = (char *)data - OVERHEAD; alloc = (struct safe_allocation *)p; crypt_safe_memzero(data, alloc->size); + if (alloc->locked) { + munlock(alloc, alloc->size + OVERHEAD); + alloc->locked = false; + } + s = (volatile size_t *)&alloc->size; *s = 0x55aa55aa; free(alloc); @@ -92,7 +105,7 @@ void *crypt_safe_realloc(void *data, size_t size) if (new_data && data) { - p = (char *)data - offsetof(struct safe_allocation, data); + p = (char *)data - OVERHEAD; alloc = (struct safe_allocation *)p; if (size > alloc->size)