Skip to content

Commit

Permalink
PS-4556: InnoDB redo log encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
dutow committed Sep 27, 2018
1 parent bdf83c4 commit f1a9fef
Show file tree
Hide file tree
Showing 61 changed files with 4,809 additions and 86 deletions.
77 changes: 73 additions & 4 deletions client/mysqltest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ enum enum_commands {
Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_SKIP,
Q_CHMOD_FILE, Q_APPEND_FILE, Q_CAT_FILE, Q_DIFF_FILES,
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
Q_FORCE_RMDIR,
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
Q_RESULT_FORMAT_VERSION,
Expand Down Expand Up @@ -503,6 +504,7 @@ const char *command_names[]=
"change_user",
"mkdir",
"rmdir",
"force-rmdir",
"list_files",
"list_files_write_file",
"list_files_append_file",
Expand Down Expand Up @@ -3889,17 +3891,78 @@ void do_mkdir(struct st_command *command)
DBUG_VOID_RETURN;
}


/*
SYNOPSIS
do_force_rmdir
command - command handle
ds_dirname - pointer to dynamic string containing directory informtion
DESCRIPTION
force-rmdir <dir_name>
Remove the directory <dir_name>
*/

static void do_force_rmdir(struct st_command *command, DYNAMIC_STRING *ds_dirname)
{
DBUG_ENTER("do_force_rmdir");

char dir_name[FN_REFLEN];
strncpy(dir_name, ds_dirname->str, sizeof(dir_name));

/* Note that my_dir sorts the list if not given any flags */
MY_DIR *dir_info= my_dir(ds_dirname->str, MYF(MY_DONT_SORT | MY_WANT_STAT));

if (dir_info && dir_info->number_off_files > 2)
{
/* Storing the length of the path to the file, so it can be reused */
size_t length= ds_dirname->length;

/* Delete the directory recursively */
for (uint i= 0; i < dir_info->number_off_files; i++)
{
FILEINFO *file= dir_info->dir_entry + i;

/* Skip the names "." and ".." */
if (!strcmp(file->name, ".") ||
!strcmp(file->name, ".."))
continue;

ds_dirname->length= length;
char dir_separator[2]= {FN_LIBCHAR, 0};
dynstr_append(ds_dirname, dir_separator);
dynstr_append(ds_dirname, file->name);

if (MY_S_ISDIR(file->mystat->st_mode))
/* It's a directory */
do_force_rmdir(command, ds_dirname);
else
/* It's a file */
my_delete(ds_dirname->str, MYF(0));
}
}

my_dirend(dir_info);
int error= rmdir(dir_name) != 0;
handle_command_error(command, error);

DBUG_VOID_RETURN;
}


/*
SYNOPSIS
do_rmdir
command called command
force Recursively delete a directory if the value is set to true,
otherwise delete an empty direcory
DESCRIPTION
rmdir <dir_name>
Remove the empty directory <dir_name>
*/

void do_rmdir(struct st_command *command)
static void do_rmdir(struct st_command *command, bool force)
{
int error;
static DYNAMIC_STRING ds_dirname;
Expand All @@ -3913,8 +3976,13 @@ void do_rmdir(struct st_command *command)
' ');

DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str));
error= rmdir(ds_dirname.str) != 0;
handle_command_error(command, error);
if (force)
do_force_rmdir(command, &ds_dirname);
else
{
error= rmdir(ds_dirname.str) != 0;
handle_command_error(command, error);
}
dynstr_free(&ds_dirname);
DBUG_VOID_RETURN;
}
Expand Down Expand Up @@ -9545,7 +9613,8 @@ int main(int argc, char **argv)
case Q_REMOVE_FILE: do_remove_file(command); break;
case Q_REMOVE_FILES_WILDCARD: do_remove_files_wildcard(command); break;
case Q_MKDIR: do_mkdir(command); break;
case Q_RMDIR: do_rmdir(command); break;
case Q_RMDIR: do_rmdir(command, 0); break;
case Q_FORCE_RMDIR: do_rmdir(command, 1); break;
case Q_LIST_FILES: do_list_files(command); break;
case Q_LIST_FILES_WRITE_FILE:
do_list_files_write_file_command(command, FALSE);
Expand Down
1 change: 1 addition & 0 deletions include/system_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

C_MODE_START
#define PERCONA_BINLOG_KEY_NAME "percona_binlog"
#define PERCONA_REDO_KEY_NAME "percona_redo"
extern const size_t valid_percona_system_keys_size;
extern const char* valid_percona_system_keys[];

Expand Down
131 changes: 131 additions & 0 deletions mysql-test/include/log_encrypt_1.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# WL#9290 InnoDB: Support transparent tablespace data encryption for redo log
# This test case will test basic redo log encryption support features.

--source include/no_valgrind_without_big.inc
--source include/have_innodb.inc
--source include/not_embedded.inc
--source include/have_innodb_max_16k.inc

--disable_query_log
call mtr.add_suppression("\\[Error\\] InnoDB: Encryption can't find master key, please check the keyring plugin is loaded.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Failed to find tablespace for table `\.\.*`\.`\.\.*` in the cache.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Operating system error number 2 in a file operation.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: The error means the system cannot find the path specified.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Could not find a valid tablespace file for");
call mtr.add_suppression("ibd can't be decrypted , please confirm the keyfile is match and keyring plugin is loaded.");
call mtr.add_suppression("\\[Warning\\] InnoDB: Ignoring tablespace .* because it could not be opened");
call mtr.add_suppression("\\[ERROR\\] InnoDB: If you are installing InnoDB, remember that you must create directories yourself, InnoDB does not create them.");
call mtr.add_suppression("\\[ERROR\\] InnoDB: Can't set redo log tablespace to be encrypted.");
--enable_query_log

#Enable redo log encryption, should report error in server log, since keyring is not loaded.
eval SET GLOBAL innodb_redo_log_encrypt = $redo_log_mode;

# Create a table with encryption, should fail since keyring is not
# loaded.
--error ER_CANNOT_FIND_KEY_IN_KEYRING
CREATE TABLE t1(c1 INT, c2 char(20)) ENCRYPTION="Y" ENGINE = InnoDB;

CREATE TABLE t1(c1 INT, c2 char(20)) ENGINE = InnoDB;

--error ER_CANNOT_FIND_KEY_IN_KEYRING
ALTER TABLE t1 ENCRYPTION="Y", algorithm=copy;

let $restart_parameters = restart: $KEYRING_PARAMS --general-log --log-output=FILE --general_log_file=$MYSQL_TMP_DIR/keyring_query_log $KEYRING_PLUGIN_OPT;
--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

#Enable redo log encryption
eval SET GLOBAL innodb_redo_log_encrypt = $redo_log_mode;

SHOW CREATE TABLE t1;

INSERT INTO t1 VALUES(0, "aaaaa");
INSERT INTO t1 VALUES(1, "bbbbb");
INSERT INTO t1 VALUES(2, "ccccc");
INSERT INTO t1 VALUES(3, "ddddd");
INSERT INTO t1 VALUES(4, "eeeee");
INSERT INTO t1 VALUES(5, "fffff");
INSERT INTO t1 VALUES(6, "ggggg");
INSERT INTO t1 VALUES(7, "hhhhh");
INSERT INTO t1 VALUES(8, "iiiii");
INSERT INTO t1 VALUES(9, "jjjjj");
INSERT INTO t1 select * from t1;
INSERT INTO t1 select * from t1;
INSERT INTO t1 select * from t1;
INSERT INTO t1 select * from t1;
INSERT INTO t1 select * from t1;
INSERT INTO t1 select * from t1;

SELECT * FROM t1 ORDER BY c1 LIMIT 10;

# Restart to confirm the encryption info can be retrieved properly.
let $restart_parameters = restart: $KEYRING_PARAMS --general-log --log-output=FILE --general_log_file=$MYSQL_TMP_DIR/keyring_query_log --innodb_redo_log_encrypt=$redo_log_mode;
--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

SELECT * FROM t1 ORDER BY c1 LIMIT 10;

DROP TABLE t1;

# Crash/recovery test.
CREATE TABLE t1(c1 INT, c2 char(20)) ENGINE = InnoDB;

INSERT INTO t1 VALUES(0, "aaaaa");
INSERT INTO t1 VALUES(1, "bbbbb");
INSERT INTO t1 VALUES(2, "ccccc");
INSERT INTO t1 VALUES(3, "ddddd");
INSERT INTO t1 VALUES(4, "eeeee");
INSERT INTO t1 VALUES(5, "fffff");
INSERT INTO t1 VALUES(6, "ggggg");
INSERT INTO t1 VALUES(7, "hhhhh");
INSERT INTO t1 VALUES(8, "iiiii");
INSERT INTO t1 VALUES(9, "jjjjj");

# Restart to confirm the encryption info can be retrieved properly.
--source include/kill_mysqld.inc
--exec echo "restart: $KEYRING_PARAMS" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--disable_reconnect

SELECT * FROM t1 ORDER BY c1 LIMIT 10;
DELETE FROM t1;

START TRANSACTION;
INSERT INTO t1 VALUES(0, "aaaaa");
INSERT INTO t1 VALUES(1, "bbbbb");
INSERT INTO t1 VALUES(2, "ccccc");
INSERT INTO t1 VALUES(3, "ddddd");
INSERT INTO t1 VALUES(4, "eeeee");
INSERT INTO t1 VALUES(5, "fffff");
INSERT INTO t1 VALUES(6, "ggggg");
INSERT INTO t1 VALUES(7, "hhhhh");
INSERT INTO t1 VALUES(8, "iiiii");
INSERT INTO t1 VALUES(9, "jjjjj");

# Restart to confirm the encryption info can be retrieved properly.
let $restart_parameters = restart: $KEYRING_PARAMS --general-log --log-output=FILE --general_log_file=$MYSQL_TMP_DIR/keyring_query_log --innodb_redo_log_encrypt=$redo_log_mode;
--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

SELECT * FROM t1 ORDER BY c1 LIMIT 10;

INSERT INTO t1 VALUES(0, "aaaaa");
INSERT INTO t1 VALUES(1, "bbbbb");
INSERT INTO t1 VALUES(2, "ccccc");
INSERT INTO t1 VALUES(3, "ddddd");
INSERT INTO t1 VALUES(4, "eeeee");
INSERT INTO t1 VALUES(5, "fffff");
INSERT INTO t1 VALUES(6, "ggggg");
INSERT INTO t1 VALUES(7, "hhhhh");
INSERT INTO t1 VALUES(8, "iiiii");
INSERT INTO t1 VALUES(9, "jjjjj");

SELECT * FROM t1 ORDER BY c1 LIMIT 10;

# Cleanup
DROP TABLE t1;
Loading

0 comments on commit f1a9fef

Please sign in to comment.