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,
{
uchar iv[BINLOG_IV_LENGTH];
fdle->crypto_data.set_iv(iv, (uint32) (my_b_tell(file) - data_len));
char *newpkt= (char*)my_malloc(data_len + ev_offset + 1, MYF(MY_WME));
size_t sz= data_len + ev_offset + 1;
#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)
DBUG_RETURN(LOG_READ_MEM);
memcpy(newpkt, packet->ptr(), ev_offset);
......
......@@ -39,10 +39,15 @@ my_bool srv_encrypt_log;
/** Redo log encryption key ID */
#define LOG_DEFAULT_ENCRYPTION_KEY 1
typedef union {
uint32_t words[MY_AES_BLOCK_SIZE / sizeof(uint32_t)];
struct aes_block_t {
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 {
ulint checkpoint_no; /*!< checkpoint no; 32 bits */
......@@ -91,7 +96,8 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
byte mysqld_key[MY_AES_MAX_KEY_LENGTH];
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,
info->key_version, mysqld_key,
......@@ -113,7 +119,7 @@ static bool init_crypt_key(crypt_info_t* info, bool upgrade = false)
uint dst_len;
int err= my_aes_crypt(MY_AES_ECB,
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,
mysqld_key, keylen, NULL, 0);
......@@ -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,
reinterpret_cast<byte*>(dst), &dst_len,
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,
op == LOG_DECRYPT
? ENCRYPTION_FLAG_DECRYPT | ENCRYPTION_FLAG_NOPAD
......@@ -249,7 +255,7 @@ log_crypt_init()
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_random_bytes(info.crypt_nonce.bytes, sizeof info.crypt_nonce)
!= MY_AES_OK) {
......@@ -287,7 +293,7 @@ log_crypt_101_read_checkpoint(const byte* buf)
infos_used++;
info.checkpoint_no = checkpoint_no;
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,
sizeof info.crypt_nonce);
......@@ -371,13 +377,14 @@ void
log_crypt_write_checkpoint_buf(byte* buf)
{
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
- LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce);
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,
sizeof info.crypt_nonce);
mach_write_to_4(buf + LOG_CHECKPOINT_CRYPT_KEY, info.key_version);
......@@ -396,13 +403,14 @@ log_crypt_read_checkpoint_buf(const byte* buf)
#if MY_AES_BLOCK_SIZE != 16
# error "MY_AES_BLOCK_SIZE != 16; redo log checkpoint format affected"
#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
- LOG_CHECKPOINT_CRYPT_NONCE
== sizeof info.crypt_nonce);
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,
sizeof info.crypt_nonce);
......@@ -435,7 +443,7 @@ log_tmp_block_encrypt(
int rc = encryption_crypt(
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),
encrypt
? ENCRYPTION_FLAG_ENCRYPT|ENCRYPTION_FLAG_NOPAD
......
......@@ -42,6 +42,14 @@ Created 2011-05-26 Marko Makela
#include <algorithm>
#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;
ulint onlineddl_rowlog_pct_used;
ulint onlineddl_pct_progress;
......@@ -3231,7 +3239,7 @@ row_log_allocate(
index->online_log = log;
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_tail = static_cast<byte *>(os_mem_alloc_large(&size));
......@@ -3265,11 +3273,11 @@ row_log_free(
row_merge_file_destroy_low(log->fd);
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) {
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);
......
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