Skip to content

Commit

Permalink
Bug#29477795 : ISSUES WITH UNDO TABLESPACE ENCRYPTION
Browse files Browse the repository at this point in the history
Reviewed by : DEBARUN.BANERJEE <debarun.banerjee@oracle.com>
              Kevin Lewis <kevin.lewis@oracle.com>
RB : 21752

Change-Id: I3d4da2ef8f5c9a20ec6bc1ba493678cec69d30ce
  • Loading branch information
mayprasa authored and dahlerlend committed Mar 26, 2019
1 parent 4b0412f commit 92198f4
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 74 deletions.
17 changes: 16 additions & 1 deletion mysql-test/suite/innodb/r/log_encrypt_2.result
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";
Variable_name Value
innodb_redo_log_encrypt OFF
CREATE TABLE t1(c1 int) ENGINE=InnoDB ENCRYPTION="Y";
DROP TABLE t1;
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";
Variable_name Value
innodb_redo_log_encrypt ON
DROP TABLE IF EXISTS t1;
SET GLOBAL innodb_file_per_table = 1;
SELECT @@innodb_file_per_table;
Expand Down Expand Up @@ -40,6 +46,9 @@ c1 c2
7 hhhhh
8 iiiii
9 jjjjj
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";
Variable_name Value
innodb_redo_log_encrypt ON
SELECT * FROM t1 LIMIT 10;
c1 c2
0 aaaaa
Expand All @@ -66,6 +75,9 @@ INSERT INTO t1 VALUES(7, "hhhhh");
INSERT INTO t1 VALUES(8, "iiiii");
INSERT INTO t1 VALUES(9, "jjjjj");
# Kill the server
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";
Variable_name Value
innodb_redo_log_encrypt ON
SELECT * FROM t1 LIMIT 10;
c1 c2
0 aaaaa
Expand All @@ -79,7 +91,10 @@ c1 c2
8 iiiii
9 jjjjj
DROP TABLE t1;
# restart: --early-plugin-load=keyring_file=keyring_file.so --loose-keyring_file_data=MYSQL_TMP_DIR/mysecret_keyring2 --general-log --log-output=FILE --general_log_file=MYSQL_TMP_DIR/keyring_query_log --plugin-dir=KEYRING_PLUGIN_PATH
# restart: --early-plugin-load=keyring_file=keyring_file.so --loose-keyring_file_data=MYSQL_TMP_DIR/mysecret_keyring2 --general-log --log-output=FILE --general_log_file=MYSQL_TMP_DIR/keyring_query_log --plugin-dir=KEYRING_PLUGIN_PATH --innodb_redo_log_encrypt=ON
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";
Variable_name Value
innodb_redo_log_encrypt ON
SET block_encryption_mode = 'aes-256-cbc';
DROP DATABASE IF EXISTS tde_db;
CREATE DATABASE tde_db;
Expand Down
1 change: 0 additions & 1 deletion mysql-test/suite/innodb/t/log_encrypt_2-master.opt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
$KEYRING_PLUGIN_OPT
$KEYRING_PLUGIN_LOAD
--loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2
--innodb_redo_log_encrypt=ON
19 changes: 14 additions & 5 deletions mysql-test/suite/innodb/t/log_encrypt_2.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ call mtr.add_suppression("\\[ERROR\\] .*MY-\\d+.* Can't set redo log tablespace
call mtr.add_suppression("You need to use --log-bin to make --binlog-format work");
--enable_query_log

--sleep 2
SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";

CREATE TABLE t1(c1 int) ENGINE=InnoDB ENCRYPTION="Y";

Expand All @@ -25,11 +25,13 @@ DROP TABLE t1;
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- send_shutdown
-- source include/wait_until_disconnected.inc
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT --innodb_redo_log_encrypt=ON" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect

SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";

--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
Expand Down Expand Up @@ -66,11 +68,13 @@ SELECT * FROM t1 LIMIT 10;
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- send_shutdown
-- source include/wait_until_disconnected.inc
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT --innodb_redo_log_encrypt=ON" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect

SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";

SELECT * FROM t1 LIMIT 10;

# Key rotation.
Expand All @@ -94,20 +98,25 @@ INSERT INTO t1 VALUES(9, "jjjjj");

# Restart to confirm the encryption info can be retrieved properly.
--source include/kill_mysqld.inc
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--exec echo "restart:--early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 $KEYRING_PLUGIN_OPT --innodb_redo_log_encrypt=ON" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect

SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";

SELECT * FROM t1 LIMIT 10;
DROP TABLE t1;



let $restart_parameters = restart: --early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 --general-log --log-output=FILE --general_log_file=$MYSQL_TMP_DIR/keyring_query_log $KEYRING_PLUGIN_OPT ;
let $restart_parameters = restart: --early-plugin-load="keyring_file=$KEYRING_PLUGIN" --loose-keyring_file_data=$MYSQL_TMP_DIR/mysecret_keyring2 --general-log --log-output=FILE --general_log_file=$MYSQL_TMP_DIR/keyring_query_log $KEYRING_PLUGIN_OPT --innodb_redo_log_encrypt=ON;
--replace_result $MYSQL_TMP_DIR MYSQL_TMP_DIR $KEYRING_PLUGIN_OPT --plugin-dir=KEYRING_PLUGIN_PATH
--replace_regex /\.dll/.so/
--source include/restart_mysqld.inc

SHOW VARIABLES LIKE "%innodb_redo_log_encrypt%";

#
# Check no effect of block_encryption_mode = 'aes-256-cbc' variable on table encryption
SET block_encryption_mode = 'aes-256-cbc';
Expand Down
15 changes: 15 additions & 0 deletions share/errmsg-utf8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19122,6 +19122,21 @@ ER_IB_RECV_FIRST_REC_GROUP_INVALID
ER_DD_UPGRADE_COMPLETED
eng "Data dictionary upgrade from version '%u' to '%u' completed."

ER_SSL_SERVER_CERT_VERIFY_FAILED
eng "Server SSL certificate doesn't verify: %s"

ER_PERSIST_OPTION_USER_TRUNCATED
eng "Truncated a user name for %s that was too long while reading the persisted variables file"

ER_PERSIST_OPTION_HOST_TRUNCATED
eng "Truncated a host name for %s that was too long while reading the persisted variables file"

ER_NET_WAIT_ERROR
eng "The wait_timeout period was exceeded, the idle time since last command was too long."

ER_IB_MSG_1285
eng "'%s' found not encrypted while '%s' is ON. Trying to encrypt it now."

#
# End of 8.0 error messages intended to be logged to the server error log.
#
Expand Down
4 changes: 3 additions & 1 deletion storage/innobase/fil/fil0fil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4223,6 +4223,7 @@ bool fil_replace_tablespace(space_id_t old_space_id, space_id_t new_space_id,
fil_space_t *space = fil_space_get(old_space_id);
std::string space_name(space->name);
std::string file_name(space->files.front().name);
bool is_encrypted = FSP_FLAGS_GET_ENCRYPTION(space->flags);

/* Delete the old file and space object. */
dberr_t err = fil_delete_tablespace(old_space_id, BUF_REMOVE_ALL_NO_WRITE);
Expand Down Expand Up @@ -4252,7 +4253,8 @@ bool fil_replace_tablespace(space_id_t old_space_id, space_id_t new_space_id,

os_file_close(fh);

uint32_t flags = fsp_flags_init(univ_page_size, false, false, false, false);
uint32_t flags =
fsp_flags_init(univ_page_size, false, false, false, false, is_encrypted);

/* Delete the fil_space_t object for the new_space_id if it exists. */
if (fil_space_get(new_space_id) != nullptr) {
Expand Down
86 changes: 51 additions & 35 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3641,6 +3641,41 @@ static void innobase_post_recover() {

fil_free_scanned_files();

/* If undo tablespaces are to be encrypted, encrypt them now */
if (srv_undo_log_encrypt) {
ut_ad(Encryption::check_keyring());

/* There would be at least 2 UNDO tablespaces */
ut_ad(undo::spaces->size() >= FSP_IMPLICIT_UNDO_TABLESPACES);

if (srv_read_only_mode) {
ib::error(ER_IB_MSG_1051);
srv_undo_log_encrypt = false;
} else {
/* Enable encryption for UNDO tablespaces */
if (srv_enable_undo_encryption(true)) {
ut_ad(false);
srv_undo_log_encrypt = false;
}
}
}

/* If redo log is to be encrypted, encrypt it now */
if (srv_redo_log_encrypt) {
ut_ad(Encryption::check_keyring());

if (srv_read_only_mode) {
ib::error(ER_IB_MSG_1242);
srv_redo_log_encrypt = false;
} else {
/* Enable encryption for REDO log */
if (srv_enable_redo_encryption(true)) {
ut_ad(false);
srv_redo_log_encrypt = false;
}
}
}

if (srv_read_only_mode || srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) {
purge_sys->state = PURGE_STATE_DISABLED;
return;
Expand Down Expand Up @@ -4832,9 +4867,9 @@ static int innodb_init(void *p) {
if (ut_win_init_time()) DBUG_RETURN(innodb_init_abort());
#endif /* _WIN32 */

/* Make sure keyring plugin is loaded if UNDO logs are intended to be
encrypted*/
if (srv_undo_log_encrypt && Encryption::check_keyring() == false) {
/* Check for keyring plugin if UNDO/REDO logs are intended to be encrypted */
if ((srv_undo_log_encrypt || srv_redo_log_encrypt) &&
Encryption::check_keyring() == false) {
DBUG_RETURN(innodb_init_abort());
}

Expand Down Expand Up @@ -19907,15 +19942,15 @@ static void update_innodb_undo_log_encrypt(THD *thd MY_ATTRIBUTE((unused)),
}

/* There would be at least 2 UNDO tablespaces */
ut_ad(!undo::spaces->empty());
ut_ad(undo::spaces->size() >= FSP_IMPLICIT_UNDO_TABLESPACES);

if (srv_read_only_mode) {
ib::error(ER_IB_MSG_1051);
return;
}

/* Enable encryption for UNDO tablespaces */
bool ret = srv_enable_undo_encryption();
bool ret = srv_enable_undo_encryption(false);

if (ret == false) {
/* At this point, all UNDO tablespaces have been encrypted. */
Expand All @@ -19941,45 +19976,26 @@ static void update_innodb_redo_log_encrypt(THD *thd MY_ATTRIBUTE((unused)),
return;
}

/* If encryption is to be disabled. This will just make sure I/O doesn't
write REDO encrypted from now on. */
if (srv_redo_log_encrypt == true) {
srv_redo_log_encrypt = false;
return;
}

/* Check encryption for redo log is enabled or not. If it's
enabled, we will start to encrypt the redo log block from now on.
Note: We need the server_uuid initialized, otherwise, the keyname will
not contains server uuid. */
fil_space_t *space = fil_space_get(dict_sys_t::s_log_space_first_id);
if (!FSP_FLAGS_GET_ENCRYPTION(space->flags) && strlen(server_uuid) > 0) {
dberr_t err;
byte key[ENCRYPTION_KEY_LEN];
byte iv[ENCRYPTION_KEY_LEN];
if (srv_read_only_mode) {
ib::error(ER_IB_MSG_1242);
return;
}

if (srv_read_only_mode) {
ib::error(ER_IB_MSG_1242);
return;
}
/* Enable encryption for REDO tablespaces */
bool ret = srv_enable_redo_encryption(false);

Encryption::random_value(key);
Encryption::random_value(iv);
if (!log_write_encryption(key, iv, false)) {
ib::error(ER_IB_MSG_1243);
return;
} else {
fsp_flags_set_encryption(space->flags);
err = fil_set_encryption(space->id, Encryption::AES, key, iv);
if (err != DB_SUCCESS) {
ib::warn(ER_IB_MSG_1244);
return;
} else {
ib::info(ER_IB_MSG_1245);
}
}
if (ret == false) {
/* At this point, REDO log has been encrypted. */
srv_redo_log_encrypt = true;
}

/* At this point, REDO log is set to be encrypted. */
srv_redo_log_encrypt = true;
return;
}

Expand Down
15 changes: 13 additions & 2 deletions storage/innobase/include/srv0srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -874,8 +874,19 @@ void srv_worker_thread();
/** Rotate default master key for UNDO tablespace. */
void undo_rotate_default_master_key();

/** Enable UNDO tablespace encryption */
bool srv_enable_undo_encryption();
/** Enable UNDO tablespace encryption.
@param[in] is_boot true if it is called during server start up. In this
case, default master key will be used which will be
rotated later with actual master key from kyering.
@return false for success, true otherwise. */
bool srv_enable_undo_encryption(bool is_boot);

/** Enable REDO tablespace encryption.
@param[in] is_boot true if it is called during server start up. In this
case, default master key will be used which will be
rotated later with actual master key from kyering.
@return false for success, true otherwise. */
bool srv_enable_redo_encryption(bool is_boot);

/** Get count of tasks in the queue.
@return number of tasks in queue */
Expand Down
6 changes: 5 additions & 1 deletion storage/innobase/include/srv0start.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*****************************************************************************

Copyright (c) 1995, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1995, 2019, Oracle and/or its affiliates. All Rights Reserved.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License, version 2.0, as published by the
Expand Down Expand Up @@ -125,6 +125,10 @@ void srv_shutdown_all_bg_threads();
purge threads early to apply purge. */
void srv_start_purge_threads();

/** If early redo/undo log encryption processing is done.
@return true if it's done. */
bool is_early_redo_undo_encryption_done();

/** Copy the file path component of the physical file to parameter. It will
copy up to and including the terminating path separator.
@return number of bytes copied or ULINT_UNDEFINED if destination buffer
Expand Down
Loading

0 comments on commit 92198f4

Please sign in to comment.