summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Kosov <claprix@yandex.ru>2021-11-01 23:51:58 +0600
committerEugene Kosov <claprix@yandex.ru>2021-11-17 15:49:22 +0600
commited0a224b3d42423699d977c338e3da05fccafaf2 (patch)
treee4d99482e862f9cafd3d3c90b2d325fc530b12cb
parent8f24f5fee267706c0a5f475140a19a9304e224b4 (diff)
downloadmariadb-git-bb-10.2-MDEV-26747-corruption-check.tar.gz
MDEV-26747 improve corruption check for encrypted tables on ALTER IMPORTbb-10.2-MDEV-26747-corruption-check
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.
-rw-r--r--mysql-test/suite/encryption/r/encryption_key_corruption.result13
-rw-r--r--mysql-test/suite/encryption/t/encryption_key_corruption.combinations6
-rw-r--r--mysql-test/suite/encryption/t/encryption_key_corruption.opt1
-rw-r--r--mysql-test/suite/encryption/t/encryption_key_corruption.test44
-rw-r--r--storage/innobase/fil/fil0crypt.cc42
-rw-r--r--storage/innobase/include/fil0crypt.h8
-rw-r--r--storage/innobase/row/row0import.cc21
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;
}