diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index 0f02a15ccc4..6122aa4029a 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -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)); diff --git a/include/mysql/plugin_auth.h.pp b/include/mysql/plugin_auth.h.pp index 21ffca7d3e6..4f42e693a16 100644 --- a/include/mysql/plugin_auth.h.pp +++ b/include/mysql/plugin_auth.h.pp @@ -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)); diff --git a/include/mysql/plugin_data_type.h.pp b/include/mysql/plugin_data_type.h.pp index b052330adee..d8788f5d4e0 100644 --- a/include/mysql/plugin_data_type.h.pp +++ b/include/mysql/plugin_data_type.h.pp @@ -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)); diff --git a/include/mysql/plugin_encryption.h.pp b/include/mysql/plugin_encryption.h.pp index bb997d0d84d..5624c6d6f61 100644 --- a/include/mysql/plugin_encryption.h.pp +++ b/include/mysql/plugin_encryption.h.pp @@ -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)); diff --git a/include/mysql/plugin_ftparser.h.pp b/include/mysql/plugin_ftparser.h.pp index 4413f446943..46f4e6fc1fe 100644 --- a/include/mysql/plugin_ftparser.h.pp +++ b/include/mysql/plugin_ftparser.h.pp @@ -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)); diff --git a/include/mysql/plugin_function.h.pp b/include/mysql/plugin_function.h.pp index aeb2caaad65..750f94cbf5d 100644 --- a/include/mysql/plugin_function.h.pp +++ b/include/mysql/plugin_function.h.pp @@ -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)); diff --git a/include/mysql/plugin_password_validation.h.pp b/include/mysql/plugin_password_validation.h.pp index 240effbb213..376df1dd330 100644 --- a/include/mysql/plugin_password_validation.h.pp +++ b/include/mysql/plugin_password_validation.h.pp @@ -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)); diff --git a/include/mysql/service_encryption.h b/include/mysql/service_encryption.h index c9c4c88b680..812b28613a9 100644 --- a/include/mysql/service_encryption.h +++ b/include/mysql/service_encryption.h @@ -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; diff --git a/sql/encryption.cc b/sql/encryption.cc index 633c46174b6..ca161749c41 100644 --- a/sql/encryption.cc +++ b/sql/encryption.cc @@ -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, diff --git a/storage/innobase/include/log0crypt.h b/storage/innobase/include/log0crypt.h index 518134eee7d..ad32dc8faa5 100644 --- a/storage/innobase/include/log0crypt.h +++ b/storage/innobase/include/log0crypt.h @@ -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 */ diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc index b53ce61061e..fc7a5180797 100644 --- a/storage/innobase/log/log0crypt.cc +++ b/storage/innobase/log/log0crypt.cc @@ -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(size); uint64_t iv[MY_AES_BLOCK_SIZE / sizeof(uint64_t)]; iv[0] = offs; memcpy(iv + 1, tmp_iv, sizeof iv - sizeof *iv); diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index eaf987d115d..40fd8c75be2 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -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 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(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 page_compress_buf(new byte[get_buf_size()]); + std::unique_ptr crypt_tmp_frame( + static_cast( + aligned_malloc(physical_size, CPU_LEVEL1_DCACHE_LINESIZE)), + &aligned_free); if (dberr_t err= decrypt_decompress(space_crypt, space_flags, {page.get(), static_cast (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 (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(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(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( - 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( - 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( + aligned_malloc(buf_size, srv_page_size)); + iter.crypt_tmp_buffer = static_cast( + 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); }