[Commits] 03742b4: MDEV-7796: encryption_algorithm configuration variable is static and can't be changed

Jan Lindström jan.lindstrom at mariadb.com
Tue Mar 24 09:52:48 EET 2015


revision-id: 03742b4b3a6b6e4a2de97a9753ab9889b39f733c
parent(s): 3dec5a7e4d4b376a12bbd1addb499ad47f7ca015
committer: Jan Lindström
branch nick: 10.1-innodb-bug
timestamp: 2015-03-24 09:50:01 +0200
message:

MDEV-7796: encryption_algorithm configuration variable is static and can't be changed

Step 2:
- Add function to change internal current_aes_dynamic_method by SUPER
- Add test case where used encryption algorithm is changed
- Fix bugs found on testing

---
 .../suite/innodb/r/innodb_encryption_change.result |  89 ++++++++
 .../suite/innodb/t/innodb_encryption_change.opt    |   7 +
 .../suite/innodb/t/innodb_encryption_change.test   | 229 +++++++++++++++++++++
 .../sys_vars/r/encryption_algorithm_basic.result   |   3 +
 .../sys_vars/t/encryption_algorithm_basic.test     |  27 ++-
 sql/sys_vars.cc                                    |  21 +-
 storage/xtradb/fil/fil0crypt.cc                    |   4 +
 storage/xtradb/fil/fil0pagecompress.cc             |   3 +-
 storage/xtradb/include/fil0fil.h                   |   2 -
 9 files changed, 378 insertions(+), 7 deletions(-)

diff --git a/mysql-test/suite/innodb/r/innodb_encryption_change.result b/mysql-test/suite/innodb/r/innodb_encryption_change.result
new file mode 100644
index 0000000..9010085
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_encryption_change.result
@@ -0,0 +1,89 @@
+SET @start_global_value = @@global.innodb_encryption_threads;
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+SHOW VARIABLES LIKE 'innodb_encrypt%';
+Variable_name	Value
+innodb_encrypt_log	ON
+innodb_encrypt_tables	OFF
+innodb_encryption_rotate_key_age	15
+innodb_encryption_rotation_iops	100
+innodb_encryption_threads	0
+DESCRIBE INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+Field	Type	Null	Key	Default	Extra
+SPACE	int(11) unsigned	NO		0	
+NAME	varchar(655)	YES		NULL	
+ENCRYPTION_SCHEME	int(11) unsigned	NO		0	
+KEYSERVER_REQUESTS	int(11) unsigned	NO		0	
+MIN_KEY_VERSION	int(11) unsigned	NO		0	
+CURRENT_KEY_VERSION	int(11) unsigned	NO		0	
+KEY_ROTATION_PAGE_NUMBER	bigint(21) unsigned	YES		NULL	
+KEY_ROTATION_MAX_PAGE_NUMBER	bigint(21) unsigned	YES		NULL	
+create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
+create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact;
+create table innodb_dynamic(c1 bigint not null, b char(200)) engine=innodb row_format=dynamic;
+create table innodb_compressed(c1 bigint not null, b char(200)) engine=innodb row_format=compressed;
+create table innodb_redundant(c1 bigint not null, b char(200)) engine=innodb row_format=redundant;
+create procedure innodb_insert_proc (repeat_count int)
+begin
+declare current_num int;
+set current_num = 0;
+while current_num < repeat_count do
+insert into innodb_normal values(current_num, substring(MD5(RAND()), -64));
+set current_num = current_num + 1;
+end while;
+end//
+commit;
+set autocommit=0;
+call innodb_insert_proc(2000);
+commit;
+set autocommit=1;
+insert into innodb_compact select * from innodb_normal;
+insert into innodb_dynamic select * from innodb_normal;
+insert into innodb_compressed select * from innodb_normal;
+insert into innodb_redundant select * from innodb_normal;
+" Start encrypt tablespaces
+SET GLOBAL innodb_encrypt_tables = on;
+SET GLOBAL innodb_encryption_threads = 4;
+# Wait max 5 min for key encryption threads to encrypt one space
+# Success!
+# Wait max 10 min for key encryption threads to encrypt all space
+# Success!
+# Now turn off encryption and wait for threads to decrypt everything
+SET GLOBAL innodb_encrypt_tables = off;
+set GLOBAL encryption_algorithm = aes_cbc;
+# Wait max 10 min for key encryption threads to decrypt all space
+# Success!
+# Shutdown innodb_encryption_threads
+SET GLOBAL innodb_encryption_threads=0;
+# Turn on encryption
+# since threads are off tables should remain unencrypted
+SET GLOBAL innodb_encrypt_tables = on;
+# Wait 15s to check that nothing gets encrypted
+# Success!
+# Startup innodb_encryption_threads
+SET GLOBAL innodb_encryption_threads=4;
+# Wait 1 min to check that it start encrypting again
+# Success!
+# Wait max 10 min for key encryption threads to decrypt all space
+# Success!
+SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_encrypted';
+variable_value >= 0
+1
+SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_decrypted';
+variable_value >= 0
+1
+SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_encryption_error';
+variable_value = 0
+1
+SELECT variable_value > 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_compressed';
+variable_value > 0
+0
+SELECT variable_value > 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_decompressed';
+variable_value > 0
+0
+drop procedure innodb_insert_proc;
+drop table innodb_normal;
+drop table innodb_compact;
+drop table innodb_dynamic;
+drop table innodb_compressed;
+drop table innodb_redundant;
diff --git a/mysql-test/suite/innodb/t/innodb_encryption_change.opt b/mysql-test/suite/innodb/t/innodb_encryption_change.opt
new file mode 100644
index 0000000..0839ecf
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_encryption_change.opt
@@ -0,0 +1,7 @@
+--aria-encrypt-tables=ON
+--encrypt-tmp-disk-tables=ON
+--innodb-encryption-rotate-key-age=15
+--innodb-encryption-threads=0
+--innodb-tablespaces-encryption
+--innodb-encrypt-log=ON
+
diff --git a/mysql-test/suite/innodb/t/innodb_encryption_change.test b/mysql-test/suite/innodb/t/innodb_encryption_change.test
new file mode 100644
index 0000000..6c5eab5
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_encryption_change.test
@@ -0,0 +1,229 @@
+#
+#
+#
+-- source include/have_innodb.inc
+-- source include/have_example_key_management_plugin.inc
+
+# embedded does not support restart
+-- source include/not_embedded.inc
+
+--disable_query_log
+let $orig_algorithm=`SELECT @@encryption_algorithm`;
+let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
+let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
+let $encrypt_tables_orig = `SELECT @@innodb_encrypt_tables`;
+--enable_query_log
+
+SET @start_global_value = @@global.innodb_encryption_threads;
+SET GLOBAL innodb_file_format = `Barracuda`;
+SET GLOBAL innodb_file_per_table = ON;
+
+--disable_query_log
+EVAL SET GLOBAL encryption_algorithm = $orig_algorithm;
+--enable_query_log
+
+SHOW VARIABLES LIKE 'innodb_encrypt%';
+
+DESCRIBE INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+
+create table innodb_normal(c1 bigint not null, b char(200)) engine=innodb;
+create table innodb_compact(c1 bigint not null, b char(200)) engine=innodb row_format=compact;
+create table innodb_dynamic(c1 bigint not null, b char(200)) engine=innodb row_format=dynamic;
+create table innodb_compressed(c1 bigint not null, b char(200)) engine=innodb row_format=compressed;
+create table innodb_redundant(c1 bigint not null, b char(200)) engine=innodb row_format=redundant;
+
+delimiter //;
+create procedure innodb_insert_proc (repeat_count int)
+begin
+  declare current_num int;
+  set current_num = 0;
+  while current_num < repeat_count do
+    insert into innodb_normal values(current_num, substring(MD5(RAND()), -64));
+    set current_num = current_num + 1;
+  end while;
+end//
+delimiter ;//
+commit;
+
+set autocommit=0;
+call innodb_insert_proc(2000);
+commit;
+set autocommit=1;
+
+insert into innodb_compact select * from innodb_normal;
+insert into innodb_dynamic select * from innodb_normal;
+insert into innodb_compressed select * from innodb_normal;
+insert into innodb_redundant select * from innodb_normal;
+
+--echo " Start encrypt tablespaces
+SET GLOBAL innodb_encrypt_tables = on;
+SET GLOBAL innodb_encryption_threads = 4;
+
+--echo # Wait max 5 min for key encryption threads to encrypt one space
+let $cnt=300;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION > 0`;
+    if ($success)
+    {
+        let $cnt=0;
+    }
+    if (!$success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+}
+if (!$success)
+{
+    SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+    SHOW STATUS LIKE 'innodb_encryption%';
+    -- die Timeout waiting for encryption threads
+}
+--echo # Success!
+
+--echo # Wait max 10 min for key encryption threads to encrypt all space
+let $cnt=600;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0`;
+    if ($success)
+    {
+        let $cnt=0;
+    }
+    if (!$success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+}
+if (!$success)
+{
+    SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+    SHOW STATUS LIKE 'innodb_encryption%';
+    -- die Timeout waiting for encryption threads
+}
+--echo # Success!
+
+--echo # Now turn off encryption and wait for threads to decrypt everything
+SET GLOBAL innodb_encrypt_tables = off;
+set GLOBAL encryption_algorithm = aes_cbc;
+
+--echo # Wait max 10 min for key encryption threads to decrypt all space
+let $cnt=600;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0`;
+    if ($success)
+    {
+        let $cnt=0;
+    }
+    if (!$success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+}
+if (!$success)
+{
+    SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+    SHOW STATUS LIKE 'innodb_encryption%';
+    -- die Timeout waiting for encryption threads
+}
+--echo # Success!
+
+--echo # Shutdown innodb_encryption_threads
+SET GLOBAL innodb_encryption_threads=0;
+
+--echo # Turn on encryption
+--echo # since threads are off tables should remain unencrypted
+SET GLOBAL innodb_encrypt_tables = on;
+
+--echo # Wait 15s to check that nothing gets encrypted
+let $cnt=15;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0`;
+    if ($success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+    if (!$success)
+    {
+        SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
+        -- die Failure, tablespace getting encrypted even if innodb_encryption_threads=0
+    }
+}
+--echo # Success!
+
+--echo # Startup innodb_encryption_threads
+SET GLOBAL innodb_encryption_threads=4;
+
+--echo # Wait 1 min to check that it start encrypting again
+let $cnt=60;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0 OR KEY_ROTATION_PAGE_NUMBER IS NOT NULL`;
+    if ($success)
+    {
+        let $cnt=0;
+    }
+    if (!$success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+}
+if (!$success)
+{
+    SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+    SHOW STATUS LIKE 'innodb_encryption%';
+    -- die Timeout waiting for encryption threads
+}
+--echo # Success!
+--echo # Wait max 10 min for key encryption threads to decrypt all space
+let $cnt=600;
+while ($cnt)
+{
+    let $success=`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0`;
+    if ($success)
+    {
+        let $cnt=0;
+    }
+    if (!$success)
+    {
+        real_sleep 1;
+        dec $cnt;
+    }
+}
+if (!$success)
+{
+    SELECT * FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION;
+    SHOW STATUS LIKE 'innodb_encryption%';
+    -- die Timeout waiting for encryption threads
+}
+--echo # Success!
+
+SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_encrypted';
+SELECT variable_value >= 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_decrypted';
+SELECT variable_value = 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_encryption_error';
+SELECT variable_value > 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_compressed';
+SELECT variable_value > 0 FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_num_pages_page_decompressed';
+
+drop procedure innodb_insert_proc;
+drop table innodb_normal;
+drop table innodb_compact;
+drop table innodb_dynamic;
+drop table innodb_compressed;
+drop table innodb_redundant;
+
+# reset system
+--disable_query_log
+EVAL SET GLOBAL innodb_encrypt_tables = $encrypt_tables_orig;
+SET GLOBAL innodb_encryption_threads=@start_global_value;
+EVAL SET GLOBAL encryption_algorithm = $orig_algorithm;
+EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
+EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
+--enable_query_log
+
diff --git a/mysql-test/suite/sys_vars/r/encryption_algorithm_basic.result b/mysql-test/suite/sys_vars/r/encryption_algorithm_basic.result
index c4522b5..02858af 100644
--- a/mysql-test/suite/sys_vars/r/encryption_algorithm_basic.result
+++ b/mysql-test/suite/sys_vars/r/encryption_algorithm_basic.result
@@ -3,3 +3,6 @@ select @@global.encryption_algorithm;
 none
 select @@session.encryption_algorithm;
 ERROR HY000: Variable 'encryption_algorithm' is a GLOBAL variable
+set global encryption_algorithm = aes_cbc;
+set global encryption_algorithm = aes_cbc;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
diff --git a/mysql-test/suite/sys_vars/t/encryption_algorithm_basic.test b/mysql-test/suite/sys_vars/t/encryption_algorithm_basic.test
index fec377b..8e1e190 100644
--- a/mysql-test/suite/sys_vars/t/encryption_algorithm_basic.test
+++ b/mysql-test/suite/sys_vars/t/encryption_algorithm_basic.test
@@ -1,8 +1,33 @@
-# bool global
+# enum global
 
+--disable_query_log
+let $orig_algorithm=`SELECT @@encryption_algorithm`;
+--enable_query_log
+#
 # exists as global only
 #
 select @@global.encryption_algorithm;
 --error ER_INCORRECT_GLOBAL_LOCAL_VAR
 select @@session.encryption_algorithm;
 
+set global encryption_algorithm = aes_cbc;
+
+#
+# Check changeable only by super
+#
+--source include/add_anonymous_users.inc
+
+connect (con1,localhost,user_1,,);
+connection con1;
+--error 1227
+set global encryption_algorithm = aes_cbc;
+
+connection default;
+
+--source include/delete_anonymous_users.inc
+
+# reset system
+--disable_query_log
+EVAL SET GLOBAL encryption_algorithm = $orig_algorithm;
+--enable_query_log
+
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 5130860..31b0e6f 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -63,7 +63,7 @@
 #include "opt_range.h"
 #include "rpl_parallel.h"
 #include "encryption_keys.h"
-
+#include "my_aes.h"
 /*
   The rule for this file: everything should be 'static'. When a sys_var
   variable or a function from this file is - in very rare cases - needed
@@ -5185,13 +5185,30 @@ static Sys_var_mybool Sys_encrypt_tmp_disk_tables(
        GLOBAL_VAR(encrypt_tmp_disk_tables),
        CMD_LINE(OPT_ARG), DEFAULT(FALSE));
 
+
+static bool fix_encryption_algorithm(sys_var *self, THD *thd,
+                                     enum_var_type type)
+{
+  if (my_aes_init_dynamic_encrypt((enum_my_aes_encryption_algorithm)
+                                  encryption_algorithm))
+  {
+    fprintf(stderr, "Can't initialize encryption algorithm to \"%s\".\nCheck that the program is linked with the right library (openssl?)\n",
+            encryption_algorithm_names[encryption_algorithm]);
+    return true;
+  }
+
+  return false;
+}
+
 const char *encryption_algorithm_names[]=
 { "none", "aes_cbc", "aes_ctr", 0 };
 static Sys_var_enum Sys_encryption_algorithm(
        "encryption_algorithm",
        "Which encryption algorithm to use for table encryption. aes_cbc is the recommended one.",
        GLOBAL_VAR(encryption_algorithm),CMD_LINE(REQUIRED_ARG),
-       encryption_algorithm_names, DEFAULT(0));
+       encryption_algorithm_names, DEFAULT(0),
+       NO_MUTEX_GUARD, NOT_IN_BINLOG,
+       ON_CHECK(0), ON_UPDATE(fix_encryption_algorithm));
 
 static bool check_pseudo_slave_mode(sys_var *self, THD *thd, set_var *var)
 {
diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc
index 00f5f9e..f9045ae 100644
--- a/storage/xtradb/fil/fil0crypt.cc
+++ b/storage/xtradb/fil/fil0crypt.cc
@@ -2197,6 +2197,10 @@ fil_crypt_flush_space(
 						      RW_X_LATCH, NULL, BUF_GET,
 						      __FILE__, __LINE__, &mtr);
 		byte* frame = buf_block_get_frame(block);
+		ulint maxsize;
+		crypt_data->page0_offset =
+			fsp_header_get_crypt_offset(zip_size, &maxsize);
+
 		fil_space_write_crypt_data(space, frame,
 					   crypt_data->page0_offset,
 					   ULINT_MAX, &mtr);
diff --git a/storage/xtradb/fil/fil0pagecompress.cc b/storage/xtradb/fil/fil0pagecompress.cc
index 80f55c0..2a64ef2 100644
--- a/storage/xtradb/fil/fil0pagecompress.cc
+++ b/storage/xtradb/fil/fil0pagecompress.cc
@@ -291,8 +291,7 @@ fil_compress_page(
 	if (orig_page_type == 0 ||
 	    orig_page_type == FIL_PAGE_TYPE_FSP_HDR ||
 	    orig_page_type == FIL_PAGE_TYPE_XDES ||
-	    orig_page_type == FIL_PAGE_PAGE_COMPRESSED ||
-	    orig_page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED) {
+	    orig_page_type == FIL_PAGE_PAGE_COMPRESSED) {
 		*out_len = len;
 		return (buf);
 	}
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index 705c5e9..8bc5cea 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -169,8 +169,6 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2;
 /* @} */
 
 /** File page types (values of FIL_PAGE_TYPE) @{ */
-#define FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED 35631 /* page compressed +
-						 	 	 encrypted page */
 #define FIL_PAGE_PAGE_COMPRESSED 34354  /*!< Page compressed page */
 #define FIL_PAGE_INDEX		17855	/*!< B-tree node */
 #define FIL_PAGE_UNDO_LOG	2	/*!< Undo log page */


More information about the commits mailing list