From bfeca0eb73c1650fa17a3b0f5e845e95f28516a4 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 22 Jun 2019 14:56:16 +0200 Subject: [PATCH] Implement key shielding to protect against side channels We may want to fold this into `sodium_mprotect_*()` instead of exposing these functions. The drawback is that a transition from PROT_NONE to PROT_READ (or the other way round) would need an intermediary state in PROT_WRITE for shielding/unshielding. Shielding is also not thread-safe, while the `mprotect_*()` functions are, and adding locks would make things more complicated than they probably should. --- src/libsodium/include/sodium/utils.h | 6 ++++ src/libsodium/sodium/utils.c | 44 +++++++++++++++++++++++++++- test/default/sodium_utils2.c | 21 +++++++++++-- 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/libsodium/include/sodium/utils.h b/src/libsodium/include/sodium/utils.h index ac801512..14a00894 100644 --- a/src/libsodium/include/sodium/utils.h +++ b/src/libsodium/include/sodium/utils.h @@ -158,6 +158,12 @@ int sodium_mprotect_readonly(void *ptr) __attribute__ ((nonnull)); SODIUM_EXPORT int sodium_mprotect_readwrite(void *ptr) __attribute__ ((nonnull)); +SODIUM_EXPORT +int sodium_mshield(void *ptr) __attribute__ ((nonnull)); + +SODIUM_EXPORT +int sodium_munshield(void *ptr) __attribute__ ((nonnull)); + SODIUM_EXPORT int sodium_pad(size_t *padded_buflen_p, unsigned char *buf, size_t unpadded_buflen, size_t blocksize, size_t max_buflen) diff --git a/src/libsodium/sodium/utils.c b/src/libsodium/sodium/utils.c index 151dd09c..e1f04a90 100644 --- a/src/libsodium/sodium/utils.c +++ b/src/libsodium/sodium/utils.c @@ -43,7 +43,10 @@ void *alloca (size_t); #endif #include "core.h" +#include "crypto_generichash.h" +#include "crypto_stream.h" #include "randombytes.h" +#include "private/common.h" #include "utils.h" #ifndef ENOSYS @@ -58,6 +61,8 @@ void *alloca (size_t); #define CANARY_SIZE 16U #define GARBAGE_VALUE 0xdb +#define SHIELDING_PREKEY_SIZE 16384U + #ifndef MAP_NOCORE # ifdef MAP_CONCEAL # define MAP_NOCORE MAP_CONCEAL @@ -87,6 +92,7 @@ void *alloca (size_t); static size_t page_size; static unsigned char canary[CANARY_SIZE]; +static unsigned char shielding_prekey[SHIELDING_PREKEY_SIZE]; /* LCOV_EXCL_START */ #ifdef HAVE_WEAK_SYMBOLS @@ -402,7 +408,11 @@ _sodium_alloc_init(void) sodium_misuse(); /* LCOV_EXCL_LINE */ } #endif - randombytes_buf(canary, sizeof canary); + COMPILER_ASSERT(sizeof shielding_prekey >= randombytes_SEEDBYTES); + randombytes_buf(shielding_prekey, randombytes_SEEDBYTES); + randombytes_buf_deterministic(canary, sizeof canary, shielding_prekey); + shielding_prekey[0] ^= 0x01; + randombytes_buf_deterministic(shielding_prekey, sizeof shielding_prekey, shielding_prekey); return 0; } @@ -715,6 +725,38 @@ sodium_mprotect_readwrite(void *ptr) return _sodium_mprotect(ptr, _mprotect_readwrite); } +int +sodium_mshield(void *ptr) +{ + unsigned char shielding_key[crypto_stream_KEYBYTES]; + unsigned char nonce[crypto_stream_NONCEBYTES]; + unsigned char *base_ptr; + unsigned char *unprotected_ptr; + size_t unprotected_size; + + unprotected_ptr = _unprotected_ptr_from_user_ptr(ptr); + base_ptr = unprotected_ptr - page_size * 2U; + memcpy(&unprotected_size, base_ptr, sizeof unprotected_size); + + crypto_generichash(shielding_key, sizeof shielding_key, + shielding_prekey, sizeof shielding_prekey, NULL, 0); + COMPILER_ASSERT(sizeof nonce >= (sizeof unprotected_ptr) + (sizeof unprotected_size)); + memset(nonce, 0, sizeof nonce); + memcpy(nonce, &unprotected_ptr, sizeof unprotected_ptr); + memcpy(nonce + sizeof unprotected_ptr, &unprotected_size, sizeof unprotected_size); + crypto_stream_xor(unprotected_ptr, unprotected_ptr, unprotected_size, nonce, shielding_prekey); + sodium_memzero(shielding_key, sizeof shielding_key); + sodium_memzero(nonce, sizeof nonce); + + return 0; +} + +int +sodium_munshield(void *ptr) +{ + return sodium_mshield(ptr); +} + int sodium_pad(size_t *padded_buflen_p, unsigned char *buf, size_t unpadded_buflen, size_t blocksize, size_t max_buflen) diff --git a/test/default/sodium_utils2.c b/test/default/sodium_utils2.c index a1801b1a..efa2718c 100644 --- a/test/default/sodium_utils2.c +++ b/test/default/sodium_utils2.c @@ -40,9 +40,24 @@ segv_handler(int sig) int main(void) { - void * buf; - size_t size; - unsigned int i; + void *buf; + void *buf2; + size_t size; + unsigned int i; + + size = randombytes_uniform(100U); + if ((buf = sodium_malloc(size)) == NULL || + (buf2 = sodium_malloc(size)) == NULL) { + return 1; + } + randombytes_buf(buf, size); + memcpy(buf2, buf, size); + sodium_mshield(buf); + assert(size == 0U || memcmp(buf, buf2, size) != 0); + sodium_munshield(buf); + assert(size == 0U || memcmp(buf, buf2, size) == 0); + sodium_free(buf2); + sodium_free(buf); if (sodium_malloc(SIZE_MAX - 1U) != NULL) { return 1;