summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extra/mariabackup/fil_cur.cc50
-rw-r--r--mysql-test/suite/innodb/include/crc32.pl33
-rw-r--r--mysql-test/suite/mariabackup/encrypted_page_corruption.result2
-rw-r--r--mysql-test/suite/mariabackup/encrypted_page_corruption.test33
4 files changed, 93 insertions, 25 deletions
diff --git a/extra/mariabackup/fil_cur.cc b/extra/mariabackup/fil_cur.cc
index e8ef2df3ba1..a080f7e5420 100644
--- a/extra/mariabackup/fil_cur.cc
+++ b/extra/mariabackup/fil_cur.cc
@@ -329,7 +329,7 @@ xb_fil_cur_read(
xb_a((to_read & (page_size - 1)) == 0);
- npages = (ulint) (to_read / cursor->page_size.physical());
+ npages = (ulint) (to_read / page_size);
retry_count = 10;
ret = XB_FIL_CUR_SUCCESS;
@@ -346,7 +346,7 @@ read_retry:
cursor->buf_read = 0;
cursor->buf_npages = 0;
cursor->buf_offset = offset;
- cursor->buf_page_no = (ulint)(offset / cursor->page_size.physical());
+ cursor->buf_page_no = (ulint)(offset / page_size);
if (!os_file_read(IORequestRead, cursor->file, cursor->buf, offset,
(ulint) to_read)) {
@@ -360,11 +360,32 @@ read_retry:
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 &&
- page_no < FSP_EXTENT_SIZE * 3) {
- /* We ignore the doublewrite buffer pages */
- } else if (mach_read_from_4(
+ if (cursor->space_id == TRX_SYS_SPACE
+ && page_no >= FSP_EXTENT_SIZE
+ && page_no < FSP_EXTENT_SIZE * 3) {
+ /* We ignore the doublewrite buffer pages */
+ } else if (mach_read_from_4(page + FIL_PAGE_OFFSET) != page_no
+ && space->id != TRX_SYS_SPACE) {
+ /* On pages that are not all zero, the
+ page number must match.
+
+ There may be a mismatch on tablespace ID,
+ because files may be renamed during backup.
+ We disable the page number check
+ on the system tablespace, because it may consist
+ of multiple files, and here we count the pages
+ from the start of each file.)
+
+ The first 38 and last 8 bytes are never encrypted. */
+ const ulint* p = reinterpret_cast<ulint*>(page);
+ const ulint* const end = reinterpret_cast<ulint*>(
+ page + page_size);
+ do {
+ if (*p++) {
+ goto corrupted;
+ }
+ } while (p != end);
+ } else if (mach_read_from_4(
page
+ FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION)
&& space->crypt_data
@@ -372,9 +393,6 @@ read_retry:
!= CRYPT_SCHEME_UNENCRYPTED
&& fil_space_verify_crypt_checksum(
page, cursor->page_size)) {
- ut_ad(mach_read_from_4(page + FIL_PAGE_SPACE_ID)
- == space->id);
-
bool decrypted = false;
memcpy(tmp_page, page, page_size);
@@ -392,23 +410,27 @@ read_retry:
cursor->page_size, space)) {
goto corrupted;
}
-
} else if (page_type == FIL_PAGE_PAGE_COMPRESSED) {
- memcpy(tmp_page, page, cursor->page_size.physical());
+ memcpy(tmp_page, page, page_size);
page_decomp:
ulint decomp = fil_page_decompress(tmp_frame, tmp_page);
+ page_type = mach_read_from_2(tmp_page + FIL_PAGE_TYPE);
if (!decomp
|| (decomp != srv_page_size
&& cursor->page_size.is_compressed())
+ || page_type == FIL_PAGE_PAGE_COMPRESSED
+ || page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
|| 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)) {
+ } else if (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
+ || buf_page_is_corrupted(true, page,
+ cursor->page_size,
+ space)) {
corrupted:
retry_count--;
if (retry_count == 0) {
diff --git a/mysql-test/suite/innodb/include/crc32.pl b/mysql-test/suite/innodb/include/crc32.pl
new file mode 100644
index 00000000000..c2bce09dd36
--- /dev/null
+++ b/mysql-test/suite/innodb/include/crc32.pl
@@ -0,0 +1,33 @@
+# The following is Public Domain / Creative Commons CC0 from
+# http://billauer.co.il/blog/2011/05/perl-crc32-crc-xs-module/
+
+sub mycrc32 {
+ my ($input, $init_value, $polynomial) = @_;
+
+ $init_value = 0 unless (defined $init_value);
+ $polynomial = 0xedb88320 unless (defined $polynomial);
+
+ my @lookup_table;
+
+ for (my $i=0; $i<256; $i++) {
+ my $x = $i;
+ for (my $j=0; $j<8; $j++) {
+ if ($x & 1) {
+ $x = ($x >> 1) ^ $polynomial;
+ } else {
+ $x = $x >> 1;
+ }
+ }
+ push @lookup_table, $x;
+ }
+
+ my $crc = $init_value ^ 0xffffffff;
+
+ foreach my $x (unpack ('C*', $input)) {
+ $crc = (($crc >> 8) & 0xffffff) ^ $lookup_table[ ($crc ^ $x) & 0xff ];
+ }
+
+ $crc = $crc ^ 0xffffffff;
+
+ return $crc;
+}
diff --git a/mysql-test/suite/mariabackup/encrypted_page_corruption.result b/mysql-test/suite/mariabackup/encrypted_page_corruption.result
index bbcd3bba816..6e879d58214 100644
--- a/mysql-test/suite/mariabackup/encrypted_page_corruption.result
+++ b/mysql-test/suite/mariabackup/encrypted_page_corruption.result
@@ -1,4 +1,4 @@
-call mtr.add_suppression("\\[ERROR\\] InnoDB: The page .* in file .* cannot be decrypted.");
+call mtr.add_suppression("\\[ERROR\\] InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=3\\] in file '.*test.t1\\.ibd' cannot be decrypted.");
CREATE TABLE t1(c VARCHAR(128)) ENGINE INNODB, encrypted=yes;
insert into t1 select repeat('a',100);
# Corrupt the table
diff --git a/mysql-test/suite/mariabackup/encrypted_page_corruption.test b/mysql-test/suite/mariabackup/encrypted_page_corruption.test
index f8f7bdb6567..12aabc5cfd9 100644
--- a/mysql-test/suite/mariabackup/encrypted_page_corruption.test
+++ b/mysql-test/suite/mariabackup/encrypted_page_corruption.test
@@ -1,11 +1,12 @@
--source include/have_file_key_management.inc
+--source include/innodb_page_size.inc
-call mtr.add_suppression("\\[ERROR\\] InnoDB: The page .* in file .* cannot be decrypted.");
+call mtr.add_suppression("\\[ERROR\\] InnoDB: The page \\[page id: space=[1-9][0-9]*, page number=3\\] in file '.*test.t1\\.ibd' cannot be decrypted.");
CREATE TABLE t1(c VARCHAR(128)) ENGINE INNODB, encrypted=yes;
insert into t1 select repeat('a',100);
-let $MYSQLD_DATADIR=`select @@datadir`;
-let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd;
+let MYSQLD_DATADIR=`select @@datadir`;
+let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
--source include/shutdown_mysqld.inc
@@ -15,17 +16,29 @@ perl;
use strict;
use warnings;
use Fcntl qw(:DEFAULT :seek);
+do "$ENV{MTR_SUITE_DIR}/../innodb/include/crc32.pl";
-my $ibd_file = $ENV{'t1_IBD'};
+my $page_size = $ENV{INNODB_PAGE_SIZE};
-my $chunk;
-my $len;
+sysopen IBD_FILE, "$ENV{MYSQLD_DATADIR}/test/t1.ibd", O_RDWR
+|| die "Cannot open t1.ibd\n";
+sysread(IBD_FILE, $_, 38) || die "Cannot read t1.ibd\n";
+my $space = unpack("x[34]N", $_);
+sysseek(IBD_FILE, $page_size * 3, SEEK_SET) || die "Cannot seek t1.ibd\n";
-sysopen IBD_FILE, $ibd_file, O_RDWR || die "Unable to open $ibd_file";
-sysseek IBD_FILE, 16384 * 3, SEEK_CUR;
-$chunk = '\xAA\xAA\xAA\xAA';
-syswrite IBD_FILE, $chunk, 4;
+my $head = pack("Nx[18]", 3); # better to have a valid page number
+my $body = chr(0) x ($page_size - 38 - 8);
+# Calculate innodb_checksum_algorithm=crc32 for the unencrypted page.
+# The following bytes are excluded:
+# bytes 0..3 (the checksum is stored there)
+# bytes 26..37 (encryption key version, post-encryption checksum, tablespace id)
+# bytes $page_size-8..$page_size-1 (checksum, LSB of FIL_PAGE_LSN)
+my $polynomial = 0x82f63b78; # CRC-32C
+my $ck = mycrc32($head, 0, $polynomial) ^ mycrc32($body, 0, $polynomial);
+
+my $page= pack("N",$ck).$head.pack("NNN",1,$ck,$space).$body.pack("Nx[4]",$ck);
+die unless syswrite(IBD_FILE, $page, $page_size) == $page_size;
close IBD_FILE;
EOF