Commit ed0a224b authored by Eugene Kosov's avatar Eugene Kosov

MDEV-26747 improve corruption check for encrypted tables on ALTER IMPORT

fil_space_decrypt(): change signature to return status via dberr_t only.
Also replace impossible condition with an assertion and prove it via
test cases.
parent 8f24f5fe
call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted");
call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it");
call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file");
CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
INSERT INTO src VALUES (1, 1), (2, 2), (3, 3);
FLUSH TABLES src FOR EXPORT;
UNLOCK TABLES;
DROP TABLE src;
CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
ALTER TABLE dst DISCARD TABLESPACE;
ALTER TABLE dst IMPORT TABLESPACE;
ERROR HY000: Internal error: Cannot reset LSNs in table `test`.`dst` : Data structure corruption
DROP TABLE dst;
[crc32]
innodb-checksum-algorithm=crc32
[none]
innodb-checksum-algorithm=none
[innodb]
innodb-checksum-algorithm=innodb
--source include/have_innodb.inc
--source include/have_example_key_management_plugin.inc
call mtr.add_suppression("InnoDB: .*: Page 0 at offset 0 looks corrupted");
call mtr.add_suppression("Index for table 'dst' is corrupt; try to repair it");
call mtr.add_suppression("Page for tablespace .* is index page with id .* but that index is not found from configuration file");
let MYSQLD_DATADIR = `SELECT @@datadir`;
CREATE TABLE src (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
INSERT INTO src VALUES (1, 1), (2, 2), (3, 3);
FLUSH TABLES src FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/src.ibd $MYSQLD_DATADIR/test/tmp.ibd
--copy_file $MYSQLD_DATADIR/test/src.cfg $MYSQLD_DATADIR/test/tmp.cfg
perl;
use strict;
die unless open(FILE, "+<$ENV{MYSQLD_DATADIR}/test/tmp.ibd");
binmode FILE;
die unless seek(FILE, 3 * 16384 + 26, 0);
print FILE pack("N", 0x00000000);
close(FILE);
EOF
UNLOCK TABLES;
DROP TABLE src;
CREATE TABLE dst (pk INT PRIMARY KEY, value INT) ENGINE=INNODB;
ALTER TABLE dst DISCARD TABLESPACE;
--copy_file $MYSQLD_DATADIR/test/tmp.ibd $MYSQLD_DATADIR/test/dst.ibd
--copy_file $MYSQLD_DATADIR/test/tmp.cfg $MYSQLD_DATADIR/test/dst.cfg
--error ER_INTERNAL_ERROR
ALTER TABLE dst IMPORT TABLESPACE;
DROP TABLE dst;
--remove_file $MYSQLD_DATADIR/test/tmp.ibd
--remove_file $MYSQLD_DATADIR/test/tmp.cfg
...@@ -668,16 +668,14 @@ fil_space_encrypt( ...@@ -668,16 +668,14 @@ fil_space_encrypt(
@param[in] tmp_frame Temporary buffer @param[in] tmp_frame Temporary buffer
@param[in] page_size Page size @param[in] page_size Page size
@param[in,out] src_frame Page to decrypt @param[in,out] src_frame Page to decrypt
@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED @return DB_SUCCESS or error */
@return true if page decrypted, false if not.*/
UNIV_INTERN UNIV_INTERN
bool dberr_t
fil_space_decrypt( fil_space_decrypt(
fil_space_crypt_t* crypt_data, fil_space_crypt_t* crypt_data,
byte* tmp_frame, byte* tmp_frame,
const page_size_t& page_size, const page_size_t& page_size,
byte* src_frame, byte* src_frame)
dberr_t* err)
{ {
ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE); ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION); uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
...@@ -686,12 +684,7 @@ fil_space_decrypt( ...@@ -686,12 +684,7 @@ fil_space_decrypt(
uint space = mach_read_from_4(src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); uint space = mach_read_from_4(src_frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN); ib_uint64_t lsn = mach_read_from_8(src_frame + FIL_PAGE_LSN);
*err = DB_SUCCESS; ut_a(key_version != ENCRYPTION_KEY_NOT_ENCRYPTED);
if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) {
return false;
}
ut_a(crypt_data != NULL && crypt_data->is_encrypted()); ut_a(crypt_data != NULL && crypt_data->is_encrypted());
/* read space & lsn */ /* read space & lsn */
...@@ -722,8 +715,7 @@ fil_space_decrypt( ...@@ -722,8 +715,7 @@ fil_space_decrypt(
if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) {
if (rc == -1) { if (rc == -1) {
*err = DB_DECRYPTION_FAILED; return DB_DECRYPTION_FAILED;
return false;
} }
ib::fatal() << "Unable to decrypt data-block " ib::fatal() << "Unable to decrypt data-block "
...@@ -748,7 +740,7 @@ fil_space_decrypt( ...@@ -748,7 +740,7 @@ fil_space_decrypt(
srv_stats.pages_decrypted.inc(); srv_stats.pages_decrypted.inc();
return true; /* page was decrypted */ return DB_SUCCESS; /* page was decrypted */
} }
/** /**
...@@ -765,27 +757,21 @@ fil_space_decrypt( ...@@ -765,27 +757,21 @@ fil_space_decrypt(
byte* tmp_frame, byte* tmp_frame,
byte* src_frame) byte* src_frame)
{ {
dberr_t err = DB_SUCCESS;
byte* res = NULL;
const page_size_t page_size(space->flags); const page_size_t page_size(space->flags);
ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted()); ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted());
ut_ad(space->n_pending_ios > 0); ut_ad(space->n_pending_ios > 0);
bool encrypted = fil_space_decrypt(space->crypt_data, tmp_frame, if (DB_SUCCESS != fil_space_decrypt(space->crypt_data, tmp_frame,
page_size, src_frame, &err); page_size, src_frame)) {
return NULL;
}
if (err == DB_SUCCESS) {
if (encrypted) {
/* Copy the decrypted page back to page buffer, not /* Copy the decrypted page back to page buffer, not
really any other options. */ really any other options. */
memcpy(src_frame, tmp_frame, page_size.physical()); memcpy(src_frame, tmp_frame, page_size.physical());
}
res = src_frame;
}
return res; return src_frame;
} }
/****************************************************************** /******************************************************************
......
...@@ -359,16 +359,14 @@ Decrypt a page. ...@@ -359,16 +359,14 @@ Decrypt a page.
@param[in] tmp_frame Temporary buffer @param[in] tmp_frame Temporary buffer
@param[in] page_size Page size @param[in] page_size Page size
@param[in,out] src_frame Page to decrypt @param[in,out] src_frame Page to decrypt
@param[out] err DB_SUCCESS or error @return DB_SUCCESS or error */
@return true if page decrypted, false if not.*/
UNIV_INTERN UNIV_INTERN
bool dberr_t
fil_space_decrypt( fil_space_decrypt(
fil_space_crypt_t* crypt_data, fil_space_crypt_t* crypt_data,
byte* tmp_frame, byte* tmp_frame,
const page_size_t& page_size, const page_size_t& page_size,
byte* src_frame, byte* src_frame);
dberr_t* err);
/****************************************************************** /******************************************************************
Decrypt a page Decrypt a page
......
...@@ -3502,9 +3502,12 @@ dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter, ...@@ -3502,9 +3502,12 @@ dberr_t FetchIndexRootPages::run(const fil_iterator_t& iter,
if (!fil_space_verify_crypt_checksum(readptr, get_page_size())) if (!fil_space_verify_crypt_checksum(readptr, get_page_size()))
goto page_corrupted; goto page_corrupted;
if (!fil_space_decrypt(iter.crypt_data, readptr, if (ENCRYPTION_KEY_NOT_ENCRYPTED ==
get_page_size(), readptr, &err) || mach_read_from_4(readptr + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION))
err != DB_SUCCESS) goto page_corrupted;
if ((err = fil_space_decrypt(iter.crypt_data, readptr,
get_page_size(), readptr)))
goto func_exit; goto func_exit;
} }
...@@ -3647,7 +3650,6 @@ static dberr_t fil_iterate( ...@@ -3647,7 +3650,6 @@ static dberr_t fil_iterate(
} else if (!mach_read_from_4( } else if (!mach_read_from_4(
FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
+ src)) { + src)) {
not_encrypted:
if (block->page.id.page_no() == 0 if (block->page.id.page_no() == 0
&& block->page.zip.data) { && block->page.zip.data) {
block->page.zip.data = src; block->page.zip.data = src;
...@@ -3666,18 +3668,13 @@ static dberr_t fil_iterate( ...@@ -3666,18 +3668,13 @@ static dberr_t fil_iterate(
goto page_corrupted; goto page_corrupted;
} }
decrypted = fil_space_decrypt( if ((err = fil_space_decrypt(
iter.crypt_data, dst, iter.crypt_data, dst,
callback.get_page_size(), src, &err); callback.get_page_size(), src))) {
if (err != DB_SUCCESS) {
goto func_exit; goto func_exit;
} }
if (!decrypted) { decrypted = true;
goto not_encrypted;
}
updated = true; updated = true;
} }
......
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