diff options
author | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-06-21 20:26:29 +0530 |
---|---|---|
committer | Thirunarayanan Balathandayuthapani <thiru@mariadb.com> | 2019-06-21 20:26:29 +0530 |
commit | aa1469507c1f6d3890edd071175a8744cf8dacfd (patch) | |
tree | 4ff0c1faa2f1e859446ceeff1a8b2071e29354a4 | |
parent | 02979daab48d871e8c43a227b8f4462128439f17 (diff) | |
download | mariadb-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.result | 1 | ||||
-rw-r--r-- | mysql-test/suite/encryption/r/innodb_encrypt_log.result | 1 | ||||
-rw-r--r-- | mysql-test/suite/encryption/r/innodb_encryption.result | 2 | ||||
-rw-r--r-- | mysql-test/suite/encryption/r/temp_table_encrypt.result | 40 | ||||
-rw-r--r-- | mysql-test/suite/encryption/t/innodb_encrypt_log.test | 2 | ||||
-rw-r--r-- | mysql-test/suite/encryption/t/temp_table_encrypt.opt | 2 | ||||
-rw-r--r-- | mysql-test/suite/encryption/t/temp_table_encrypt.test | 40 | ||||
-rw-r--r-- | mysql-test/suite/sys_vars/r/sysvars_innodb.result | 14 | ||||
-rw-r--r-- | storage/innobase/buf/buf0buf.cc | 62 | ||||
-rw-r--r-- | storage/innobase/buf/buf0flu.cc | 10 | ||||
-rw-r--r-- | storage/innobase/fil/fil0crypt.cc | 64 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 23 | ||||
-rw-r--r-- | storage/innobase/include/fil0crypt.h | 20 | ||||
-rw-r--r-- | storage/innobase/include/log0crypt.h | 11 | ||||
-rw-r--r-- | storage/innobase/include/srv0srv.h | 13 | ||||
-rw-r--r-- | storage/innobase/log/log0crypt.cc | 46 | ||||
-rw-r--r-- | storage/innobase/srv/srv0srv.cc | 10 | ||||
-rw-r--r-- | storage/innobase/srv/srv0start.cc | 4 |
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; |