diff --git a/mysql-test/std_data/keys2.txt b/mysql-test/std_data/keys2.txt index aa1600b894d..5b98fbeebd2 100644 --- a/mysql-test/std_data/keys2.txt +++ b/mysql-test/std_data/keys2.txt @@ -4,3 +4,4 @@ 4;205379930183490D3BECA139BDF4DB5B 5;E2D944D5D837A1DCB22FF7FD397892EE 6;BAFE99B0BB87F2CD33A6AF26A11F6BD1 +19;678D6B0063824BACCE33224B385104B35F30FF5749F0EBC030A0955DBC7FAC34 diff --git a/mysql-test/suite/encryption/r/innodb-missing-key.result b/mysql-test/suite/encryption/r/innodb-missing-key.result new file mode 100644 index 00000000000..b59ec158273 --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb-missing-key.result @@ -0,0 +1,54 @@ +call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted"); +call mtr.add_suppression("InnoDB: However key management plugin or used key_id .* is not found or used encryption algorithm or method does not match."); +call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file."); + +# 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; +CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO; +INSERT INTO t1(b) VALUES ('thisissecredmessage'); +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t2 SELECT * FROM t1; +INSERT INTO t3 SELECT * FROM t1; + +# Restart server with keys3.txt +set global innodb_encryption_rotate_key_age = 1; +use test; +CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1; +SELECT SLEEP(5); +SLEEP(5) +0 +SELECT COUNT(1) FROM t3; +COUNT(1) +2048 +SELECT COUNT(1) FROM t2; +COUNT(1) +2048 +SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a; +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 +SELECT COUNT(1) FROM t1 where b = 'ab'; +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 +SELECT COUNT(1) FROM t1; +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 + +# Start server with keys2.txt +SELECT COUNT(1) FROM t1; +COUNT(1) +2048 +SELECT COUNT(1) FROM t2; +COUNT(1) +2048 +SELECT COUNT(1) FROM t3; +COUNT(1) +2048 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/suite/encryption/t/innodb-missing-key.opt b/mysql-test/suite/encryption/t/innodb-missing-key.opt new file mode 100644 index 00000000000..02691695cbd --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb-missing-key.opt @@ -0,0 +1,5 @@ +--innodb-encrypt-tables +--innodb-encryption-rotate-key-age=15 +--innodb-encryption-threads=4 +--innodb-tablespaces-encryption + diff --git a/mysql-test/suite/encryption/t/innodb-missing-key.test b/mysql-test/suite/encryption/t/innodb-missing-key.test new file mode 100644 index 00000000000..8fcfb766117 --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb-missing-key.test @@ -0,0 +1,68 @@ +--source include/have_innodb.inc +-- source include/have_file_key_management_plugin.inc +# embedded does not support restart +-- source include/not_embedded.inc +-- source include/not_valgrind.inc +# Avoid CrashReporter popup on Mac +-- source include/not_crashrep.inc + +# +# MDEV-11004: Unable to start (Segfault or os error 2) when encryption key missing +# +call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted"); +call mtr.add_suppression("InnoDB: However key management plugin or used key_id .* is not found or used encryption algorithm or method does not match."); +call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file."); + +--echo +--echo # Start server with keys2.txt +-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt +-- source include/restart_mysqld.inc + +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; +CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO; +INSERT INTO t1(b) VALUES ('thisissecredmessage'); +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t1(b) SELECT b FROM t1; +INSERT INTO t2 SELECT * FROM t1; +INSERT INTO t3 SELECT * FROM t1; + +--echo +--echo # Restart server with keys3.txt +-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys3.txt +-- source include/restart_mysqld.inc + +set global innodb_encryption_rotate_key_age = 1; +use test; +CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1; +SELECT SLEEP(5); +SELECT COUNT(1) FROM t3; +SELECT COUNT(1) FROM t2; +--error 1296 +SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a; +--error 1296 +SELECT COUNT(1) FROM t1 where b = 'ab'; +--error 1296 +SELECT COUNT(1) FROM t1; + +--echo +--echo # Start server with keys2.txt +-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt +-- source include/restart_mysqld.inc + +SELECT COUNT(1) FROM t1; +SELECT COUNT(1) FROM t2; +SELECT COUNT(1) FROM t3; + +DROP TABLE t1, t2, t3; + + diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 94913098063..9d098c1caf6 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -317,6 +317,9 @@ on the io_type */ ? (counter##_READ) \ : (counter##_WRITTEN)) +/* prototypes for new functions added to ha_innodb.cc */ +trx_t* innobase_get_trx(); + /********************************************************************//** Check if page is maybe compressed, encrypted or both when we encounter corrupted page. Note that we can't be 100% sure if page is corrupted @@ -4485,7 +4488,6 @@ buf_page_check_corrupt( ulint zip_size = buf_page_get_zip_size(bpage); byte* dst_frame = (zip_size) ? bpage->zip.data : ((buf_block_t*) bpage)->frame; - unsigned key_version = bpage->key_version; bool page_compressed = bpage->page_encrypted; ulint stored_checksum = bpage->stored_checksum; ulint calculated_checksum = bpage->stored_checksum; @@ -4495,6 +4497,7 @@ buf_page_check_corrupt( fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); fil_space_t* space = fil_space_found_by_id(space_id); bool corrupted = true; + ulint key_version = bpage->key_version; if (key_version != 0 || page_compressed_encrypted) { bpage->encrypted = true; @@ -4524,7 +4527,7 @@ buf_page_check_corrupt( stored_checksum, calculated_checksum); } ib_logf(IB_LOG_LEVEL_ERROR, - "Reason could be that key_version %u in page " + "Reason could be that key_version %lu in page " "or in crypt_data %p could not be found.", key_version, crypt_data); ib_logf(IB_LOG_LEVEL_ERROR, @@ -4538,7 +4541,7 @@ buf_page_check_corrupt( "Block in space_id %lu in file %s encrypted.", space_id, space ? space->name : "NULL"); ib_logf(IB_LOG_LEVEL_ERROR, - "However key management plugin or used key_id %u is not found or" + "However key management plugin or used key_id %lu is not found or" " used encryption algorithm or method does not match.", key_version); ib_logf(IB_LOG_LEVEL_ERROR, @@ -4718,6 +4721,7 @@ database_corrupted: return(false); } else { corrupted = buf_page_check_corrupt(bpage); + ulint key_version = bpage->key_version; if (corrupted) { ib_logf(IB_LOG_LEVEL_ERROR, @@ -4726,12 +4730,12 @@ database_corrupted: ut_error; } - ib_push_warning((void *)NULL, DB_DECRYPTION_FAILED, + ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED, "Table in tablespace %lu encrypted." - "However key management plugin or used key_id %u is not found or" + "However key management plugin or used key_id %lu is not found or" " used encryption algorithm or method does not match." " Can't continue opening the table.", - (ulint)bpage->space, bpage->key_version); + (ulint)bpage->space, key_version); if (bpage->space > TRX_SYS_SPACE) { if (corrupted) { @@ -4890,7 +4894,7 @@ buf_all_freed_instance( const buf_block_t* block = buf_chunk_not_freed(chunk); if (UNIV_LIKELY_NULL(block)) { - if (block->page.key_version == 0) { + if (block->page.key_version == 0) { fil_space_t* space = fil_space_get(block->page.space); ib_logf(IB_LOG_LEVEL_ERROR, "Page %u %u still fixed or dirty.", diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index bedaf7cfe49..72e3454cbb5 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation( } } + /* If used key_id is not found from encryption plugin we can't + continue to rotate the tablespace */ + if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) { + return false; + } + mutex_enter(&crypt_data->mutex); do { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index f18ce89fb4c..d790bf4c4b6 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2601,6 +2601,20 @@ check_trx_exists( return(trx); } +/************************************************************************* +Gets current trx. */ +trx_t* +innobase_get_trx() +{ + THD *thd=current_thd; + if (likely(thd != 0)) { + trx_t*& trx = thd_to_trx(thd); + return(trx); + } else { + return(NULL); + } +} + /*********************************************************************//** Note that a transaction has been registered with MySQL. @return true if transaction is registered with MySQL 2PC coordinator */ @@ -20664,15 +20678,17 @@ ib_push_warning( char *buf; #define MAX_BUF_SIZE 4*1024 - va_start(args, format); - buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); - vsprintf(buf,format, args); + if (thd) { + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - convert_error_code_to_mysql((dberr_t)error, 0, thd), - buf); - my_free(buf); - va_end(args); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); + } } /********************************************************************//** @@ -20694,15 +20710,17 @@ ib_push_warning( thd = current_thd; } - va_start(args, format); - buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); - vsprintf(buf,format, args); + if (thd) { + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - convert_error_code_to_mysql((dberr_t)error, 0, thd), - buf); - my_free(buf); - va_end(args); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); + } } /********************************************************************//** diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index e77225a3bd2..f5ac842f4e8 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -4601,7 +4601,6 @@ buf_page_check_corrupt( ulint zip_size = buf_page_get_zip_size(bpage); byte* dst_frame = (zip_size) ? bpage->zip.data : ((buf_block_t*) bpage)->frame; - unsigned key_version = bpage->key_version; bool page_compressed = bpage->page_encrypted; ulint stored_checksum = bpage->stored_checksum; ulint calculated_checksum = bpage->stored_checksum; @@ -4611,6 +4610,7 @@ buf_page_check_corrupt( fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id); fil_space_t* space = fil_space_found_by_id(space_id); bool corrupted = true; + ulint key_version = bpage->key_version; if (key_version != 0 || page_compressed_encrypted) { bpage->encrypted = true; @@ -4640,7 +4640,7 @@ buf_page_check_corrupt( stored_checksum, calculated_checksum); } ib_logf(IB_LOG_LEVEL_ERROR, - "Reason could be that key_version %u in page " + "Reason could be that key_version %lu in page " "or in crypt_data %p could not be found.", key_version, crypt_data); ib_logf(IB_LOG_LEVEL_ERROR, @@ -4654,7 +4654,7 @@ buf_page_check_corrupt( "Block in space_id %lu in file %s encrypted.", space_id, space ? space->name : "NULL"); ib_logf(IB_LOG_LEVEL_ERROR, - "However key management plugin or used key_id %u is not found or" + "However key management plugin or used key_id %lu is not found or" " used encryption algorithm or method does not match.", key_version); ib_logf(IB_LOG_LEVEL_ERROR, @@ -4855,6 +4855,7 @@ database_corrupted: return(false); } else { corrupted = buf_page_check_corrupt(bpage); + ulint key_version = bpage->key_version; if (corrupted) { ib_logf(IB_LOG_LEVEL_ERROR, @@ -4865,10 +4866,10 @@ database_corrupted: ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED, "Table in tablespace %lu encrypted." - "However key management plugin or used key_id %u is not found or" + "However key management plugin or used key_id %lu is not found or" " used encryption algorithm or method does not match." " Can't continue opening the table.", - (ulint)bpage->space, bpage->key_version); + (ulint)bpage->space, key_version); if (bpage->space > TRX_SYS_SPACE) { if (corrupted) { diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc index bedaf7cfe49..72e3454cbb5 100644 --- a/storage/xtradb/fil/fil0crypt.cc +++ b/storage/xtradb/fil/fil0crypt.cc @@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation( } } + /* If used key_id is not found from encryption plugin we can't + continue to rotate the tablespace */ + if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) { + return false; + } + mutex_enter(&crypt_data->mutex); do { diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 85bc897efc2..bd76d524e25 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -22245,15 +22245,17 @@ ib_push_warning( char *buf; #define MAX_BUF_SIZE 4*1024 - va_start(args, format); - buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); - vsprintf(buf,format, args); + if (thd) { + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - convert_error_code_to_mysql((dberr_t)error, 0, thd), - buf); - my_free(buf); - va_end(args); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); + } } /********************************************************************//** @@ -22275,15 +22277,17 @@ ib_push_warning( thd = current_thd; } - va_start(args, format); - buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); - vsprintf(buf,format, args); + if (thd) { + va_start(args, format); + buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME)); + vsprintf(buf,format, args); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - convert_error_code_to_mysql((dberr_t)error, 0, thd), - buf); - my_free(buf); - va_end(args); + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + convert_error_code_to_mysql((dberr_t)error, 0, thd), + buf); + my_free(buf); + va_end(args); + } } /********************************************************************//**