Skip to content

Commit 4d3f680

Browse files
author
Jan Lindström
committed
MDEV-8772: Assertion failure in file ha_innodb.cc line 20027 when importing page compressed and encrypted tablespace using incorrect keys
Add error handling to decryp function when decrypt fails during import.
1 parent ddaddf1 commit 4d3f680

File tree

10 files changed

+215
-20
lines changed

10 files changed

+215
-20
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
call mtr.add_suppression("InnoDB: Table .* tablespace is set as discarded");
2+
SET GLOBAL innodb_file_format = `Barracuda`;
3+
SET GLOBAL innodb_file_per_table = ON;
4+
set global innodb_compression_algorithm = 1;
5+
CREATE TABLE t1 (pk INT PRIMARY KEY, f VARCHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
6+
SHOW WARNINGS;
7+
Level Code Message
8+
SHOW CREATE TABLE t1;
9+
Table Create Table
10+
t1 CREATE TABLE `t1` (
11+
`pk` int(11) NOT NULL,
12+
`f` varchar(255) DEFAULT NULL,
13+
PRIMARY KEY (`pk`)
14+
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `PAGE_COMPRESSED`=1 `ENCRYPTED`=YES `ENCRYPTION_KEY_ID`=4
15+
INSERT INTO t1 VALUES (1,'foobar'),(2,'barfoo');
16+
FLUSH TABLE t1 FOR EXPORT;
17+
# List before copying files
18+
t1.cfg
19+
t1.frm
20+
t1.ibd
21+
UNLOCK TABLES;
22+
# Tablespaces should be still encrypted
23+
# t1 yes on expecting NOT FOUND
24+
NOT FOUND /foobar/ in t1.ibd
25+
ALTER TABLE t1 DISCARD TABLESPACE;
26+
SET GLOBAL innodb_file_format = `Barracuda`;
27+
SET GLOBAL innodb_file_per_table = ON;
28+
# List after t1 DISCARD
29+
t1.frm
30+
ALTER TABLE t1 IMPORT TABLESPACE;
31+
ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
32+
SHOW CREATE TABLE t1;
33+
Table Create Table
34+
t1 CREATE TABLE `t1` (
35+
`pk` int(11) NOT NULL,
36+
`f` varchar(255) DEFAULT NULL,
37+
PRIMARY KEY (`pk`)
38+
) ENGINE=InnoDB DEFAULT CHARSET=latin1 `PAGE_COMPRESSED`=1 `ENCRYPTED`=YES `ENCRYPTION_KEY_ID`=4
39+
SELECT * FROM t1;
40+
ERROR HY000: Tablespace has been discarded for table 't1'
41+
# Tablespaces should be still encrypted
42+
# t1 yes on expecting NOT FOUND
43+
NOT FOUND /foobar/ in t1.ibd
44+
DROP TABLE t1;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
--source include/have_innodb.inc
2+
# embedded does not support restart
3+
-- source include/not_embedded.inc
4+
-- source include/not_valgrind.inc
5+
# Avoid CrashReporter popup on Mac
6+
-- source include/not_crashrep.inc
7+
8+
#
9+
# MDEV-8772: Assertion failure in file ha_innodb.cc line 20027 when importing page compressed and encrypted tablespace using incorrect keys
10+
#
11+
call mtr.add_suppression("InnoDB: Table .* tablespace is set as discarded");
12+
13+
--disable_query_log
14+
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
15+
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
16+
--enable_query_log
17+
18+
--let $MYSQLD_TMPDIR = `SELECT @@tmpdir`
19+
--let $MYSQLD_DATADIR = `SELECT @@datadir`
20+
--let SEARCH_RANGE = 10000000
21+
--let t1_IBD = $MYSQLD_DATADIR/test/t1.ibd
22+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
23+
--shutdown_server
24+
--source include/wait_until_disconnected.inc
25+
26+
--write_file $MYSQLTEST_VARDIR/keys1.txt
27+
1;770A8A65DA156D24EE2A093277530142
28+
4;770A8A65DA156D24EE2A093277530143
29+
EOF
30+
31+
--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
32+
--enable_reconnect
33+
--source include/wait_until_connected_again.inc
34+
35+
SET GLOBAL innodb_file_format = `Barracuda`;
36+
SET GLOBAL innodb_file_per_table = ON;
37+
set global innodb_compression_algorithm = 1;
38+
39+
CREATE TABLE t1 (pk INT PRIMARY KEY, f VARCHAR(255)) ENGINE=InnoDB PAGE_COMPRESSED=1 ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
40+
SHOW WARNINGS;
41+
SHOW CREATE TABLE t1;
42+
INSERT INTO t1 VALUES (1,'foobar'),(2,'barfoo');
43+
FLUSH TABLE t1 FOR EXPORT;
44+
--echo # List before copying files
45+
--list_files $MYSQLD_DATADIR/test
46+
--copy_file $MYSQLD_DATADIR/test/t1.cfg $MYSQLD_TMPDIR/t1.cfg
47+
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_TMPDIR/t1.ibd
48+
UNLOCK TABLES;
49+
50+
--sleep 5
51+
--echo # Tablespaces should be still encrypted
52+
--let SEARCH_PATTERN=foobar
53+
--echo # t1 yes on expecting NOT FOUND
54+
-- let SEARCH_FILE=$t1_IBD
55+
-- source include/search_pattern_in_file.inc
56+
57+
ALTER TABLE t1 DISCARD TABLESPACE;
58+
59+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
60+
--shutdown_server
61+
--source include/wait_until_disconnected.inc
62+
63+
--write_file $MYSQLTEST_VARDIR/keys2.txt
64+
1;770A8A65DA156D24EE2A093277530142
65+
4;770A8A65DA156D24EE2A093277530144
66+
EOF
67+
68+
--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
69+
--enable_reconnect
70+
--source include/wait_until_connected_again.inc
71+
--source include/restart_mysqld.inc
72+
73+
SET GLOBAL innodb_file_format = `Barracuda`;
74+
SET GLOBAL innodb_file_per_table = ON;
75+
--echo # List after t1 DISCARD
76+
--list_files $MYSQLD_DATADIR/test
77+
--copy_file $MYSQLD_TMPDIR/t1.cfg $MYSQLD_DATADIR/test/t1.cfg
78+
--copy_file $MYSQLD_TMPDIR/t1.ibd $MYSQLD_DATADIR/test/t1.ibd
79+
80+
--error ER_GET_ERRMSG
81+
ALTER TABLE t1 IMPORT TABLESPACE;
82+
SHOW CREATE TABLE t1;
83+
--error ER_TABLESPACE_DISCARDED
84+
SELECT * FROM t1;
85+
--sleep 5
86+
--echo # Tablespaces should be still encrypted
87+
-- let SEARCH_FILE=$t1_IBD
88+
--let SEARCH_PATTERN=foobar
89+
--echo # t1 yes on expecting NOT FOUND
90+
-- let SEARCH_FILE=$t1_IBD
91+
-- source include/search_pattern_in_file.inc
92+
DROP TABLE t1;
93+
94+
# reset system
95+
--disable_query_log
96+
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
97+
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
98+
--enable_query_log
99+
100+
--remove_file $MYSQLTEST_VARDIR/keys1.txt
101+
--remove_file $MYSQLTEST_VARDIR/keys2.txt

storage/innobase/fil/fil0crypt.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,16 @@ fil_space_decrypt(
714714
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
715715
byte* tmp_frame, /*!< in: temporary buffer */
716716
ulint page_size, /*!< in: page size */
717-
byte* src_frame) /*!< in:out: page buffer */
717+
byte* src_frame, /*!< in: out: page buffer */
718+
dberr_t* err) /*!< in: out: DB_SUCCESS or
719+
error code */
718720
{
719721
ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
720722
uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
721723
bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
722724

725+
*err = DB_SUCCESS;
726+
723727
if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) {
724728
return false;
725729
}
@@ -756,6 +760,12 @@ fil_space_decrypt(
756760
space, offset, lsn);
757761

758762
if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) {
763+
764+
if (rc == -1) {
765+
*err = DB_DECRYPTION_FAILED;
766+
return false;
767+
}
768+
759769
ib_logf(IB_LOG_LEVEL_FATAL,
760770
"Unable to decrypt data-block "
761771
" src: %p srclen: %ld buf: %p buflen: %d."
@@ -797,11 +807,14 @@ fil_space_decrypt(
797807
ulint page_size, /*!< in: page size */
798808
byte* src_frame) /*!< in/out: page buffer */
799809
{
810+
dberr_t err = DB_SUCCESS;
811+
800812
bool encrypted = fil_space_decrypt(
801813
fil_space_get_crypt_data(space),
802814
tmp_frame,
803815
page_size,
804-
src_frame);
816+
src_frame,
817+
&err);
805818

806819
if (encrypted) {
807820
/* Copy the decrypted page back to page buffer, not

storage/innobase/fil/fil0fil.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6425,6 +6425,7 @@ fil_iterate(
64256425
if ((iter.crypt_data != NULL && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
64266426
(srv_encrypt_tables &&
64276427
iter.crypt_data && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
6428+
64286429
encrypted = true;
64296430
readptr = iter.crypt_io_buffer;
64306431
writeptr = iter.crypt_io_buffer;
@@ -6444,6 +6445,7 @@ fil_iterate(
64446445

64456446
for (ulint i = 0; i < n_pages_read; ++i) {
64466447
ulint size = iter.page_size;
6448+
dberr_t err = DB_SUCCESS;
64476449

64486450
/* If tablespace is encrypted, we need to decrypt
64496451
the page. */
@@ -6452,10 +6454,14 @@ fil_iterate(
64526454
iter.crypt_data,
64536455
io_buffer + i * size, //dst
64546456
iter.page_size,
6455-
readptr + i * size); // src
6457+
readptr + i * size, // src
6458+
&err); // src
6459+
6460+
if (err != DB_SUCCESS) {
6461+
return(err);
6462+
}
64566463

64576464
if (decrypted) {
6458-
/* write back unencrypted page */
64596465
updated = true;
64606466
} else {
64616467
/* TODO: remove unnecessary memcpy's */
@@ -6465,7 +6471,6 @@ fil_iterate(
64656471

64666472
buf_block_set_file_page(block, space_id, page_no++);
64676473

6468-
dberr_t err;
64696474

64706475
if ((err = callback(page_off, block)) != DB_SUCCESS) {
64716476

storage/innobase/include/fil0crypt.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ fil_space_decrypt(
211211
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
212212
byte* tmp_frame, /*!< in: temporary buffer */
213213
ulint page_size, /*!< in: page size */
214-
byte* src_frame); /*!< in:out: page buffer */
214+
byte* src_frame, /*!< in:out: page buffer */
215+
dberr_t* err); /*!< in: out: DB_SUCCESS or
216+
error code */
217+
215218

216219
/*********************************************************************
217220
Encrypt buffer page

storage/innobase/row/row0import.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 2012, 2015, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2015, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -3597,10 +3598,13 @@ row_import_for_mysql(
35973598
innobase_format_name(
35983599
table_name, sizeof(table_name), table->name, FALSE);
35993600

3600-
ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3601-
ER_INTERNAL_ERROR,
3602-
"Cannot reset LSNs in table '%s' : %s",
3603-
table_name, ut_strerr(err));
3601+
if (err != DB_DECRYPTION_FAILED) {
3602+
3603+
ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3604+
ER_INTERNAL_ERROR,
3605+
"Cannot reset LSNs in table '%s' : %s",
3606+
table_name, ut_strerr(err));
3607+
}
36043608

36053609
return(row_import_cleanup(prebuilt, trx, err));
36063610
}

storage/xtradb/fil/fil0crypt.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -714,12 +714,16 @@ fil_space_decrypt(
714714
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
715715
byte* tmp_frame, /*!< in: temporary buffer */
716716
ulint page_size, /*!< in: page size */
717-
byte* src_frame) /*!< in:out: page buffer */
717+
byte* src_frame, /*!< in: out: page buffer */
718+
dberr_t* err) /*!< in: out: DB_SUCCESS or
719+
error code */
718720
{
719721
ulint page_type = mach_read_from_2(src_frame+FIL_PAGE_TYPE);
720722
uint key_version = mach_read_from_4(src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
721723
bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED);
722724

725+
*err = DB_SUCCESS;
726+
723727
if (key_version == ENCRYPTION_KEY_NOT_ENCRYPTED) {
724728
return false;
725729
}
@@ -756,6 +760,12 @@ fil_space_decrypt(
756760
space, offset, lsn);
757761

758762
if (! ((rc == MY_AES_OK) && ((ulint) dstlen == srclen))) {
763+
764+
if (rc == -1) {
765+
*err = DB_DECRYPTION_FAILED;
766+
return false;
767+
}
768+
759769
ib_logf(IB_LOG_LEVEL_FATAL,
760770
"Unable to decrypt data-block "
761771
" src: %p srclen: %ld buf: %p buflen: %d."
@@ -797,11 +807,14 @@ fil_space_decrypt(
797807
ulint page_size, /*!< in: page size */
798808
byte* src_frame) /*!< in/out: page buffer */
799809
{
810+
dberr_t err = DB_SUCCESS;
811+
800812
bool encrypted = fil_space_decrypt(
801813
fil_space_get_crypt_data(space),
802814
tmp_frame,
803815
page_size,
804-
src_frame);
816+
src_frame,
817+
&err);
805818

806819
if (encrypted) {
807820
/* Copy the decrypted page back to page buffer, not

storage/xtradb/fil/fil0fil.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6482,6 +6482,7 @@ fil_iterate(
64826482
if ((iter.crypt_data != NULL && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
64836483
(srv_encrypt_tables &&
64846484
iter.crypt_data && iter.crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
6485+
64856486
encrypted = true;
64866487
readptr = iter.crypt_io_buffer;
64876488
writeptr = iter.crypt_io_buffer;
@@ -6501,6 +6502,7 @@ fil_iterate(
65016502

65026503
for (ulint i = 0; i < n_pages_read; ++i) {
65036504
ulint size = iter.page_size;
6505+
dberr_t err = DB_SUCCESS;
65046506

65056507
/* If tablespace is encrypted, we need to decrypt
65066508
the page. */
@@ -6509,10 +6511,14 @@ fil_iterate(
65096511
iter.crypt_data,
65106512
io_buffer + i * size, //dst
65116513
iter.page_size,
6512-
readptr + i * size); // src
6514+
readptr + i * size, // src
6515+
&err); // src
6516+
6517+
if (err != DB_SUCCESS) {
6518+
return(err);
6519+
}
65136520

65146521
if (decrypted) {
6515-
/* write back unencrypted page */
65166522
updated = true;
65176523
} else {
65186524
/* TODO: remove unnecessary memcpy's */
@@ -6522,7 +6528,6 @@ fil_iterate(
65226528

65236529
buf_block_set_file_page(block, space_id, page_no++);
65246530

6525-
dberr_t err;
65266531

65276532
if ((err = callback(page_off, block)) != DB_SUCCESS) {
65286533

storage/xtradb/include/fil0crypt.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ fil_space_decrypt(
211211
fil_space_crypt_t* crypt_data, /*!< in: crypt data */
212212
byte* tmp_frame, /*!< in: temporary buffer */
213213
ulint page_size, /*!< in: page size */
214-
byte* src_frame); /*!< in:out: page buffer */
214+
byte* src_frame, /*!< in:out: page buffer */
215+
dberr_t* err); /*!< in: out: DB_SUCCESS or
216+
error code */
217+
215218

216219
/*********************************************************************
217220
Encrypt buffer page

storage/xtradb/row/row0import.cc

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
4+
Copyright (c) 2015, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -3620,10 +3621,13 @@ row_import_for_mysql(
36203621
innobase_format_name(
36213622
table_name, sizeof(table_name), table->name, FALSE);
36223623

3623-
ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3624-
ER_INTERNAL_ERROR,
3625-
"Cannot reset LSNs in table '%s' : %s",
3626-
table_name, ut_strerr(err));
3624+
if (err != DB_DECRYPTION_FAILED) {
3625+
3626+
ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3627+
ER_INTERNAL_ERROR,
3628+
"Cannot reset LSNs in table '%s' : %s",
3629+
table_name, ut_strerr(err));
3630+
}
36273631

36283632
return(row_import_cleanup(prebuilt, trx, err));
36293633
}

0 commit comments

Comments
 (0)