1
mirror of https://github.com/jedisct1/libsodium.git synced 2024-12-19 18:15:18 -07:00

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.
This commit is contained in:
Frank Denis 2019-06-22 14:56:16 +02:00
parent 60f4bc8212
commit bfeca0eb73
3 changed files with 67 additions and 4 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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;