Skip to content

Commit

Permalink
PS-5223 : Can't upgrade with encrypted undo tablespaces from 5.7.24 to
Browse files Browse the repository at this point in the history
8.0.13

This is a fix for upgrade from 5.7 encrypted undo tablespaces to PS
8.0.15. The fix is to accept encrypted undo tablespace header with
ENCRYPTION_KEY_MAGIC_V2 (instead of only ENCRYPTION_KEY_MAGIC_V3),
since PS 5.7 encrypted undo tablespaces are encrypted with
ENCRYPTION_KEY_MAGIC_V2.

Testcase percona_dd_upgrade_undo_encrypted was addded. It tests
upgrade with 5.7 encrypted undo tablespaces with:
1) correct keyring and later upgrade
2) empty keyring
3) corrupted undo encryption keys
  • Loading branch information
Robert Golebiowski committed Apr 5, 2019
1 parent c1decd1 commit d2cf60b
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 0 deletions.
65 changes: 65 additions & 0 deletions mysql-test/r/percona_dd_upgrade_undo_encrypted.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Set different paths for --datadir
# Set path for undo* files.
# Set path for ibdata* files.
# Stop DB server which was created by MTR default, empty undo logs
SET GLOBAL innodb_fast_shutdown=0;
# Start the 8.0 server on 5.7 datadir with correct keyring_file
# Execute mysql_upgrade
mysql.columns_priv OK
mysql.component OK
mysql.db OK
mysql.default_roles OK
mysql.engine_cost OK
mysql.func OK
mysql.general_log OK
mysql.global_grants OK
mysql.gtid_executed OK
mysql.help_category OK
mysql.help_keyword OK
mysql.help_relation OK
mysql.help_topic OK
mysql.innodb_index_stats OK
mysql.innodb_table_stats OK
mysql.ndb_binlog_index OK
mysql.password_history OK
mysql.plugin OK
mysql.procs_priv OK
mysql.proxies_priv OK
mysql.role_edges OK
mysql.server_cost OK
mysql.servers OK
mysql.slave_master_info OK
mysql.slave_relay_log_info OK
mysql.slave_worker_info OK
mysql.slow_log OK
mysql.tables_priv OK
mysql.time_zone OK
mysql.time_zone_leap_second OK
mysql.time_zone_name OK
mysql.time_zone_transition OK
mysql.time_zone_transition_type OK
mysql.user OK
sys.sys_config OK
test.tab1 OK
SHOW CREATE TABLE test.tab1;
Table Create Table
tab1 CREATE TABLE `tab1` (
`c1` int(11) DEFAULT NULL,
`c2` varchar(30) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
SELECT * FROM tab1;
c1 c2
100 aaaaa
200 bbbbb
300 aaaaa
400 bbbbb
# Now let's test what happens when encryption key is missing and we try to start 8.0 server on 5.7 directory
# with encrypted undo tablespaces
# Recreate the directories
# Check for errors in error log
# Corrupt undo encryption keys
# Now we check how the server behaves when undo encryption keys are corrupted
# Check for errors in error log
# Cleanup
# Restart the server with default options.
# restart
Binary file added mysql-test/std_data/undo57_encrypted.zip
Binary file not shown.
1 change: 1 addition & 0 deletions mysql-test/t/percona_dd_upgrade_undo_encrypted-master.opt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--bootstrap --innodb_page_size=16k
146 changes: 146 additions & 0 deletions mysql-test/t/percona_dd_upgrade_undo_encrypted.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# This test contains keyring file created on 64bit which is not
# portable
--source include/have_64bit.inc
--source include/no_valgrind_without_big.inc
--source include/have_util_unzip.inc

--disable_query_log
call mtr.add_suppression("Resizing redo log from");
call mtr.add_suppression("Upgrading redo log");
call mtr.add_suppression("Starting to delete and rewrite log files");
call mtr.add_suppression("New log files created");
call mtr.add_suppression("Unknown system variable 'show_compatibility_56'");
call mtr.add_suppression("You need to use --log-bin to make --binlog-format work");
call mtr.add_suppression("Creating routine without parsing routine body");
call mtr.add_suppression("Resolving dependency for the view");
call mtr.add_suppression("references invalid");
call mtr.add_suppression("doesn't exist");
call mtr.add_suppression("information_schema");
call mtr.add_suppression("Storage engine '.*' does not support system tables. \\[mysql.*\\]");
call mtr.add_suppression("Table 'mysql.component' doesn't exist");
call mtr.add_suppression("is expected to be transactional");
call mtr.add_suppression("table is missing or has an incorrect definition");
call mtr.add_suppression("ACL DDLs will not work unless mysql_upgrade is executed");
call mtr.add_suppression("Native table .* has the wrong structure");
call mtr.add_suppression("Column count of mysql.* is wrong");
call mtr.add_suppression("Cannot open table mysql/version from the internal data dictionary of InnoDB though the .frm file for the table exists");
call mtr.add_suppression("Column count of performance_schema.events_statements_summary_by_digest is wrong");
call mtr.add_suppression("The privilege system failed to initialize correctly");
call mtr.add_suppression("Missing system table mysql.global_grants");
# InnoDB reports "Lock wait timeout" warnings when it tries to drop persistent
# statistics while persistent statistics table is altered during upgrade.
# This issue doesn't seem to cause any further trouble (as there is no persistent
# stats for persistent stats table anyway), so we ignore these warnings here.
call mtr.add_suppression("Unable to delete statistics for table mysql.");
# new fields were added to these tables
call mtr.add_suppression("Column count of performance_schema.replication_group_members is wrong. Expected 7, found 5");
call mtr.add_suppression("Column count of performance_schema.replication_group_member_stats is wrong. Expected 13, found 9");
call mtr.add_suppression("Column count of performance_schema.threads is wrong. Expected 18, found 17");
call mtr.add_suppression("ACL table mysql.[a-zA-Z_]* missing. Some operations may fail.");
call mtr.add_suppression("Info table is not ready to be used. Table 'mysql.slave_master_info' cannot be opened");
call mtr.add_suppression("Error in checking mysql.slave_master_info repository info type of TABLE");
call mtr.add_suppression("Error creating master info: Error checking repositories.");
call mtr.add_suppression("Slave: Failed to initialize the master info structure for channel");
call mtr.add_suppression("Failed to create or recover replication info repositories.");
call mtr.add_suppression("db.opt file not found for test database. Using default Character set");
call mtr.add_suppression("Skip re-populating collations and character sets tables in InnoDB read-only mode");
call mtr.add_suppression("Skipped updating resource group metadata in InnoDB read only mode");
--enable_query_log

--echo # Set different paths for --datadir
let $MYSQLD_DATADIR1 = $MYSQL_TMP_DIR/undo57_encrypted/datadir/data;

--echo # Set path for undo* files.
let $MYSQLD_UNDO_DATADIR = $MYSQL_TMP_DIR/undo57_encrypted/innodb_undo_data_dir;

--echo # Set path for ibdata* files.
let $MYSQLD_HOME_DATA_DIR = $MYSQL_TMP_DIR/undo57_encrypted/innodb_data_home_dir;

--copy_file $MYSQLTEST_VARDIR/std_data/undo57_encrypted.zip $MYSQL_TMP_DIR/undo57_encrypted.zip

--exec unzip -qo $MYSQL_TMP_DIR/undo57_encrypted.zip -d $MYSQL_TMP_DIR

--echo # Stop DB server which was created by MTR default, empty undo logs
SET GLOBAL innodb_fast_shutdown=0;
--source include/shutdown_mysqld.inc

--echo # Start the 8.0 server on 5.7 datadir with correct keyring_file
--let $restart_parameters="restart: --early-plugin-load="keyring_file=$KEYRING_PLUGIN" $KEYRING_PLUGIN_OPT --keyring_file_data=$MYSQL_TMP_DIR/undo57_encrypted/my_key_undo5 --innodb_data_home_dir=$MYSQLD_HOME_DATA_DIR --innodb_undo_directory=$MYSQLD_UNDO_DATADIR --datadir=$MYSQLD_DATADIR1"
--replace_result $MYSQL_TMP_DIR TMP_DIR $KEYRING_PLUGIN_OPT --plugin-dir=KEYRING_PLUGIN_PATH $MYSQLD_HOME_DATA_DIR HOME_DIR $MYSQLD_UNDO_DATADIR UNDO_DATADIR $MYSQLD_DATADIR1 DATADIR
--source include/start_mysqld_no_echo.inc

--echo # Execute mysql_upgrade

--source include/mysql_upgrade_preparation.inc
--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
--source include/mysql_upgrade_cleanup.inc


SHOW CREATE TABLE test.tab1;
SELECT * FROM tab1;

--source include/shutdown_mysqld.inc

--echo # Now let's test what happens when encryption key is missing and we try to start 8.0 server on 5.7 directory
--echo # with encrypted undo tablespaces
--echo # Recreate the directories
--force-rmdir $MYSQL_TMP_DIR/undo57_encrypted

--exec unzip -qo $MYSQL_TMP_DIR/undo57_encrypted.zip -d $MYSQL_TMP_DIR

--let $error_log=$MYSQLTEST_VARDIR/tmp/my_restart.err

--error 1
--exec $MYSQLD_CMD --log-error=$error_log --early-plugin-load="keyring_file=$KEYRING_PLUGIN" $KEYRING_PLUGIN_OPT --keyring_file_data=$MYSQL_TMP_DIR/my_empty_keyring --innodb_data_home_dir=$MYSQLD_HOME_DATA_DIR --innodb_undo_directory=$MYSQLD_UNDO_DATADIR --datadir=$MYSQLD_DATADIR1

--echo # Check for errors in error log

--let ABORT_ON=NOT_FOUND
--let SEARCH_FILE=$error_log
--let SEARCH_PATTERN=Encryption can't find master key, please check the keyring plugin is loaded.
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=Error reading encryption for innodb_undo001
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= Unable to open undo tablespace number 1
--source include/search_pattern_in_file.inc

--echo # Corrupt undo encryption keys

perl;
open(FILE, "+<", "$ENV{MYSQL_TMP_DIR}/undo57_encrypted/my_key_undo5") or die "open";
binmode FILE;
seek(FILE, 77, SEEK_SET) or die "seek";
print FILE pack("H*", "c00l");
seek(FILE, 206, SEEK_SET) or die "seek";
print FILE pack("H*", "c00l");
close FILE or die "close";
EOF

--echo # Now we check how the server behaves when undo encryption keys are corrupted

--let $error_log2=$MYSQLTEST_VARDIR/tmp/my_restart2.err

--error 1
--exec $MYSQLD_CMD --log-error=$error_log2 --early-plugin-load="keyring_file=$KEYRING_PLUGIN" $KEYRING_PLUGIN_OPT --keyring_file_data=$MYSQL_TMP_DIR/undo57_encrypted/my_key_undo5 --innodb_data_home_dir=$MYSQLD_HOME_DATA_DIR --innodb_undo_directory=$MYSQLD_UNDO_DATADIR --datadir=$MYSQLD_DATADIR1

--echo # Check for errors in error log

--let ABORT_ON=NOT_FOUND
--let SEARCH_FILE=$error_log2
--let SEARCH_PATTERN=Encryption can't find master key, please check the keyring plugin is loaded.
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN=Error reading encryption for innodb_undo001
--source include/search_pattern_in_file.inc
--let SEARCH_PATTERN= Unable to open undo tablespace number 1
--source include/search_pattern_in_file.inc

--echo # Cleanup
--remove_file $error_log
--remove_file $error_log2
--remove_file $MYSQL_TMP_DIR/my_empty_keyring
--remove_file $MYSQL_TMP_DIR/undo57_encrypted.zip
--force-rmdir $MYSQL_TMP_DIR/undo57_encrypted

--echo # Restart the server with default options.
--let $restart_parameters=
--source include/start_mysqld.inc
3 changes: 3 additions & 0 deletions storage/innobase/srv/srv0start.cc
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,9 @@ static dberr_t srv_undo_tablespace_read_encryption(pfs_os_file_t fh,

/* Return if the encryption metadata is empty. */
if (memcmp(first_page + offset, ENCRYPTION_KEY_MAGIC_V3,
ENCRYPTION_MAGIC_SIZE) != 0 &&
/* PS 5.7 undo encryption */
memcmp(first_page + offset, ENCRYPTION_KEY_MAGIC_V2,
ENCRYPTION_MAGIC_SIZE) != 0) {
ut_free(first_page_buf);
return (DB_SUCCESS);
Expand Down

0 comments on commit d2cf60b

Please sign in to comment.