diff options
7 files changed, 90 insertions, 45 deletions
diff --git a/mysql-test/suite/encryption/r/encryption_key_corruption.result b/mysql-test/suite/encryption/r/encryption_key_corruption.result new file mode 100644 index 00000000000..f467207d0f7 --- /dev/null +++ b/mysql-test/suite/encryption/r/encryption_key_corruption.result @@ -0,0 +1,13 @@ +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; diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.combinations b/mysql-test/suite/encryption/t/encryption_key_corruption.combinations new file mode 100644 index 00000000000..ec77ac17760 --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.combinations @@ -0,0 +1,6 @@ +[crc32] +innodb-checksum-algorithm=crc32 +[none] +innodb-checksum-algorithm=none +[innodb] +innodb-checksum-algorithm=innodb diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.opt b/mysql-test/suite/encryption/t/encryption_key_corruption.opt new file mode 100644 index 00000000000..682d06d5732 --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.opt @@ -0,0 +1 @@ +--innodb-encrypt-tables=1 diff --git a/mysql-test/suite/encryption/t/encryption_key_corruption.test b/mysql-test/suite/encryption/t/encryption_key_corruption.test new file mode 100644 index 00000000000..defb2af741e --- /dev/null +++ b/mysql-test/suite/encryption/t/encryption_key_corruption.test @@ -0,0 +1,44 @@ +--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 diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index ff6294e85b7..46fc12ee6b0 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -668,16 +668,14 @@ fil_space_encrypt( @param[in] tmp_frame Temporary buffer @param[in] page_size Page size @param[in,out] src_frame Page to decrypt -@param[out] err DB_SUCCESS or DB_DECRYPTION_FAILED -@return true if page decrypted, false if not.*/ +@return DB_SUCCESS or error */ UNIV_INTERN -bool +dberr_t fil_space_decrypt( fil_space_crypt_t* crypt_data, byte* tmp_frame, const page_size_t& page_size, - byte* src_frame, - dberr_t* err) + byte* src_frame) { 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); @@ -686,12 +684,7 @@ fil_space_decrypt( 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); - *err = DB_SUCCESS; - - if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) { - return false; - } - + ut_a(key_version != ENCRYPTION_KEY_NOT_ENCRYPTED); ut_a(crypt_data != NULL && crypt_data->is_encrypted()); /* read space & lsn */ @@ -722,8 +715,7 @@ fil_space_decrypt( if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) { if (rc == -1) { - *err = DB_DECRYPTION_FAILED; - return false; + return DB_DECRYPTION_FAILED; } ib::fatal() << "Unable to decrypt data-block " @@ -748,7 +740,7 @@ fil_space_decrypt( srv_stats.pages_decrypted.inc(); - return true; /* page was decrypted */ + return DB_SUCCESS; /* page was decrypted */ } /** @@ -765,27 +757,21 @@ fil_space_decrypt( byte* tmp_frame, byte* src_frame) { - dberr_t err = DB_SUCCESS; - byte* res = NULL; const page_size_t page_size(space->flags); ut_ad(space->crypt_data != NULL && space->crypt_data->is_encrypted()); ut_ad(space->n_pending_ios > 0); - bool encrypted = fil_space_decrypt(space->crypt_data, tmp_frame, - page_size, src_frame, &err); - - if (err == DB_SUCCESS) { - if (encrypted) { - /* Copy the decrypted page back to page buffer, not - really any other options. */ - memcpy(src_frame, tmp_frame, page_size.physical()); - } - - res = src_frame; + if (DB_SUCCESS != fil_space_decrypt(space->crypt_data, tmp_frame, + page_size, src_frame)) { + return NULL; } - return res; + /* Copy the decrypted page back to page buffer, not + really any other options. */ + memcpy(src_frame, tmp_frame, page_size.physical()); + + return src_frame; } /****************************************************************** diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h index af6c930659b..42b38c395d8 100644 --- a/storage/innobase/include/fil0crypt.h +++ b/storage/innobase/include/fil0crypt.h @@ -359,16 +359,14 @@ Decrypt a page. @param[in] tmp_frame Temporary buffer @param[in] page_size Page size @param[in,out] src_frame Page to decrypt -@param[out] err DB_SUCCESS or error -@return true if page decrypted, false if not.*/ +@return DB_SUCCESS or error */ UNIV_INTERN -bool +dberr_t fil_space_decrypt( fil_space_crypt_t* crypt_data, byte* tmp_frame, const page_size_t& page_size, - byte* src_frame, - dberr_t* err); + byte* src_frame); /****************************************************************** Decrypt a page diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index f4df44b3e2b..b7f73bc8e19 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3502,9 +3502,12 @@ page_corrupted: if (!fil_space_verify_crypt_checksum(readptr, get_page_size())) goto page_corrupted; - if (!fil_space_decrypt(iter.crypt_data, readptr, - get_page_size(), readptr, &err) || - err != DB_SUCCESS) + if (ENCRYPTION_KEY_NOT_ENCRYPTED == + mach_read_from_4(readptr + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)) + goto page_corrupted; + + if ((err = fil_space_decrypt(iter.crypt_data, readptr, + get_page_size(), readptr))) goto func_exit; } @@ -3647,7 +3650,6 @@ page_corrupted: } else if (!mach_read_from_4( FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + src)) { -not_encrypted: if (block->page.id.page_no() == 0 && block->page.zip.data) { block->page.zip.data = src; @@ -3666,18 +3668,13 @@ not_encrypted: goto page_corrupted; } - decrypted = fil_space_decrypt( + if ((err = fil_space_decrypt( iter.crypt_data, dst, - callback.get_page_size(), src, &err); - - if (err != DB_SUCCESS) { + callback.get_page_size(), src))) { goto func_exit; } - if (!decrypted) { - goto not_encrypted; - } - + decrypted = true; updated = true; } |