mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
Fix encryption calls with overlapping buffers
Allocate a temporary buffer instead of using the same buffer in some cases, and add assertions to verify the buffers do not overlap. See [1] for reasonsing. [1] https://github.com/MariaDB/server/pull/2438#discussion_r1137403645 Signed-off-by: Trevor Gross <tmgross@umich.edu>
This commit is contained in:
parent
b91d5bcedc
commit
dbc3429592
12 changed files with 90 additions and 29 deletions
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -60,6 +60,10 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
unsigned int d1, d2= *dlen;
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
if ((res1= encryption_handler.encryption_ctx_init_func((ctx),(key),(klen),(iv),(ivlen),(flags),(key_id),(key_version))))
|
||||
return res1;
|
||||
res1= encryption_handler.encryption_ctx_update_func((ctx),(src),(slen),(dst),(&d1));
|
||||
|
|
|
@ -104,7 +104,11 @@ static inline unsigned int encryption_key_version_exists(unsigned int id, unsign
|
|||
return encryption_key_get(id, version, NULL, &unused) != ENCRYPTION_KEY_VERSION_INVALID;
|
||||
}
|
||||
|
||||
/* main entrypoint to perform encryption or decryption */
|
||||
/** main entrypoint to perform encryption or decryption
|
||||
* @invariant `src` is valid for `slen`
|
||||
* @invariant `dst` is valid for `*dlen`, `*dlen` is initialized
|
||||
* @invariant `src` and `dst` do not overlap
|
||||
*/
|
||||
static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
||||
unsigned char* dst, unsigned int* dlen,
|
||||
const unsigned char* key, unsigned int klen,
|
||||
|
@ -118,6 +122,11 @@ static inline int encryption_crypt(const unsigned char* src, unsigned int slen,
|
|||
// Verify dlen is initialized properly. See MDEV-30389
|
||||
assert(*dlen >= slen);
|
||||
assert((dst[*dlen - 1]= 1));
|
||||
// Verify buffers do not overlap
|
||||
if (src < dst)
|
||||
assert(src + slen <= dst);
|
||||
else
|
||||
assert(dst + *dlen <= src);
|
||||
|
||||
if ((res1= encryption_ctx_init(ctx, key, klen, iv, ivlen, flags, key_id, key_version)))
|
||||
return res1;
|
||||
|
|
|
@ -189,8 +189,7 @@ ret:
|
|||
|
||||
/** Run encryption or decryption on a block.
|
||||
* `i32_1`, `i32_2`, and `i64` are used to create the initialization vector
|
||||
* @invariant `src` must be valid for `slen`
|
||||
* @invariant `dst` is valid for `*dlen`, `*dlen` is initialized
|
||||
* @invariant `src` and `dst` invariants are the same as in `encryption_crypt`
|
||||
*/
|
||||
int do_crypt(const unsigned char* src, unsigned int slen,
|
||||
unsigned char* dst, unsigned int* dlen,
|
||||
|
@ -231,8 +230,7 @@ int do_crypt(const unsigned char* src, unsigned int slen,
|
|||
|
||||
/** Encrypt a block.
|
||||
* `i32_1`, `i32_2`, and `i64` are used to create the initialization vector
|
||||
* @invariant `src` is valid for `slen`
|
||||
* @invariant `dst` is valid for `*dlen`, `*dlen` is initialized
|
||||
* @invariant `src` and `dst` invariants are the same as in `encryption_crypt`
|
||||
*/
|
||||
int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen,
|
||||
unsigned char* dst, unsigned int* dlen,
|
||||
|
@ -246,8 +244,7 @@ int encryption_scheme_encrypt(const unsigned char* src, unsigned int slen,
|
|||
|
||||
/** Decrypt a block.
|
||||
* `i32_1`, `i32_2`, and `i64` are used to create the initialization vector
|
||||
* @invariant `src` is valid for `slen`
|
||||
* @invariant `dst` is valid for `*dlen`, `*dlen` is initialized
|
||||
* @invariant `src` and `dst` invariants are the same as in `encryption_crypt`
|
||||
*/
|
||||
int encryption_scheme_decrypt(const unsigned char* src, unsigned int slen,
|
||||
unsigned char* dst, unsigned int* dlen,
|
||||
|
|
|
@ -84,8 +84,8 @@ void log_decrypt_buf(const byte *iv, byte *buf, const byte *const end);
|
|||
|
||||
/** Encrypt or decrypt a temporary file block.
|
||||
@param[in] src block to encrypt or decrypt
|
||||
@param[in] size size of the block
|
||||
@param[out] dst destination block, also of length `size`
|
||||
@param[in] size length of both src and dst in bytes
|
||||
@param[out] dst destination block
|
||||
@param[in] offs offset to block
|
||||
@param[in] encrypt true=encrypt; false=decrypt
|
||||
@return whether the operation succeeded */
|
||||
|
@ -99,7 +99,7 @@ bool log_tmp_block_encrypt(
|
|||
|
||||
/** Decrypt a temporary file block.
|
||||
@param[in] src block to decrypt
|
||||
@param[in] size size of the block
|
||||
@param[in] size length of both src and dst in bytes
|
||||
@param[out] dst destination block
|
||||
@param[in] offs offset to block
|
||||
@return whether the operation succeeded */
|
||||
|
|
|
@ -429,8 +429,8 @@ ATTRIBUTE_COLD bool log_crypt_read_checkpoint_buf(const byte* buf)
|
|||
|
||||
/** Encrypt or decrypt a temporary file block.
|
||||
@param[in] src block to encrypt or decrypt
|
||||
@param[in] size size of 'src' block
|
||||
@param[out] dst destination block, also of length 'size'
|
||||
@param[in] size length of both src and dst blocks in bytes
|
||||
@param[out] dst destination block
|
||||
@param[in] offs offset to block
|
||||
@param[in] encrypt true=encrypt; false=decrypt
|
||||
@return whether the operation succeeded */
|
||||
|
@ -441,7 +441,7 @@ bool log_tmp_block_encrypt(
|
|||
uint64_t offs,
|
||||
bool encrypt)
|
||||
{
|
||||
uint dst_len = (uint) size;
|
||||
uint dst_len = static_cast<uint>(size);
|
||||
uint64_t iv[MY_AES_BLOCK_SIZE / sizeof(uint64_t)];
|
||||
iv[0] = offs;
|
||||
memcpy(iv + 1, tmp_iv, sizeof iv - sizeof *iv);
|
||||
|
|
|
@ -239,6 +239,7 @@ struct fil_iterator_t {
|
|||
byte* io_buffer; /*!< Buffer to use for IO */
|
||||
fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
|
||||
byte* crypt_io_buffer; /*!< IO buffer when encrypted */
|
||||
byte* crypt_tmp_buffer; /*!< Temporary buffer for crypt use */
|
||||
};
|
||||
|
||||
/** Use the page cursor to iterate over records in a block. */
|
||||
|
@ -2985,17 +2986,25 @@ row_import_read_meta_data(
|
|||
/* decrypt and decompress page if needed */
|
||||
static dberr_t decrypt_decompress(fil_space_crypt_t *space_crypt,
|
||||
uint32_t space_flags, span<byte> page,
|
||||
uint32_t space_id, byte *page_compress_buf)
|
||||
uint32_t space_id, byte *page_compress_buf,
|
||||
byte *tmp_frame)
|
||||
{
|
||||
auto *data= page.data();
|
||||
|
||||
if (space_crypt && space_crypt->should_encrypt())
|
||||
{
|
||||
uint page_size= static_cast<uint>(page.size());
|
||||
|
||||
if (!buf_page_verify_crypt_checksum(data, space_flags))
|
||||
return DB_CORRUPTION;
|
||||
|
||||
if (dberr_t err= fil_space_decrypt(space_id, space_flags, space_crypt,
|
||||
data, page.size(), data))
|
||||
dberr_t err=
|
||||
fil_space_decrypt(space_id, space_flags, space_crypt,
|
||||
tmp_frame, page_size, data);
|
||||
|
||||
memcpy(data, tmp_frame, page_size);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -3115,11 +3124,16 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
|
|||
return err;
|
||||
|
||||
std::unique_ptr<byte[]> page_compress_buf(new byte[get_buf_size()]);
|
||||
std::unique_ptr<byte[], decltype(&aligned_free)> crypt_tmp_frame(
|
||||
static_cast<byte *>(
|
||||
aligned_malloc(physical_size, CPU_LEVEL1_DCACHE_LINESIZE)),
|
||||
&aligned_free);
|
||||
|
||||
if (dberr_t err= decrypt_decompress(space_crypt, space_flags,
|
||||
{page.get(), static_cast<size_t>
|
||||
(physical_size)},
|
||||
space_id, page_compress_buf.get()))
|
||||
space_id, page_compress_buf.get(),
|
||||
crypt_tmp_frame.get()))
|
||||
return err;
|
||||
|
||||
if (table->supports_instant())
|
||||
|
@ -3173,7 +3187,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
|
|||
if (dberr_t err= decrypt_decompress(space_crypt, space_flags,
|
||||
{page.get(), static_cast<size_t>
|
||||
(physical_size)}, space_id,
|
||||
page_compress_buf.get()))
|
||||
page_compress_buf.get(),
|
||||
crypt_tmp_frame.get()))
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -3255,7 +3270,8 @@ static dberr_t handle_instant_metadata(dict_table_t *table,
|
|||
if (dberr_t err= decrypt_decompress(space_crypt, space_flags,
|
||||
{second_page.get(),
|
||||
static_cast<size_t>(physical_size)},
|
||||
space_id, page_compress_buf.get()))
|
||||
space_id, page_compress_buf.get(),
|
||||
crypt_tmp_frame.get()))
|
||||
return err;
|
||||
|
||||
if (fil_page_get_type(second_page.get()) != FIL_PAGE_TYPE_BLOB ||
|
||||
|
@ -3697,8 +3713,14 @@ page_corrupted:
|
|||
if (!buf_page_verify_crypt_checksum(readptr, m_space_flags))
|
||||
goto page_corrupted;
|
||||
|
||||
if ((err= fil_space_decrypt(get_space_id(), m_space_flags, iter.crypt_data,
|
||||
readptr, size, readptr)))
|
||||
dberr_t err= fil_space_decrypt(get_space_id(), m_space_flags,
|
||||
iter.crypt_data, iter.crypt_tmp_buffer,
|
||||
size, readptr);
|
||||
|
||||
memcpy_aligned<CPU_LEVEL1_DCACHE_LINESIZE>(readptr, iter.crypt_tmp_buffer,
|
||||
size);
|
||||
|
||||
if (err)
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
|
@ -4155,17 +4177,21 @@ fil_tablespace_iterate(
|
|||
iter.file_size = file_size;
|
||||
iter.n_io_buffers = n_io_buffers;
|
||||
|
||||
size_t buf_size = (1 + iter.n_io_buffers) * srv_page_size;
|
||||
|
||||
/* Add an extra page for compressed page scratch area. */
|
||||
iter.io_buffer = static_cast<byte*>(
|
||||
aligned_malloc((1 + iter.n_io_buffers)
|
||||
<< srv_page_size_shift, srv_page_size));
|
||||
aligned_malloc(buf_size, srv_page_size));
|
||||
|
||||
iter.crypt_io_buffer = iter.crypt_data
|
||||
? static_cast<byte*>(
|
||||
aligned_malloc((1 + iter.n_io_buffers)
|
||||
<< srv_page_size_shift,
|
||||
srv_page_size))
|
||||
: NULL;
|
||||
if (iter.crypt_data) {
|
||||
iter.crypt_io_buffer = static_cast<byte *>(
|
||||
aligned_malloc(buf_size, srv_page_size));
|
||||
iter.crypt_tmp_buffer = static_cast<byte *>(
|
||||
aligned_malloc(buf_size, CPU_LEVEL1_DCACHE_LINESIZE));
|
||||
} else {
|
||||
iter.crypt_io_buffer = NULL;
|
||||
iter.crypt_tmp_buffer = NULL;
|
||||
}
|
||||
|
||||
if (block->page.zip.ssize) {
|
||||
ut_ad(iter.n_io_buffers == 1);
|
||||
|
@ -4180,6 +4206,7 @@ fil_tablespace_iterate(
|
|||
fil_space_destroy_crypt_data(&iter.crypt_data);
|
||||
}
|
||||
|
||||
aligned_free(iter.crypt_tmp_buffer);
|
||||
aligned_free(iter.crypt_io_buffer);
|
||||
aligned_free(iter.io_buffer);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue