Commit 6b698715 authored by Jan Lindström's avatar Jan Lindström

MDEV-12114: install_db shows corruption for rest encryption and...

MDEV-12114: install_db shows corruption for rest encryption and innodb_checksum_algorithm=strict_none

Problem was that checksum check resulted false positives that page is
both not encrypted and encryted when checksum_algorithm was
strict_none.

Encrypton checksum will use only crc32 regardless of setting.

buf_zip_decompress: If compression fails report a error message
containing the space name if available (not available during import).
And note if space could be encrypted.

buf_page_get_gen: Do not assert if decompression fails,
instead unfix the page and return NULL to upper layer.

fil_crypt_calculate_checksum: Use only crc32 method.

fil_space_verify_crypt_checksum: Here we need to check
crc32, innodb and none method for old datafiles.

fil_space_release_for_io: Allow null space.

encryption.innodb-compressed-blob is now run with crc32 and none
combinations.

Note that with none and strict_none method there is not really
a way to detect page corruptions and page corruptions after
decrypting the page with incorrect key.

New test innodb-checksum-algorithm to test different checksum
algorithms with encrypted, row compressed and page compressed
tables.
parent 1af8bf39
This diff is collapsed.
call mtr.add_suppression("InnoDB: However key management plugin or used key_version .*");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t1 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t2 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t3 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[0-9]+\\] in file test/t[1-3] cannot be decrypted.");
call mtr.add_suppression("Unable to decompress space ..test.t[1-3].ibd \\[[1-9][0-9]*:[0-9]+\\]");
# Restart mysqld --file-key-management-filename=keys2.txt
SET GLOBAL innodb_file_format = `Barracuda`;
SET GLOBAL innodb_file_per_table = ON;
......
--innodb_checksum_algorithm=innodb
--innodb-tablespaces-encryption
--innodb-encrypt-tables=on
--innodb-encryption-threads=2
--max_allowed_packet=64K
--innodb-encryption-threads=4
This diff is collapsed.
[crc32]
loose-innodb-tablespaces-encryption
loose-innodb-encrypt-tables=on
loose-innodb-encryption-threads=4
max_allowed_packet=64K
loose-innodb-checksum-algorithm=crc32
[none]
loose-innodb-tablespaces-encryption
loose-innodb-encrypt-tables=on
loose-innodb-encryption-threads=4
max_allowed_packet=64K
loose-innodb-checksum-algorithm=none
......@@ -5,10 +5,8 @@
-- source include/not_embedded.inc
call mtr.add_suppression("InnoDB: However key management plugin or used key_version .*");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t1 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t2 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \[page id: space=[0-9]+, page number=[0-9]+\] in file test/t3 cannot be decrypted.");
call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[0-9]+\\] in file test/t[1-3] cannot be decrypted.");
call mtr.add_suppression("Unable to decompress space ..test.t[1-3].ibd \\[[1-9][0-9]*:[0-9]+\\]");
--echo # Restart mysqld --file-key-management-filename=keys2.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
......
......@@ -354,6 +354,15 @@ bool
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
MY_ATTRIBUTE((nonnull));
/********************************************************************//**
Mark a table with the specified space pointed by bpage->space corrupted.
Also remove the bpage from LRU list.
@param[in,out] bpage Block */
static
void
buf_mark_space_corrupt(
buf_page_t* bpage);
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
......@@ -2526,17 +2535,26 @@ buf_zip_decompress(
{
const byte* frame = block->page.zip.data;
ulint size = page_zip_get_size(&block->page.zip);
/* Space is not found if this function is called during IMPORT */
fil_space_t* space = fil_space_acquire_for_io(block->page.space);
const unsigned key_version = mach_read_from_4(frame +
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL;
const bool encrypted = crypt_data
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
ut_ad(buf_block_get_zip_size(block));
ut_a(buf_block_get_space(block) != 0);
if (UNIV_UNLIKELY(check && !page_zip_verify_checksum(frame, size))) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: compressed page checksum mismatch"
" (space %u page %u): stored: %lu, crc32: %lu "
"innodb: %lu, none: %lu\n",
ib_logf(IB_LOG_LEVEL_ERROR,
"Compressed page checksum mismatch"
" for %s [%u:%u]: stored: " ULINTPF ", crc32: " ULINTPF
" innodb: " ULINTPF ", none: " ULINTPF ".",
space ? space->chain.start->name : "N/A",
block->page.space, block->page.offset,
mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM),
page_zip_calc_checksum(frame, size,
......@@ -2545,22 +2563,28 @@ buf_zip_decompress(
SRV_CHECKSUM_ALGORITHM_INNODB),
page_zip_calc_checksum(frame, size,
SRV_CHECKSUM_ALGORITHM_NONE));
return(FALSE);
goto err_exit;
}
switch (fil_page_get_type(frame)) {
case FIL_PAGE_INDEX:
case FIL_PAGE_INDEX: {
if (page_zip_decompress(&block->page.zip,
block->frame, TRUE)) {
if (space) {
fil_space_release_for_io(space);
}
return(TRUE);
}
fprintf(stderr,
"InnoDB: unable to decompress space %u page %u\n",
ib_logf(IB_LOG_LEVEL_ERROR,
"Unable to decompress space %s [%u:%u]",
space ? space->chain.start->name : "N/A",
block->page.space,
block->page.offset);
return(FALSE);
goto err_exit;
}
case FIL_PAGE_TYPE_ALLOCATED:
case FIL_PAGE_INODE:
case FIL_PAGE_IBUF_BITMAP:
......@@ -2571,14 +2595,36 @@ buf_zip_decompress(
/* Copy to uncompressed storage. */
memcpy(block->frame, frame,
buf_block_get_zip_size(block));
if (space) {
fil_space_release_for_io(space);
}
return(TRUE);
}
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: unknown compressed page"
" type %lu\n",
fil_page_get_type(frame));
ib_logf(IB_LOG_LEVEL_ERROR,
"Unknown compressed page in %s [%u:%u]"
" type %s [" ULINTPF "].",
space ? space->chain.start->name : "N/A",
block->page.space, block->page.offset,
fil_get_page_type_name(fil_page_get_type(frame)), fil_page_get_type(frame));
err_exit:
if (encrypted) {
ib_logf(IB_LOG_LEVEL_INFO,
"Row compressed page could be encrypted with key_version %u.",
key_version);
block->page.encrypted = true;
dict_set_encrypted_by_space(block->page.space);
} else {
dict_set_corrupted_by_space(block->page.space);
}
if (space) {
fil_space_release_for_io(space);
}
return(FALSE);
}
......@@ -3031,9 +3077,9 @@ buf_page_get_gen(
}
ib_logf(IB_LOG_LEVEL_FATAL, "Unable"
" to read tablespace %lu page no"
" %lu into the buffer pool after"
" %lu attempts"
" to read tablespace " ULINTPF " page no "
ULINTPF " into the buffer pool after "
ULINTPF " attempts."
" The most probable cause"
" of this error may be that the"
" table has been corrupted."
......@@ -3232,12 +3278,21 @@ buf_page_get_gen(
/* Decompress the page while not holding
buf_pool->mutex or block->mutex. */
/* Page checksum verification is already done when
the page is read from disk. Hence page checksum
verification is not necessary when decompressing the page. */
{
bool success = buf_zip_decompress(block, FALSE);
ut_a(success);
bool success = buf_zip_decompress(block, TRUE);
if (!success) {
buf_pool_mutex_enter(buf_pool);
buf_block_mutex_enter(fix_block);
buf_block_set_io_fix(fix_block, BUF_IO_NONE);
buf_block_mutex_exit(fix_block);
--buf_pool->n_pend_unzip;
buf_block_unfix(fix_block);
buf_pool_mutex_exit(buf_pool);
rw_lock_x_unlock(&fix_block->lock);
return NULL;
}
}
if (!recv_no_ibuf_operations) {
......
......@@ -887,7 +887,7 @@ fil_space_decrypt(
Calculate post encryption checksum
@param[in] zip_size zip_size or 0
@param[in] dst_frame Block where checksum is calculated
@return page checksum or BUF_NO_CHECKSUM_MAGIC
@return page checksum
not needed. */
UNIV_INTERN
ulint
......@@ -896,30 +896,13 @@ fil_crypt_calculate_checksum(
const byte* dst_frame)
{
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
/* For encrypted tables we use only crc32 and strict_crc32 */
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
checksum = buf_calc_page_crc32(dst_frame);
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
SRV_CHECKSUM_ALGORITHM_CRC32);
}
return checksum;
......@@ -953,14 +936,6 @@ fil_space_verify_crypt_checksum(
return(false);
}
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
/* If no checksum is used, can't continue checking. */
if (algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
return(true);
}
/* Read stored post encryption checksum. */
ib_uint32_t checksum = mach_read_from_4(
page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
......@@ -1044,7 +1019,6 @@ fil_space_verify_crypt_checksum(
checksum2 = mach_read_from_4(
page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
valid = (buf_page_is_checksum_valid_crc32(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_none(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_innodb(page,checksum1, checksum2));
}
......
......@@ -86,6 +86,15 @@ bool
buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
MY_ATTRIBUTE((nonnull));
/********************************************************************//**
Mark a table with the specified space pointed by bpage->space corrupted.
Also remove the bpage from LRU list.
@param[in,out] bpage Block */
static
void
buf_mark_space_corrupt(
buf_page_t* bpage);
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
......@@ -2538,17 +2547,26 @@ buf_zip_decompress(
{
const byte* frame = block->page.zip.data;
ulint size = page_zip_get_size(&block->page.zip);
/* Space is not found if this function is called during IMPORT */
fil_space_t* space = fil_space_acquire_for_io(block->page.space);
const unsigned key_version = mach_read_from_4(frame +
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
fil_space_crypt_t* crypt_data = space ? space->crypt_data : NULL;
const bool encrypted = crypt_data
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
|| srv_encrypt_tables);
ut_ad(buf_block_get_zip_size(block));
ut_a(buf_block_get_space(block) != 0);
if (UNIV_UNLIKELY(check && !page_zip_verify_checksum(frame, size))) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: compressed page checksum mismatch"
" (space %u page %u): stored: %lu, crc32: %lu "
"innodb: %lu, none: %lu\n",
ib_logf(IB_LOG_LEVEL_ERROR,
"Compressed page checksum mismatch"
" for %s [%u:%u]: stored: " ULINTPF ", crc32: " ULINTPF
" innodb: " ULINTPF ", none: " ULINTPF ".",
space ? space->chain.start->name : "N/A",
block->page.space, block->page.offset,
mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM),
page_zip_calc_checksum(frame, size,
......@@ -2557,22 +2575,28 @@ buf_zip_decompress(
SRV_CHECKSUM_ALGORITHM_INNODB),
page_zip_calc_checksum(frame, size,
SRV_CHECKSUM_ALGORITHM_NONE));
return(FALSE);
goto err_exit;
}
switch (fil_page_get_type(frame)) {
case FIL_PAGE_INDEX:
case FIL_PAGE_INDEX: {
if (page_zip_decompress(&block->page.zip,
block->frame, TRUE)) {
if (space) {
fil_space_release_for_io(space);
}
return(TRUE);
}
fprintf(stderr,
"InnoDB: unable to decompress space %u page %u\n",
ib_logf(IB_LOG_LEVEL_ERROR,
"Unable to decompress space %s [%u:%u]",
space ? space->chain.start->name : "N/A",
block->page.space,
block->page.offset);
return(FALSE);
goto err_exit;
}
case FIL_PAGE_TYPE_ALLOCATED:
case FIL_PAGE_INODE:
case FIL_PAGE_IBUF_BITMAP:
......@@ -2583,14 +2607,36 @@ buf_zip_decompress(
/* Copy to uncompressed storage. */
memcpy(block->frame, frame,
buf_block_get_zip_size(block));
if (space) {
fil_space_release_for_io(space);
}
return(TRUE);
}
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: unknown compressed page"
" type %lu\n",
fil_page_get_type(frame));
ib_logf(IB_LOG_LEVEL_ERROR,
"Unknown compressed page in %s [%u:%u]"
" type %s [" ULINTPF "].",
space ? space->chain.start->name : "N/A",
block->page.space, block->page.offset,
fil_get_page_type_name(fil_page_get_type(frame)), fil_page_get_type(frame));
err_exit:
if (encrypted) {
ib_logf(IB_LOG_LEVEL_INFO,
"Row compressed page could be encrypted with key_version %u.",
key_version);
block->page.encrypted = true;
dict_set_encrypted_by_space(block->page.space);
} else {
dict_set_corrupted_by_space(block->page.space);
}
if (space) {
fil_space_release_for_io(space);
}
return(FALSE);
}
......@@ -3073,9 +3119,9 @@ buf_page_get_gen(
}
ib_logf(IB_LOG_LEVEL_FATAL, "Unable"
" to read tablespace %lu page no"
" %lu into the buffer pool after"
" %lu attempts"
" to read tablespace " ULINTPF " page no "
ULINTPF " into the buffer pool after "
ULINTPF " attempts."
" The most probable cause"
" of this error may be that the"
" table has been corrupted."
......@@ -3288,12 +3334,21 @@ buf_page_get_gen(
/* Decompress the page while not holding
any buf_pool or block->mutex. */
/* Page checksum verification is already done when
the page is read from disk. Hence page checksum
verification is not necessary when decompressing the page. */
{
bool success = buf_zip_decompress(block, FALSE);
ut_a(success);
bool success = buf_zip_decompress(block, TRUE);
if (!success) {
buf_block_mutex_enter(fix_block);
buf_block_set_io_fix(fix_block, BUF_IO_NONE);
buf_block_mutex_exit(fix_block);
os_atomic_decrement_ulint(&buf_pool->n_pend_unzip, 1);
rw_lock_x_unlock(&fix_block->lock);
mutex_enter(&buf_pool->LRU_list_mutex);
buf_block_unfix(fix_block);
mutex_exit(&buf_pool->LRU_list_mutex);
return NULL;
}
}
if (!recv_no_ibuf_operations) {
......
......@@ -887,7 +887,7 @@ fil_space_decrypt(
Calculate post encryption checksum
@param[in] zip_size zip_size or 0
@param[in] dst_frame Block where checksum is calculated
@return page checksum or BUF_NO_CHECKSUM_MAGIC
@return page checksum
not needed. */
UNIV_INTERN
ulint
......@@ -896,30 +896,13 @@ fil_crypt_calculate_checksum(
const byte* dst_frame)
{
ib_uint32_t checksum = 0;
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
/* For encrypted tables we use only crc32 and strict_crc32 */
if (zip_size == 0) {
switch (algorithm) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
checksum = buf_calc_page_crc32(dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
checksum = (ib_uint32_t) buf_calc_page_new_checksum(
dst_frame);
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
checksum = BUF_NO_CHECKSUM_MAGIC;
break;
/* no default so the compiler will emit a warning
* if new enum is added and not handled here */
}
checksum = buf_calc_page_crc32(dst_frame);
} else {
checksum = page_zip_calc_checksum(dst_frame, zip_size,
algorithm);
SRV_CHECKSUM_ALGORITHM_CRC32);
}
return checksum;
......@@ -953,14 +936,6 @@ fil_space_verify_crypt_checksum(
return(false);
}
srv_checksum_algorithm_t algorithm =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
/* If no checksum is used, can't continue checking. */
if (algorithm == SRV_CHECKSUM_ALGORITHM_NONE) {
return(true);
}
/* Read stored post encryption checksum. */
ib_uint32_t checksum = mach_read_from_4(
page + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + 4);
......@@ -1044,7 +1019,6 @@ fil_space_verify_crypt_checksum(
checksum1 = mach_read_from_4(
page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM);
valid = (buf_page_is_checksum_valid_crc32(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_none(page,checksum1,checksum2)
|| buf_page_is_checksum_valid_innodb(page,checksum1, checksum2));
}
......
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