Commit 88b7926f authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-19582 WolfSSL decyption function can read memory out-of-bounds.

MDEV-19581 Valgrind error with WolfSSL and encrypted binlog

WolfSSL can read  memory out of bounds in EVP_CipherUpdate()
in decrypt/NOPAD mode, when the input length is not multiple of AES block
size.

The workaround ensures that input will have some padding at the end
by having slightly larger allocated buffer, or padding the structures
with 16 more bytes.
parent 5d2619b6
...@@ -1847,8 +1847,16 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet, ...@@ -1847,8 +1847,16 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
{ {
uchar iv[BINLOG_IV_LENGTH]; uchar iv[BINLOG_IV_LENGTH];
fdle->crypto_data.set_iv(iv, (uint32) (my_b_tell(file) - data_len)); fdle->crypto_data.set_iv(iv, (uint32) (my_b_tell(file) - data_len));
size_t sz= data_len + ev_offset + 1;
char *newpkt= (char*)my_malloc(data_len + ev_offset + 1, MYF(MY_WME)); #ifdef HAVE_WOLFSSL
/*
Workaround for MDEV-19582.
WolfSSL reads memory out of bounds with decryption/NOPAD)
We allocate a little more memory therefore.
*/
sz += MY_AES_BLOCK_SIZE;
#endif
char *newpkt= (char*)my_malloc(sz, MYF(MY_WME));
if (!newpkt) if (!newpkt)
DBUG_RETURN(LOG_READ_MEM); DBUG_RETURN(LOG_READ_MEM);
memcpy(newpkt, packet->ptr(), ev_offset); memcpy(newpkt, packet->ptr(), ev_offset);
......
...@@ -39,10 +39,15 @@ my_bool srv_encrypt_log; ...@@ -39,10 +39,15 @@ my_bool srv_encrypt_log;
/** Redo log encryption key ID */ /** Redo log encryption key ID */
#define LOG_DEFAULT_ENCRYPTION_KEY 1 #define LOG_DEFAULT_ENCRYPTION_KEY 1
typedef union { struct aes_block_t {
uint32_t words[MY_AES_BLOCK_SIZE / sizeof(uint32_t)];
byte bytes[MY_AES_BLOCK_SIZE]; byte bytes[MY_AES_BLOCK_SIZE];
} aes_block_t; #ifdef HAVE_WOLFSSL
// Workaround for MDEV-19582.
// WolfSSL reads memory out of bounds with decrypt/NOPAD
// Pad the structure to workaround
byte pad[MY_AES_BLOCK_SIZE];
#endif
};
struct crypt_info_t { struct crypt_info_t {
ulint checkpoint_no; /*!< checkpoint no; 32 bits */ ulint checkpoint_no; /*!< checkpoint no; 32 bits */
...@@ -91,7 +96,8 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false) ...@@ -91,7 +96,8 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
byte mysqld_key[MY_AES_MAX_KEY_LENGTH]; byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
uint keylen = sizeof mysqld_key; uint keylen = sizeof mysqld_key;
compile_time_assert(16 == sizeof info->crypt_key); compile_time_assert(16 == sizeof info->crypt_key.bytes);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
if (uint rc = encryption_key_get(LOG_DEFAULT_ENCRYPTION_KEY, if (uint rc = encryption_key_get(LOG_DEFAULT_ENCRYPTION_KEY,
info->key_version, mysqld_key, info->key_version, mysqld_key,
...@@ -113,7 +119,7 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false) ...@@ -113,7 +119,7 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
uint dst_len; uint dst_len;
int err= my_aes_crypt(MY_AES_ECB, int err= my_aes_crypt(MY_AES_ECB,
ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT, ENCRYPTION_FLAG_NOPAD | ENCRYPTION_FLAG_ENCRYPT,
info->crypt_msg.bytes, sizeof info->crypt_msg, info->crypt_msg.bytes, MY_AES_BLOCK_SIZE,
info->crypt_key.bytes, &dst_len, info->crypt_key.bytes, &dst_len,
mysqld_key, keylen, NULL, 0); mysqld_key, keylen, NULL, 0);
...@@ -212,7 +218,7 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op) ...@@ -212,7 +218,7 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op)
buf + LOG_CRYPT_HDR_SIZE, dst_size, buf + LOG_CRYPT_HDR_SIZE, dst_size,
reinterpret_cast<byte*>(dst), &dst_len, reinterpret_cast<byte*>(dst), &dst_len,
const_cast<byte*>(info.crypt_key.bytes), const_cast<byte*>(info.crypt_key.bytes),
sizeof info.crypt_key, MY_AES_BLOCK_SIZE,
reinterpret_cast<byte*>(aes_ctr_iv), sizeof aes_ctr_iv, reinterpret_cast<byte*>(aes_ctr_iv), sizeof aes_ctr_iv,
op == LOG_DECRYPT op == LOG_DECRYPT
? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD ? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD
...@@ -249,7 +255,7 @@ log_crypt_init() ...@@ -249,7 +255,7 @@ log_crypt_init()
return false; return false;
} }
if (my_random_bytes(info.crypt_msg.bytes, sizeof info.crypt_msg) if (my_random_bytes(info.crypt_msg.bytes, MY_AES_BLOCK_SIZE)
!= MY_AES_OK != MY_AES_OK
|| my_random_bytes(info.crypt_nonce.bytes, sizeof info.crypt_nonce) || my_random_bytes(info.crypt_nonce.bytes, sizeof info.crypt_nonce)
!= MY_AES_OK) { != MY_AES_OK) {
...@@ -287,7 +293,7 @@ log_crypt_101_read_checkpoint(const byte* buf) ...@@ -287,7 +293,7 @@ log_crypt_101_read_checkpoint(const byte* buf)
infos_used++; infos_used++;
info.checkpoint_no = checkpoint_no; info.checkpoint_no = checkpoint_no;
info.key_version = mach_read_from_4(buf + 4); info.key_version = mach_read_from_4(buf + 4);
memcpy(info.crypt_msg.bytes, buf + 8, sizeof info.crypt_msg); memcpy(info.crypt_msg.bytes, buf + 8, MY_AES_BLOCK_SIZE);
memcpy(info.crypt_nonce.bytes, buf + 24, memcpy(info.crypt_nonce.bytes, buf + 24,
sizeof info.crypt_nonce); sizeof info.crypt_nonce);
...@@ -371,13 +377,14 @@ void ...@@ -371,13 +377,14 @@ void
log_crypt_write_checkpoint_buf(byte* buf) log_crypt_write_checkpoint_buf(byte* buf)
{ {
ut_ad(info.key_version); ut_ad(info.key_version);
compile_time_assert(16 == sizeof info.crypt_msg); compile_time_assert(16 == sizeof info.crypt_msg.bytes);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE - LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce); == sizeof info.crypt_nonce);
memcpy(buf + LOG_CHECKPOINT_CRYPT_MESSAGE, info.crypt_msg.bytes, memcpy(buf + LOG_CHECKPOINT_CRYPT_MESSAGE, info.crypt_msg.bytes,
sizeof info.crypt_msg); MY_AES_BLOCK_SIZE);
memcpy(buf + LOG_CHECKPOINT_CRYPT_NONCE, info.crypt_nonce.bytes, memcpy(buf + LOG_CHECKPOINT_CRYPT_NONCE, info.crypt_nonce.bytes,
sizeof info.crypt_nonce); sizeof info.crypt_nonce);
mach_write_to_4(buf + LOG_CHECKPOINT_CRYPT_KEY, info.key_version); mach_write_to_4(buf + LOG_CHECKPOINT_CRYPT_KEY, info.key_version);
...@@ -396,13 +403,14 @@ log_crypt_read_checkpoint_buf(const byte* buf) ...@@ -396,13 +403,14 @@ log_crypt_read_checkpoint_buf(const byte* buf)
#if MY_AES_BLOCK_SIZE != 16 #if MY_AES_BLOCK_SIZE != 16
# error "MY_AES_BLOCK_SIZE != 16; redo log checkpoint format affected" # error "MY_AES_BLOCK_SIZE != 16; redo log checkpoint format affected"
#endif #endif
compile_time_assert(16 == sizeof info.crypt_msg); compile_time_assert(16 == sizeof info.crypt_msg.bytes);
compile_time_assert(16 == MY_AES_BLOCK_SIZE);
compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE compile_time_assert(LOG_CHECKPOINT_CRYPT_MESSAGE
- LOG_CHECKPOINT_CRYPT_NONCE - LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce); == sizeof info.crypt_nonce);
memcpy(info.crypt_msg.bytes, buf + LOG_CHECKPOINT_CRYPT_MESSAGE, memcpy(info.crypt_msg.bytes, buf + LOG_CHECKPOINT_CRYPT_MESSAGE,
sizeof info.crypt_msg); MY_AES_BLOCK_SIZE);
memcpy(info.crypt_nonce.bytes, buf + LOG_CHECKPOINT_CRYPT_NONCE, memcpy(info.crypt_nonce.bytes, buf + LOG_CHECKPOINT_CRYPT_NONCE,
sizeof info.crypt_nonce); sizeof info.crypt_nonce);
...@@ -435,7 +443,7 @@ log_tmp_block_encrypt( ...@@ -435,7 +443,7 @@ log_tmp_block_encrypt(
int rc = encryption_crypt( int rc = encryption_crypt(
src, (uint)size, dst, &dst_len, src, (uint)size, dst, &dst_len,
const_cast<byte*>(info.crypt_key.bytes), (uint)(sizeof info.crypt_key), info.crypt_key.bytes, MY_AES_BLOCK_SIZE,
reinterpret_cast<byte*>(aes_ctr_iv), (uint)(sizeof aes_ctr_iv), reinterpret_cast<byte*>(aes_ctr_iv), (uint)(sizeof aes_ctr_iv),
encrypt encrypt
? ENCRYPTION_FLAG_ENCRYPT|ENCRYPTION_FLAG_NOPAD ? ENCRYPTION_FLAG_ENCRYPT|ENCRYPTION_FLAG_NOPAD
......
...@@ -42,6 +42,14 @@ Created 2011-05-26 Marko Makela ...@@ -42,6 +42,14 @@ Created 2011-05-26 Marko Makela
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#ifdef HAVE_WOLFSSL
// Workaround for MDEV-19582
// (WolfSSL reads memory out of bounds with decryption/NOPAD)
#define WOLFSSL_PAD_SIZE MY_AES_BLOCK_SIZE
#else
#define WOLFSSL_PAD_SIZE 0
#endif
Atomic_counter<ulint> onlineddl_rowlog_rows; Atomic_counter<ulint> onlineddl_rowlog_rows;
ulint onlineddl_rowlog_pct_used; ulint onlineddl_rowlog_pct_used;
ulint onlineddl_pct_progress; ulint onlineddl_pct_progress;
...@@ -3231,7 +3239,7 @@ row_log_allocate( ...@@ -3231,7 +3239,7 @@ row_log_allocate(
index->online_log = log; index->online_log = log;
if (log_tmp_is_encrypted()) { if (log_tmp_is_encrypted()) {
ulint size = srv_sort_buf_size; ulint size = srv_sort_buf_size + WOLFSSL_PAD_SIZE;
log->crypt_head = static_cast<byte *>(os_mem_alloc_large(&size)); log->crypt_head = static_cast<byte *>(os_mem_alloc_large(&size));
log->crypt_tail = static_cast<byte *>(os_mem_alloc_large(&size)); log->crypt_tail = static_cast<byte *>(os_mem_alloc_large(&size));
...@@ -3265,11 +3273,11 @@ row_log_free( ...@@ -3265,11 +3273,11 @@ row_log_free(
row_merge_file_destroy_low(log->fd); row_merge_file_destroy_low(log->fd);
if (log->crypt_head) { if (log->crypt_head) {
os_mem_free_large(log->crypt_head, srv_sort_buf_size); os_mem_free_large(log->crypt_head, srv_sort_buf_size + WOLFSSL_PAD_SIZE);
} }
if (log->crypt_tail) { if (log->crypt_tail) {
os_mem_free_large(log->crypt_tail, srv_sort_buf_size); os_mem_free_large(log->crypt_tail, srv_sort_buf_size + WOLFSSL_PAD_SIZE);
} }
mutex_free(&log->mutex); mutex_free(&log->mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment