summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThirunarayanan Balathandayuthapani <thiru@mariadb.com>2019-06-21 20:26:29 +0530
committerThirunarayanan Balathandayuthapani <thiru@mariadb.com>2019-06-21 20:26:29 +0530
commitaa1469507c1f6d3890edd071175a8744cf8dacfd (patch)
tree4ff0c1faa2f1e859446ceeff1a8b2071e29354a4
parent02979daab48d871e8c43a227b8f4462128439f17 (diff)
downloadmariadb-git-bb-10.4-MDEV-17228.tar.gz
MDEV-17228 Encrypted temporary tables are not encryptedbb-10.4-MDEV-17228
- Introduce a new variable called innodb_encrypt_temporary_tables which is a boolean variable. It decides whether to encrypt the temporary tablespace. - Encrypts the temporary tablespace based on full checksum format. - Introduced a new counter to track encrypted and decrypted temporary tablespace pages. - Warnings issued if temporary table creation has conflict value with innodb_encrypt_temporary_tables - Added a new test case which reads and writes the pages from/to temporary tablespace.
-rw-r--r--mysql-test/suite/encryption/r/debug_key_management.result1
-rw-r--r--mysql-test/suite/encryption/r/innodb_encrypt_log.result1
-rw-r--r--mysql-test/suite/encryption/r/innodb_encryption.result2
-rw-r--r--mysql-test/suite/encryption/r/temp_table_encrypt.result40
-rw-r--r--mysql-test/suite/encryption/t/innodb_encrypt_log.test2
-rw-r--r--mysql-test/suite/encryption/t/temp_table_encrypt.opt2
-rw-r--r--mysql-test/suite/encryption/t/temp_table_encrypt.test40
-rw-r--r--mysql-test/suite/sys_vars/r/sysvars_innodb.result14
-rw-r--r--storage/innobase/buf/buf0buf.cc62
-rw-r--r--storage/innobase/buf/buf0flu.cc10
-rw-r--r--storage/innobase/fil/fil0crypt.cc64
-rw-r--r--storage/innobase/handler/ha_innodb.cc23
-rw-r--r--storage/innobase/include/fil0crypt.h20
-rw-r--r--storage/innobase/include/log0crypt.h11
-rw-r--r--storage/innobase/include/srv0srv.h13
-rw-r--r--storage/innobase/log/log0crypt.cc46
-rw-r--r--storage/innobase/srv/srv0srv.cc10
-rw-r--r--storage/innobase/srv/srv0start.cc4
18 files changed, 344 insertions, 21 deletions
diff --git a/mysql-test/suite/encryption/r/debug_key_management.result b/mysql-test/suite/encryption/r/debug_key_management.result
index c06d2bb3965..911a369f0c6 100644
--- a/mysql-test/suite/encryption/r/debug_key_management.result
+++ b/mysql-test/suite/encryption/r/debug_key_management.result
@@ -4,6 +4,7 @@ show variables like 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables ON
+innodb_encrypt_temporary_tables OFF
innodb_encryption_rotate_key_age 2
innodb_encryption_rotation_iops 100
innodb_encryption_threads 4
diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_log.result b/mysql-test/suite/encryption/r/innodb_encrypt_log.result
index d0c17ed09ae..9c3f7f29320 100644
--- a/mysql-test/suite/encryption/r/innodb_encrypt_log.result
+++ b/mysql-test/suite/encryption/r/innodb_encrypt_log.result
@@ -5,6 +5,7 @@
# MDEV-9422 Encrypted redo log checksum errors
# on restart after killing busy server instance
#
+call mtr.add_suppression("InnoDB: InnoDB: Ignoring encryption parameter during temporary table creation.");
SET GLOBAL innodb_log_checksums=0;
Warnings:
Warning 138 innodb_encrypt_log implies innodb_log_checksums
diff --git a/mysql-test/suite/encryption/r/innodb_encryption.result b/mysql-test/suite/encryption/r/innodb_encryption.result
index ab31eed5cf2..4ede82ebd38 100644
--- a/mysql-test/suite/encryption/r/innodb_encryption.result
+++ b/mysql-test/suite/encryption/r/innodb_encryption.result
@@ -3,6 +3,7 @@ SHOW VARIABLES LIKE 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables ON
+innodb_encrypt_temporary_tables OFF
innodb_encryption_rotate_key_age 15
innodb_encryption_rotation_iops 100
innodb_encryption_threads 4
@@ -58,6 +59,7 @@ SHOW VARIABLES LIKE 'innodb_encrypt%';
Variable_name Value
innodb_encrypt_log ON
innodb_encrypt_tables OFF
+innodb_encrypt_temporary_tables OFF
innodb_encryption_rotate_key_age 15
innodb_encryption_rotation_iops 100
innodb_encryption_threads 0
diff --git a/mysql-test/suite/encryption/r/temp_table_encrypt.result b/mysql-test/suite/encryption/r/temp_table_encrypt.result
new file mode 100644
index 00000000000..b020452bb1b
--- /dev/null
+++ b/mysql-test/suite/encryption/r/temp_table_encrypt.result
@@ -0,0 +1,40 @@
+CREATE TEMPORARY TABLE t1(f1 CHAR(200), f2 CHAR(200)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES("mysql", "database"), ("mariadb", "database");
+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;
+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;
+CREATE TEMPORARY TABLE t2(f1 CHAR(100), f2 CHAR(200), f3 CHAR(200))ENGINE=InnoDB;
+INSERT INTO t2 VALUES ("mysql", "mysql", "mysql"), ("mariadb", "mariadb", "mariadb");
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+4096
+SELECT variable_value > 0 FROM information_schema.global_status
+WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted';
+variable_value > 0
+1
+SELECT variable_value > 0 FROM information_schema.global_status
+WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted';
+variable_value > 0
+1
+# restart
diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_log.test b/mysql-test/suite/encryption/t/innodb_encrypt_log.test
index 4b3d92e876c..e43826a3a91 100644
--- a/mysql-test/suite/encryption/t/innodb_encrypt_log.test
+++ b/mysql-test/suite/encryption/t/innodb_encrypt_log.test
@@ -13,6 +13,8 @@
--let $MYSQLD_DATADIR=`select @@datadir`
+call mtr.add_suppression("InnoDB: InnoDB: Ignoring encryption parameter during temporary table creation.");
+
SET GLOBAL innodb_log_checksums=0;
SELECT @@global.innodb_log_checksums;
diff --git a/mysql-test/suite/encryption/t/temp_table_encrypt.opt b/mysql-test/suite/encryption/t/temp_table_encrypt.opt
new file mode 100644
index 00000000000..70797302d01
--- /dev/null
+++ b/mysql-test/suite/encryption/t/temp_table_encrypt.opt
@@ -0,0 +1,2 @@
+--innodb_buffer_pool_size=5M
+--innodb_encrypt_temporary_tables=1
diff --git a/mysql-test/suite/encryption/t/temp_table_encrypt.test b/mysql-test/suite/encryption/t/temp_table_encrypt.test
new file mode 100644
index 00000000000..64ab11bab0a
--- /dev/null
+++ b/mysql-test/suite/encryption/t/temp_table_encrypt.test
@@ -0,0 +1,40 @@
+--source include/have_innodb.inc
+--source include/have_file_key_management_plugin.inc
+
+CREATE TEMPORARY TABLE t1(f1 CHAR(200), f2 CHAR(200)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES("mysql", "database"), ("mariadb", "database");
+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;
+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;
+
+CREATE TEMPORARY TABLE t2(f1 CHAR(100), f2 CHAR(200), f3 CHAR(200))ENGINE=InnoDB;
+INSERT INTO t2 VALUES ("mysql", "mysql", "mysql"), ("mariadb", "mariadb", "mariadb");
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+INSERT INTO t2 SELECT * FROM t2;
+
+SELECT COUNT(*) FROM t1;
+SELECT variable_value > 0 FROM information_schema.global_status
+WHERE variable_name = 'innodb_encryption_n_temp_blocks_encrypted';
+
+SELECT variable_value > 0 FROM information_schema.global_status
+WHERE variable_name = 'innodb_encryption_n_temp_blocks_decrypted';
+--source include/restart_mysqld.inc
diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
index 159d8ca7ae1..65435e4dc48 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result
@@ -876,6 +876,20 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON,FORCE
READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL
+VARIABLE_NAME INNODB_ENCRYPT_TEMPORARY_TABLES
+SESSION_VALUE NULL
+GLOBAL_VALUE OFF
+GLOBAL_VALUE_ORIGIN COMPILE-TIME
+DEFAULT_VALUE OFF
+VARIABLE_SCOPE GLOBAL
+VARIABLE_TYPE BOOLEAN
+VARIABLE_COMMENT Enable the variable to encrypt the temporary tablespace data.
+NUMERIC_MIN_VALUE NULL
+NUMERIC_MAX_VALUE NULL
+NUMERIC_BLOCK_SIZE NULL
+ENUM_VALUE_LIST OFF,ON
+READ_ONLY YES
+COMMAND_LINE_ARGUMENT NONE
VARIABLE_NAME INNODB_FAST_SHUTDOWN
SESSION_VALUE NULL
GLOBAL_VALUE 1
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index dc83db7fc95..632081e2de6 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -496,6 +496,22 @@ static bool buf_page_decrypt_after_read(buf_page_t* bpage, fil_space_t* space)
tablespace and page contains used key_version. This is true
also for pages first compressed and then encrypted. */
+ if (space->purpose == FIL_TYPE_TEMPORARY
+ && srv_encrypt_temp_space) {
+ buf_tmp_buffer_t* slot = buf_pool_reserve_tmp_slot(buf_pool);
+ buf_tmp_reserve_crypt_buf(slot);
+
+ if (buf_page_is_zeroes(dst_frame, srv_page_size)) {
+ } else if (!fil_tmp_space_decrypt(slot->crypt_buf, dst_frame)) {
+ ib::error() << "Encrypted page " << bpage->id
+ << " in file " << space->chain.start->name;
+ return false;
+ }
+
+ slot->release();
+ return true;
+ }
+
buf_tmp_buffer_t* slot;
uint key_version = buf_page_get_key_version(dst_frame, space->flags);
@@ -5916,9 +5932,19 @@ static dberr_t buf_page_check_corrupt(buf_page_t* bpage, fil_space_t* space)
if (!still_encrypted) {
/* If traditional checksums match, we assume that page is
not anymore encrypted. */
- if (space->full_crc32()
- && !buf_page_is_zeroes(dst_frame, space->physical_size())
- && (key_version || space->is_compressed())) {
+
+ if (space->purpose == FIL_TYPE_TEMPORARY
+ && srv_encrypt_temp_space) {
+
+ if (buf_page_is_zeroes(dst_frame, srv_page_size)) {
+ corrupted = false;
+ } else {
+ corrupted = buf_page_full_crc32_is_corrupted(
+ space->id, dst_frame, false);
+ }
+ } else if (space->full_crc32()
+ && !buf_page_is_zeroes(dst_frame, space->physical_size())
+ && (key_version || space->is_compressed())) {
corrupted = buf_page_full_crc32_is_corrupted(
space->id, dst_frame,
space->is_compressed());
@@ -7386,7 +7412,7 @@ buf_page_encrypt(
fil_space_crypt_t* crypt_data = space->crypt_data;
- const bool encrypted = crypt_data
+ bool encrypted = crypt_data
&& !crypt_data->not_encrypted()
&& crypt_data->type != CRYPT_SCHEME_UNENCRYPTED
&& (!crypt_data->is_default_encryption()
@@ -7394,6 +7420,11 @@ buf_page_encrypt(
bool page_compressed = space->is_compressed();
+ if (space->purpose == FIL_TYPE_TEMPORARY
+ && srv_encrypt_temp_space) {
+ encrypted = true;
+ }
+
if (!encrypted && !page_compressed) {
/* No need to encrypt or page compress the page.
Clear key-version & crypt-checksum. */
@@ -7418,7 +7449,7 @@ buf_page_encrypt(
byte *dst_frame = slot->crypt_buf;
const bool full_crc32 = space->full_crc32();
- if (full_crc32) {
+ if (full_crc32 || space->purpose == FIL_TYPE_TEMPORARY) {
/* Write LSN for the full crc32 checksum before
encryption. Because lsn is one of the input for encryption. */
mach_write_to_8(src_frame + FIL_PAGE_LSN,
@@ -7432,18 +7463,27 @@ buf_page_encrypt(
if (!page_compressed) {
not_compressed:
- /* Encrypt page content */
- byte* tmp = fil_space_encrypt(space,
- bpage->id.page_no(),
- bpage->newest_modification,
- src_frame,
- dst_frame);
+ byte* tmp;
+ if (space->purpose == FIL_TYPE_TEMPORARY) {
+ /** Encrypt temporary page content */
+ tmp = fil_tmp_space_encrypt(bpage->id.page_no(),
+ src_frame, dst_frame);
+ } else {
+ /* Encrypt page content */
+ tmp = fil_space_encrypt(
+ space,
+ bpage->id.page_no(),
+ bpage->newest_modification,
+ src_frame,
+ dst_frame);
+ }
bpage->real_size = srv_page_size;
slot->out_buf = dst_frame = tmp;
ut_d(fil_page_type_validate(space, tmp));
} else {
+ ut_ad(space->purpose != FIL_TYPE_TEMPORARY);
/* First we compress the page content */
buf_tmp_reserve_compression_buf(slot);
byte* tmp = slot->comp_buf;
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 373f6eb4539..d5410f6ad59 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -967,7 +967,9 @@ buf_flush_write_block_low(
== (space == fil_system.temp_space));
page_t* frame = NULL;
- const bool full_crc32 = space->full_crc32();
+ const bool full_crc32 = (space->full_crc32()
+ || (space->purpose == FIL_TYPE_TEMPORARY
+ && srv_encrypt_temp_space));
#ifdef UNIV_DEBUG
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
@@ -1130,7 +1132,11 @@ buf_flush_page(
rw_lock_t* rw_lock;
bool no_fix_count = bpage->buf_fix_count == 0;
- if (!is_uncompressed) {
+ if (fsp_is_system_temporary(bpage->id.space())
+ && srv_shutdown_state != SRV_SHUTDOWN_NONE) {
+ flush = FALSE;
+ buf_flush_remove(bpage);
+ } else if (!is_uncompressed) {
flush = TRUE;
rw_lock = NULL;
} else if (!(no_fix_count || flush_type == BUF_FLUSH_LIST)
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index 44cc9daa508..c43f8af6ebd 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -40,6 +40,7 @@ Modified Jan Lindström jan.lindstrom@mariadb.com
#include "fsp0fsp.h"
#include "fil0pagecompress.h"
#include <my_crypt.h>
+#include "log0crypt.h"
/** Mutex for keys */
static ib_mutex_t fil_crypt_key_mutex;
@@ -699,6 +700,37 @@ static bool fil_space_encrypt_valid_page_type(
return true;
}
+/** Encrypt a buffer of temporary tablespace
+@param[in] offset Page offset
+@param[in] src_frame Page to encrypt
+@param[in,out] dst_frame Output buffer
+@return encrypted buffer or NULL */
+UNIV_INTERN
+byte* fil_tmp_space_encrypt(
+ ulint offset,
+ byte* src_frame,
+ byte* dst_frame)
+{
+ uint srclen = uint(srv_page_size) -
+ (FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
+ + FIL_PAGE_FCRC32_CHECKSUM);
+ const byte* src = src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION;
+ byte* dst = dst_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION;
+
+ /* Till FIL_PAGE_LSN, page is not encrypted */
+ memcpy(dst_frame, src_frame, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
+
+ if (!log_tmp_block_encrypt(src, srclen, dst, (offset * srv_page_size),
+ SRV_TMP_SPACE_ID, true, true)) {
+ return NULL;
+ }
+
+ const ulint payload = srv_page_size - FIL_PAGE_FCRC32_CHECKSUM;
+ mach_write_to_4(dst_frame + payload, ut_crc32(dst_frame, payload));
+ srv_stats.pages_encrypted.inc();
+ return dst_frame;
+}
+
/******************************************************************
Encrypt a page
@@ -795,6 +827,38 @@ fil_space_encrypt(
return tmp;
}
+/** Decrypt a page for temporary tablespace.
+@param[in,out] tmp_frame Temporary buffer
+@param[in] src_frame Page to decrypt
+@return true if temporary tablespace decrypted, false if not */
+bool fil_tmp_space_decrypt(
+ byte* tmp_frame,
+ byte* src_frame)
+{
+ memcpy(tmp_frame, src_frame, FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION);
+
+ /* Calculate the offset where decryption starts */
+ ulint offset = mach_read_from_4(src_frame + FIL_PAGE_OFFSET);
+ const byte* src = src_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION;
+ byte* dst = tmp_frame + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION;
+ uint srclen = uint(srv_page_size) -
+ (FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION
+ + FIL_PAGE_FCRC32_CHECKSUM);
+
+ if (!log_tmp_block_encrypt(src, srclen, dst, (offset * srv_page_size),
+ SRV_TMP_SPACE_ID, false, true)) {
+ return false;
+ }
+
+ memcpy(tmp_frame + srv_page_size - FIL_PAGE_FCRC32_CHECKSUM,
+ src_frame + srv_page_size - FIL_PAGE_FCRC32_CHECKSUM,
+ FIL_PAGE_FCRC32_CHECKSUM);
+
+ srv_stats.pages_decrypted.inc();
+ memcpy(src_frame, tmp_frame, srv_page_size);
+ return true;
+}
+
/** Decrypt a page for full checksum format.
@param[in] space space id
@param[in] crypt_data crypt_data
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 88ea6f5e642..e191d91b313 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1150,6 +1150,12 @@ static SHOW_VAR innodb_status_variables[]= {
{"encryption_n_rowlog_blocks_decrypted",
(char*)&export_vars.innodb_n_rowlog_blocks_decrypted,
SHOW_LONGLONG},
+ {"encryption_n_temp_blocks_encrypted",
+ (char*)&export_vars.innodb_n_temp_blocks_encrypted,
+ SHOW_LONGLONG},
+ {"encryption_n_temp_blocks_decrypted",
+ (char*)&export_vars.innodb_n_temp_blocks_decrypted,
+ SHOW_LONGLONG},
/* scrubing */
{"scrub_background_page_reorganizations",
@@ -3792,8 +3798,8 @@ static int innodb_init_params()
}
#endif
- if ((srv_encrypt_tables || srv_encrypt_log)
- && !encryption_key_id_exists(FIL_DEFAULT_ENCRYPTION_KEY)) {
+ if ((srv_encrypt_tables || srv_encrypt_log || srv_encrypt_temp_space)
+ && !encryption_key_id_exists(FIL_DEFAULT_ENCRYPTION_KEY)) {
sql_print_error("InnoDB: cannot enable encryption, "
"encryption plugin is not available");
DBUG_RETURN(HA_ERR_INITIALIZATION);
@@ -11150,6 +11156,13 @@ err_col:
dict_table_add_system_columns(table, heap);
if (table->is_temporary()) {
+
+ if ((options->encryption == 1 && !srv_encrypt_temp_space)
+ || (options->encryption == 2 && srv_encrypt_temp_space)) {
+ ib::warn() << "InnoDB: Ignoring encryption parameter "
+ "during temporary table creation.";
+ }
+
m_trx->table_id = table->id
= dict_sys.get_temporary_table_id();
ut_ad(dict_tf_get_rec_format(table->flags)
@@ -19635,6 +19648,11 @@ static MYSQL_SYSVAR_ULONG(buf_dump_status_frequency, srv_buf_dump_status_frequen
"dumped. Default is 0 (only start and end status is printed).",
NULL, NULL, 0, 0, 100, 0);
+static MYSQL_SYSVAR_BOOL(encrypt_temporary_tables, srv_encrypt_temp_space,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Enable the variable to encrypt the temporary tablespace data.",
+ NULL, NULL, FALSE);
+
#ifdef WITH_INNODB_DISALLOW_WRITES
/*******************************************************
* innobase_disallow_writes variable definition *
@@ -20161,6 +20179,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
#endif
MYSQL_SYSVAR(buf_dump_status_frequency),
MYSQL_SYSVAR(background_thread),
+ MYSQL_SYSVAR(encrypt_temporary_tables),
NULL
};
diff --git a/storage/innobase/include/fil0crypt.h b/storage/innobase/include/fil0crypt.h
index 7a54cb4d53f..ce6fb4c9039 100644
--- a/storage/innobase/include/fil0crypt.h
+++ b/storage/innobase/include/fil0crypt.h
@@ -325,9 +325,18 @@ fil_encrypt_buf(
bool use_full_checksum)
MY_ATTRIBUTE((warn_unused_result));
-/**
-Encrypt a page.
+/** Encrypt a buffer of temporary tablespace
+@param[in] offset Page offset
+@param[in] src_frame Page to encrypt
+@param[in,out] dst_frame Output buffer
+@return encrypted buffer or NULL */
+UNIV_INTERN
+byte* fil_tmp_space_encrypt(
+ ulint offset,
+ byte* src_frame,
+ byte* dst_frame);
+/** Encrypt a page.
@param[in] space Tablespace
@param[in] offset Page offset
@param[in] lsn Log sequence number
@@ -344,6 +353,13 @@ fil_space_encrypt(
byte* dst_frame)
MY_ATTRIBUTE((warn_unused_result));
+/** Decrypt a page for temporary tablespace.
+@param[in,out] tmp_frame Temporary buffer
+@param[in] src_frame Page to decrypt
+@return true if temporary tablespace decrypted, false if not */
+bool fil_tmp_space_decrypt(
+ byte* tmp_frame,
+ byte* src_frame);
/** Decrypt a page.
@param]in] space_id space id
diff --git a/storage/innobase/include/log0crypt.h b/storage/innobase/include/log0crypt.h
index c54a369ff47..2cd28e505a1 100644
--- a/storage/innobase/include/log0crypt.h
+++ b/storage/innobase/include/log0crypt.h
@@ -42,6 +42,12 @@ UNIV_INTERN
bool
log_crypt_init();
+/** Initialize the temporary tablespace encryption key and random
+parameters when creating new temporary tablespace.
+@return whether the operation succeeded */
+UNIV_INTERN
+bool log_tmp_crypt_init();
+
/*********************************************************************//**
Writes the crypto (version, msg and iv) info, which has been used for
log blocks with lsn <= this checkpoint's lsn, to a log header's
@@ -98,6 +104,8 @@ bool log_crypt(byte* buf, lsn_t lsn, ulint size, log_crypt_t op = LOG_ENCRYPT);
@param[in] offs offset to block
@param[in] space_id tablespace id
@param[in] encrypt true=encrypt; false=decrypt
+@param[in] temp_space temporary tablespace; so use
+ tmp_info.key
@return whether the operation succeeded */
UNIV_INTERN
bool
@@ -107,7 +115,8 @@ log_tmp_block_encrypt(
byte* dst,
uint64_t offs,
ulint space_id,
- bool encrypt = true)
+ bool encrypt = true,
+ bool temp_space = false)
MY_ATTRIBUTE((warn_unused_result, nonnull));
/** Decrypt a temporary file block.
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 6494365b69f..7a991f26aa6 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -184,6 +184,12 @@ struct srv_stats_t
/** Number of spaces in keyrotation list */
ulint_ctr_64_t key_rotation_list_length;
+
+ /** Number of temporary tablespace blocks encrypted */
+ ulint_ctr_64_t n_temp_blocks_encrypted;
+
+ /** Number of temporary tablespace blocks decrypted */
+ ulint_ctr_64_t n_temp_blocks_decrypted;
};
extern const char* srv_main_thread_op_info;
@@ -472,6 +478,7 @@ extern ulong srv_max_purge_lag;
extern ulong srv_max_purge_lag_delay;
extern ulong srv_replication_delay;
+extern my_bool srv_encrypt_temp_space;
/*-------------------------------------------*/
/** Modes of operation */
@@ -1020,6 +1027,12 @@ struct export_var_t{
/*!< Number of row log blocks decrypted */
ib_int64_t innodb_n_rowlog_blocks_decrypted;
+ /* Number of temporary tablespace pages encrypted */
+ ib_int64_t innodb_n_temp_blocks_encrypted;
+
+ /* Number of temporary tablespace pages decrypted */
+ ib_int64_t innodb_n_temp_blocks_decrypted;
+
ulint innodb_sec_rec_cluster_reads; /*!< srv_sec_rec_cluster_reads */
ulint innodb_sec_rec_cluster_reads_avoided;/*!< srv_sec_rec_cluster_reads_avoided */
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index b088c9af09d..82c9366b217 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -32,6 +32,7 @@ MDEV-11782: Rewritten for MariaDB 10.2 by Marko Mäkelä, MariaDB Corporation.
#include "log0crypt.h"
#include "srv0start.h" // for srv_start_lsn
#include "log0recv.h" // for recv_sys
+#include "srv0srv.h"
/** innodb_encrypt_log: whether to encrypt the redo log */
my_bool srv_encrypt_log;
@@ -63,6 +64,9 @@ struct crypt_info_t {
} crypt_nonce;
};
+/** Crypt info for the temporary tablespace */
+static crypt_info_t tmp_info;
+
/** The crypt info */
static crypt_info_t info;
@@ -266,6 +270,29 @@ log_crypt_init()
return init_crypt_key(&info);
}
+UNIV_INTERN
+bool
+log_tmp_crypt_init()
+{
+ tmp_info.key_version = encryption_key_get_latest_version(1);
+
+ if (tmp_info.key_version == ENCRYPTION_KEY_VERSION_INVALID) {
+ ib::error() << "innodb_encrypt_temporary_tables: cannot get "
+ "key version";
+ tmp_info.key_version = 0;
+ return false;
+ }
+
+ if (my_random_bytes(tmp_info.crypt_msg.bytes, MY_AES_BLOCK_SIZE)
+ != MY_AES_OK) {
+ ib::error() << "innodb_encrypt_temporary_tables: "
+ "my_random_bytes() failed";
+ return false;
+ }
+
+ return init_crypt_key(&tmp_info);
+}
+
/** Read the MariaDB 10.1 checkpoint crypto (version, msg and iv) info.
@param[in] buf checkpoint buffer
@return whether the operation was successful */
@@ -424,6 +451,8 @@ log_crypt_read_checkpoint_buf(const byte* buf)
@param[in] offs offset to block
@param[in] space_id tablespace id
@param[in] encrypt true=encrypt; false=decrypt
+@param[in] temp_space temporary tablespace; so use
+ tmp_info.key
@return whether the operation succeeded */
UNIV_INTERN
bool
@@ -433,7 +462,8 @@ log_tmp_block_encrypt(
byte* dst,
uint64_t offs,
ulint space_id,
- bool encrypt)
+ bool encrypt,
+ bool temp_space)
{
uint dst_len;
uint64_t aes_ctr_iv[MY_AES_BLOCK_SIZE / sizeof(uint64_t)];
@@ -443,17 +473,27 @@ log_tmp_block_encrypt(
int rc = encryption_crypt(
src, (uint)size, dst, &dst_len,
- info.crypt_key.bytes, MY_AES_BLOCK_SIZE,
+ temp_space ? tmp_info.crypt_key.bytes : info.crypt_key.bytes,
+ MY_AES_BLOCK_SIZE,
reinterpret_cast<byte*>(aes_ctr_iv), (uint)(sizeof aes_ctr_iv),
encrypt
? ENCRYPTION_FLAG_ENCRYPT|ENCRYPTION_FLAG_NOPAD
: ENCRYPTION_FLAG_DECRYPT|ENCRYPTION_FLAG_NOPAD,
- LOG_DEFAULT_ENCRYPTION_KEY, info.key_version);
+ LOG_DEFAULT_ENCRYPTION_KEY,
+ temp_space ? tmp_info.key_version: info.key_version);
if (rc != MY_AES_OK) {
ib::error() << (encrypt ? "Encryption" : "Decryption")
<< " failed for temporary file: " << rc;
}
+ if (temp_space) {
+ if (encrypt) {
+ srv_stats.n_temp_blocks_encrypted.inc();
+ } else {
+ srv_stats.n_temp_blocks_decrypted.inc();
+ }
+ }
+
return rc == MY_AES_OK;
}
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index ace166273a6..a6274ccfc5d 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -423,6 +423,10 @@ my_bool srv_print_innodb_lock_monitor;
PRIMARY KEY */
my_bool srv_force_primary_key;
+/** innodb_encrypt_temporary_tables; whether to encrypt the temporary
+tablespace */
+my_bool srv_encrypt_temp_space;
+
/* Array of English strings describing the current state of an
i/o handler thread */
@@ -1600,6 +1604,12 @@ srv_export_innodb_status(void)
export_vars.innodb_sec_rec_cluster_reads_avoided =
srv_stats.n_sec_rec_cluster_reads_avoided;
+ export_vars.innodb_n_temp_blocks_encrypted =
+ srv_stats.n_temp_blocks_encrypted;
+
+ export_vars.innodb_n_temp_blocks_decrypted =
+ srv_stats.n_temp_blocks_decrypted;
+
if (!srv_read_only_mode) {
export_vars.innodb_encryption_rotation_pages_read_from_cache =
crypt_stat.pages_read_from_cache;
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 328f1d209a5..69b83db9e96 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -995,6 +995,10 @@ srv_open_tmp_tablespace(bool create_new_db)
srv_tmp_space.delete_files();
srv_tmp_space.set_ignore_read_only(true);
+ if (srv_encrypt_temp_space && !log_tmp_crypt_init()) {
+ return DB_ERROR;
+ }
+
ib::info() << "Creating shared tablespace for temporary tables";
bool create_new_temp_space;