diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc index e2a47e35f6d..e8ef2df3ba1 100644 --- a/extra/mariabackup/fil_cur.cc +++ b/extra/mariabackup/fil_cur.cc @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include "fil_cur.h" #include "fil0crypt.h" +#include "fil0pagecompress.h" #include "common.h" #include "read_filt.h" #include "xtrabackup.h" @@ -357,6 +358,7 @@ read_retry: for (page = cursor->buf, i = 0; i < npages; page += page_size, i++) { ulint page_no = cursor->buf_page_no + i; + ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE); if (cursor->space_id == TRX_SYS_SPACE && page_no >= FSP_EXTENT_SIZE && @@ -378,12 +380,33 @@ read_retry: memcpy(tmp_page, page, page_size); if (!fil_space_decrypt(space, tmp_frame, - tmp_page, &decrypted) + tmp_page, &decrypted)) { + goto corrupted; + } + + if (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) { + goto page_decomp; + } + + if (buf_page_is_corrupted(true, tmp_page, + cursor->page_size, space)) { + goto corrupted; + } + + } else if (page_type == FIL_PAGE_PAGE_COMPRESSED) { + memcpy(tmp_page, page, cursor->page_size.physical()); +page_decomp: + ulint decomp = fil_page_decompress(tmp_frame, tmp_page); + + if (!decomp + || (decomp != srv_page_size + && cursor->page_size.is_compressed()) || buf_page_is_corrupted(true, tmp_page, cursor->page_size, space)) { goto corrupted; } + } else if (buf_page_is_corrupted(true, page, cursor->page_size, space)) { corrupted: diff --git a/mysql-test/suite/encryption/r/innodb-bad-key-change.result b/mysql-test/suite/encryption/r/innodb-bad-key-change.result index 1b0fc58ea18..51dcc5166ec 100644 --- a/mysql-test/suite/encryption/r/innodb-bad-key-change.result +++ b/mysql-test/suite/encryption/r/innodb-bad-key-change.result @@ -2,6 +2,7 @@ call mtr.add_suppression("Plugin 'file_key_management' init function returned er call mtr.add_suppression("Plugin 'file_key_management' registration.*failed"); call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[12]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t1.ibd looks corrupted; key_version=1"); call mtr.add_suppression("File '.*mysql-test.std_data.keysbad3\\.txt' not found"); # Start server with keys2.txt SET GLOBAL innodb_file_per_table = ON; diff --git a/mysql-test/suite/encryption/r/innodb-encryption-disable.result b/mysql-test/suite/encryption/r/innodb-encryption-disable.result index 4ccacd4293c..3b3d6712817 100644 --- a/mysql-test/suite/encryption/r/innodb-encryption-disable.result +++ b/mysql-test/suite/encryption/r/innodb-encryption-disable.result @@ -1,5 +1,6 @@ call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[15]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t[15].ibd looks corrupted; key_version=1"); call mtr.add_suppression("Couldn't load plugins from 'file_key_management"); create table t5 ( `intcol1` int(32) DEFAULT NULL, diff --git a/mysql-test/suite/encryption/r/innodb-missing-key.result b/mysql-test/suite/encryption/r/innodb-missing-key.result index b3627cb17b7..ed5bab9e252 100644 --- a/mysql-test/suite/encryption/r/innodb-missing-key.result +++ b/mysql-test/suite/encryption/r/innodb-missing-key.result @@ -1,5 +1,6 @@ call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[123]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t[12].ibd looks corrupted; key_version=1"); # Start server with keys2.txt CREATE TABLE t1(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=19; CREATE TABLE t2(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1; diff --git a/mysql-test/suite/encryption/t/innodb-bad-key-change.test b/mysql-test/suite/encryption/t/innodb-bad-key-change.test index 79e5725e271..a7df715445a 100644 --- a/mysql-test/suite/encryption/t/innodb-bad-key-change.test +++ b/mysql-test/suite/encryption/t/innodb-bad-key-change.test @@ -12,6 +12,7 @@ call mtr.add_suppression("Plugin 'file_key_management' init function returned er call mtr.add_suppression("Plugin 'file_key_management' registration.*failed"); call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[12]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t1.ibd looks corrupted; key_version=1"); call mtr.add_suppression("File '.*mysql-test.std_data.keysbad3\\.txt' not found"); --echo # Start server with keys2.txt diff --git a/mysql-test/suite/encryption/t/innodb-encryption-disable.test b/mysql-test/suite/encryption/t/innodb-encryption-disable.test index 616d613742a..8d870376d99 100644 --- a/mysql-test/suite/encryption/t/innodb-encryption-disable.test +++ b/mysql-test/suite/encryption/t/innodb-encryption-disable.test @@ -9,6 +9,7 @@ call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[15]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t[15].ibd looks corrupted; key_version=1"); # Suppression for builds where file_key_management plugin is linked statically call mtr.add_suppression("Couldn't load plugins from 'file_key_management"); diff --git a/mysql-test/suite/encryption/t/innodb-missing-key.test b/mysql-test/suite/encryption/t/innodb-missing-key.test index 37ac3b00343..56d85c4ebfc 100644 --- a/mysql-test/suite/encryption/t/innodb-missing-key.test +++ b/mysql-test/suite/encryption/t/innodb-missing-key.test @@ -9,6 +9,7 @@ call mtr.add_suppression("InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\] in file '.*test.t[123]\\.ibd' cannot be decrypted\\."); call mtr.add_suppression("failed to read or decrypt \\[page id: space=[1-9][0-9]*, page number=[1-9][0-9]*\\]"); +call mtr.add_suppression("InnoDB: Encrypted page \\[page id: space=[1-9][0-9]*, page number=3\\] in file .*test.t[12].ibd looks corrupted; key_version=1"); --echo # Start server with keys2.txt -- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt diff --git a/mysql-test/suite/mariabackup/encrypted_page_compressed.opt b/mysql-test/suite/mariabackup/encrypted_page_compressed.opt new file mode 100644 index 00000000000..e5a02a1a1c9 --- /dev/null +++ b/mysql-test/suite/mariabackup/encrypted_page_compressed.opt @@ -0,0 +1,6 @@ +--innodb-encryption-rotate-key-age=2 +--innodb-encryption-threads=4 +--innodb-tablespaces-encryption +--plugin-load-add=$FILE_KEY_MANAGEMENT_SO +--loose-file-key-management +--loose-file-key-management-filename=$MYSQL_TEST_DIR/std_data/logkey.txt diff --git a/mysql-test/suite/mariabackup/encrypted_page_compressed.result b/mysql-test/suite/mariabackup/encrypted_page_compressed.result new file mode 100644 index 00000000000..9ed54e5869f --- /dev/null +++ b/mysql-test/suite/mariabackup/encrypted_page_compressed.result @@ -0,0 +1,6 @@ +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes encrypted=yes; +insert into t1(b, c) values("mariadb", "mariabackup"); +# Corrupt the table +# xtrabackup backup +FOUND 1 /Database page corruption detected/ in backup.log +drop table t1; diff --git a/mysql-test/suite/mariabackup/encrypted_page_compressed.test b/mysql-test/suite/mariabackup/encrypted_page_compressed.test new file mode 100644 index 00000000000..eaca762d459 --- /dev/null +++ b/mysql-test/suite/mariabackup/encrypted_page_compressed.test @@ -0,0 +1,47 @@ +source include/have_file_key_management.inc; +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes encrypted=yes; +insert into t1(b, c) values("mariadb", "mariabackup"); + +let $MYSQLD_DATADIR=`select @@datadir`; +let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd; +let INNODB_PAGE_SIZE=`select @@innodb_page_size`; + +--source include/shutdown_mysqld.inc + +--echo # Corrupt the table + +perl; +use strict; +use warnings; +use Fcntl qw(:DEFAULT :seek); + +my $ibd_file = $ENV{'t1_IBD'}; + +my $chunk; +my $page_size = $ENV{'INNODB_PAGE_SIZE'}; + +sysopen IBD_FILE, $ibd_file, O_RDWR || die "Unable to open $ibd_file"; +sysseek IBD_FILE, $page_size * 3 + 75, SEEK_CUR; +$chunk = '\xAA\xAA\xAA\xAA'; +syswrite IBD_FILE, $chunk, 4; + +close IBD_FILE; +EOF + +--source include/start_mysqld.inc + +echo # xtrabackup backup; +--disable_result_log +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log; +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir > $backuplog; +--enable_result_log + +--let SEARCH_PATTERN=Database page corruption detected +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +remove_file $backuplog; + +drop table t1; +rmdir $targetdir; diff --git a/mysql-test/suite/mariabackup/unencrypted_page_compressed.result b/mysql-test/suite/mariabackup/unencrypted_page_compressed.result new file mode 100644 index 00000000000..7f13d37c5f3 --- /dev/null +++ b/mysql-test/suite/mariabackup/unencrypted_page_compressed.result @@ -0,0 +1,8 @@ +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes; +insert into t1(b, c) values("mariadb", "mariabackup"); +InnoDB 0 transactions not purged +# Corrupt the table +# xtrabackup backup +FOUND 1 /Database page corruption detected/ in backup.log +drop table t1; diff --git a/mysql-test/suite/mariabackup/unencrypted_page_compressed.test b/mysql-test/suite/mariabackup/unencrypted_page_compressed.test new file mode 100644 index 00000000000..026b776bffb --- /dev/null +++ b/mysql-test/suite/mariabackup/unencrypted_page_compressed.test @@ -0,0 +1,49 @@ +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY, b TEXT, c char(200)) ENGINE=InnoDB page_compressed=yes; +insert into t1(b, c) values("mariadb", "mariabackup"); +--source ../innodb/include/wait_all_purged.inc + +let $MYSQLD_DATADIR=`select @@datadir`; +let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd; +let INNODB_PAGE_SIZE=`select @@innodb_page_size`; + +--source include/shutdown_mysqld.inc + +--echo # Corrupt the table + +perl; +use strict; +use warnings; +use Fcntl qw(:DEFAULT :seek); + +my $ibd_file = $ENV{'t1_IBD'}; + +my $chunk; +my $page_size = $ENV{'INNODB_PAGE_SIZE'}; + +sysopen IBD_FILE, $ibd_file, O_RDWR || die "Unable to open $ibd_file"; +sysseek IBD_FILE, 16384 * 3 + 75, SEEK_CUR; +$chunk = '\xAA\xAA\xAA\xAA'; +syswrite IBD_FILE, $chunk, 4; + +close IBD_FILE; +EOF + +--let $restart_parameters= --skip-innodb-buffer-pool-load-at-startup +--source include/start_mysqld.inc + +echo # xtrabackup backup; +--disable_result_log +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +let $backuplog=$MYSQLTEST_VARDIR/tmp/backup.log; +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir > $backuplog; +--enable_result_log + +--let SEARCH_PATTERN=Database page corruption detected +--let SEARCH_FILE=$backuplog +--source include/search_pattern_in_file.inc +remove_file $backuplog; + +drop table t1; +rmdir $targetdir; diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index a5a5367326f..02568142e7a 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -526,13 +526,13 @@ decompress_with_slot: /* Verify encryption checksum before we even try to decrypt. */ if (!fil_space_verify_crypt_checksum(dst_frame, bpage->size)) { +decrypt_failed: ib::error() << "Encrypted page " << bpage->id << " in file " << space->chain.start->name << " looks corrupted; key_version=" << mach_read_from_4( FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + dst_frame); -decrypt_failed: /* Mark page encrypted in case it should be. */ if (space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) { diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index a212061ff54..44ad78b1f9a 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -482,6 +482,8 @@ decompress_with_slot: decrypt. */ if (!fil_space_verify_crypt_checksum( dst_frame, buf_page_get_zip_size(bpage))) { + +decrypt_failed: ib_logf(IB_LOG_LEVEL_ERROR, "Encrypted page %u:%u in file %s" " looks corrupted; key_version=" ULINTPF, @@ -490,7 +492,7 @@ decompress_with_slot: mach_read_from_4( FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION + dst_frame)); -decrypt_failed: + /* Mark page encrypted in case it should be. */ if (space->crypt_data->type != CRYPT_SCHEME_UNENCRYPTED) { @@ -4797,7 +4799,6 @@ static dberr_t buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space) not anymore encrypted. */ corrupted = buf_page_is_corrupted(true, dst_frame, zip_size, space); - if (!corrupted) { bpage->encrypted = false; } else {