Commit 3e55ef26 authored by Jan Lindström's avatar Jan Lindström

MDEV-8173: InnoDB; Failing assertion: crypt_data->type == 1

Make sure that when we publish the crypt_data we access the
memory cache of the tablespace crypt_data. Make sure that
crypt_data is stored whenever it is really needed.

All this is not yet enough in my opinion because:

sql/encryption.cc has DBUG_ASSERT(scheme->type == 1) i.e.
crypt_data->type == CRYPT_SCHEME_1

However, for InnoDB point of view we have global crypt_data
for every tablespace. When we change variables on crypt_data
we take mutex. However, when we use crypt_data for
encryption/decryption we use pointer to this global
structure and no mutex to protect against changes on
crypt_data.

Tablespace encryption starts in fil_crypt_start_encrypting_space
from crypt_data that has crypt_data->type = CRYPT_SCHEME_UNENCRYPTED
and later we write page 0 CRYPT_SCHEME_1 and finally whe publish
that to memory cache.
parent 44cd6f22
......@@ -3,3 +3,15 @@ CREATE TABLE t1 (pk INT PRIMARY KEY, c VARCHAR(256));
CREATE TABLE t2 AS SELECT * FROM t1;
drop table t1,t2;
SET GLOBAL innodb_encryption_threads = 0;
SET GLOBAL innodb_encryption_threads = 4;
CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3);
CREATE TABLE `table1_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int,key (`col_int_key` ), primary key (pk)) engine=innodb;
CREATE TABLE `table0_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table1_int_autoinc VALUES (4, NULL, NULL);
INSERT IGNORE INTO `table0_int_autoinc` ( `col_int_key` ) VALUES ( 1 ), ( 3 ), ( 4 ), ( 1 );
INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ), ( 9 );
INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 );
drop table if exists create_or_replace_t, table1_int_autoinc, table0_int_autoinc, table10_int_autoinc;
SET GLOBAL innodb_encryption_threads = 0;
SET GLOBAL innodb_encrypt_tables = OFF;
......@@ -33,4 +33,77 @@ dec $i;
--enable_query_log
drop table t1,t2;
SET GLOBAL innodb_encryption_threads = 0;
\ No newline at end of file
SET GLOBAL innodb_encryption_threads = 0;
#
# MDEV-8173: InnoDB; Failing assertion: crypt_data->type == 1
#
SET GLOBAL innodb_encryption_threads = 4;
CREATE TABLE `table10_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table10_int_autoinc VALUES (NULL, NULL, -474021888) , (1, NULL, NULL) , (1141047296, NULL, NULL) , (NULL, NULL, NULL) , (NULL, NULL, 1) , (NULL, NULL, 9) , (0, NULL, 1225785344) , (NULL, NULL, 1574174720) , (2, NULL, NULL) , (6, NULL, 3);
CREATE TABLE `table1_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int,key (`col_int_key` ), primary key (pk)) engine=innodb;
CREATE TABLE `table0_int_autoinc` (`col_int_key` int, pk int auto_increment, `col_int` int, key (`col_int_key` ),primary key (pk)) engine=innodb;
INSERT /*! IGNORE */ INTO table1_int_autoinc VALUES (4, NULL, NULL);
INSERT IGNORE INTO `table0_int_autoinc` ( `col_int_key` ) VALUES ( 1 ), ( 3 ), ( 4 ), ( 1 );
INSERT IGNORE INTO `table1_int_autoinc` ( `col_int` ) VALUES ( 1 ), ( 0 ), ( 7 ), ( 9 );
INSERT IGNORE INTO `table10_int_autoinc` ( `col_int` ) VALUES ( 6 ), ( 2 ), ( 3 ), ( 6 );
--connect (con1,localhost,root,,test)
--connect (con2,localhost,root,,test)
--disable_abort_on_error
--disable_warnings
--disable_query_log
let $i = 500;
while ($i)
{
connection con1;
send SET GLOBAL innodb_encrypt_tables = ON;
connection default;
CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table1_int_autoinc`;
connection con2;
send CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table10_int_autoinc`;
connection default;
send CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table0_int_autoinc`;
connection con1;
--reap;
send SET GLOBAL innodb_encrypt_tables = OFF;
connection con2;
--reap;
connection default;
--reap;
send CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table1_int_autoinc`;
connection con2;
send CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table10_int_autoinc`;
connection con1;
--reap;
send SET GLOBAL innodb_encrypt_tables = ON;
connection default;
--reap;
send CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table1_int_autoinc`;
connection con2;
--reap;
CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table10_int_autoinc`;
CREATE OR REPLACE TABLE `create_or_replace_t` AS SELECT * FROM `table0_int_autoinc`;
connection con1;
--reap;
connection default;
--reap;
dec $i;
}
--enable_query_log
connection default;
drop table if exists create_or_replace_t, table1_int_autoinc, table0_int_autoinc, table10_int_autoinc;
--disconnect con1
--disconnect con2
--enable_abort_on_error
--enable_warnings
SET GLOBAL innodb_encryption_threads = 0;
SET GLOBAL innodb_encrypt_tables = OFF;
......@@ -169,7 +169,13 @@ int do_crypt(const unsigned char* src, unsigned int slen,
compile_time_assert(ENCRYPTION_SCHEME_KEY_INVALID ==
(int)ENCRYPTION_KEY_VERSION_INVALID);
DBUG_ASSERT(scheme->type == 1);
// Maybe temporal solution for MDEV-8173
// Rationale: scheme->type is currently global/object
// and when used here might not represent actual state
// of smaller granularity objects e.g. InnoDB page state
// as type is stored to tablespace (FIL) and could represent
// state where key rotation is trying to reach
//DBUG_ASSERT(scheme->type == 1);
if (key_version == ENCRYPTION_KEY_VERSION_INVALID ||
key_version == ENCRYPTION_KEY_NOT_ENCRYPTED)
......
......@@ -4334,7 +4334,7 @@ corrupt:
"InnoDB: space %lu file %s read of page %lu.\n"
"InnoDB: You may have to recover"
" from a backup.\n",
bpage->space,
(ulint)bpage->space,
space ? space->name : "NULL",
(ulong) bpage->offset);
buf_page_print(frame, buf_page_get_zip_size(bpage),
......
......@@ -266,13 +266,8 @@ fil_space_read_crypt_data(
ulint offset) /*!< in: offset */
{
if (memcmp(page + offset, EMPTY_PATTERN, MAGIC_SZ) == 0) {
/* crypt is not stored but create memory cache for
not system tablespace */
if (space != 0) {
return fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);
} else {
return NULL;
}
/* Crypt data is not stored. */
return NULL;
}
if (memcmp(page + offset, CRYPT_MAGIC, MAGIC_SZ) != 0) {
......@@ -288,12 +283,8 @@ fil_space_read_crypt_data(
page[offset + 3],
page[offset + 4],
page[offset + 5]);
/* Create memory cache for not system tablespace */
if (space != 0) {
return fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);
} else {
return NULL;
}
/* Create data is not stored. */
return NULL;
}
ulint type = mach_read_from_1(page + offset + MAGIC_SZ + 0);
......@@ -461,12 +452,6 @@ fil_space_write_crypt_data(
return;
}
/* If tablespace encryption is disabled and encryption mode is
DEFAULT, then do not continue writing crypt data to page 0. */
if (!srv_encrypt_tables && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT) {
return;
}
fil_space_write_crypt_data_low(crypt_data, crypt_data->type,
page, offset, maxsize, mtr);
}
......@@ -1073,7 +1058,7 @@ fil_crypt_start_encrypting_space(
crypt_data->rotate_state.active_threads = 1;
mutex_enter(&crypt_data->mutex);
fil_space_set_crypt_data(space, crypt_data);
crypt_data = fil_space_set_crypt_data(space, crypt_data);
mutex_exit(&crypt_data->mutex);
fil_crypt_start_converting = true;
......@@ -1108,6 +1093,7 @@ fil_crypt_start_encrypting_space(
/* 3 - compute location to store crypt data */
byte* frame = buf_block_get_frame(block);
ulint maxsize;
ut_ad(crypt_data);
crypt_data->page0_offset =
fsp_header_get_crypt_offset(zip_size, &maxsize);
......@@ -1160,6 +1146,7 @@ fil_crypt_start_encrypting_space(
/* 5 - publish crypt data */
mutex_enter(&fil_crypt_threads_mutex);
ut_ad(crypt_data);
mutex_enter(&crypt_data->mutex);
crypt_data->type = CRYPT_SCHEME_1;
ut_a(crypt_data->rotate_state.active_threads == 1);
......@@ -1173,6 +1160,7 @@ fil_crypt_start_encrypting_space(
return pending_op;
} while (0);
ut_ad(crypt_data);
mutex_enter(&crypt_data->mutex);
ut_a(crypt_data->rotate_state.active_threads == 1);
crypt_data->rotate_state.active_threads = 0;
......
......@@ -6855,7 +6855,7 @@ fil_space_get_crypt_data(
/******************************************************************
Get crypt data for a tablespace */
UNIV_INTERN
void
fil_space_crypt_t*
fil_space_set_crypt_data(
/*=====================*/
ulint id, /*!< in: space id */
......@@ -6863,6 +6863,7 @@ fil_space_set_crypt_data(
{
fil_space_t* space;
fil_space_crypt_t* free_crypt_data = NULL;
fil_space_crypt_t* ret_crypt_data = NULL;
ut_ad(fil_system);
......@@ -6881,9 +6882,11 @@ fil_space_set_crypt_data(
mutex_exit(&fil_system->mutex);
fil_space_merge_crypt_data(space->crypt_data,
crypt_data);
ret_crypt_data = space->crypt_data;
free_crypt_data = crypt_data;
} else {
space->crypt_data = crypt_data;
ret_crypt_data = space->crypt_data;
mutex_exit(&fil_system->mutex);
}
} else {
......@@ -6899,4 +6902,6 @@ fil_space_set_crypt_data(
*/
fil_space_destroy_crypt_data(&free_crypt_data);
}
return ret_crypt_data;
}
......@@ -134,7 +134,7 @@ fil_space_get_crypt_data(
/*********************************************************************
Set crypt data for a space*/
UNIV_INTERN
void
fil_space_crypt_t*
fil_space_set_crypt_data(
/*=====================*/
ulint space, /*!< in: tablespace id */
......
......@@ -4414,7 +4414,7 @@ corrupt:
"InnoDB: space %lu file %s read of page %lu.\n"
"InnoDB: You may have to recover"
" from a backup.\n",
bpage->space,
(ulint)bpage->space,
space ? space->name : "NULL",
(ulong) bpage->offset);
......
......@@ -266,13 +266,8 @@ fil_space_read_crypt_data(
ulint offset) /*!< in: offset */
{
if (memcmp(page + offset, EMPTY_PATTERN, MAGIC_SZ) == 0) {
/* crypt is not stored but create memory cache for
not system tablespace */
if (space != 0) {
return fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);
} else {
return NULL;
}
/* Crypt data is not stored. */
return NULL;
}
if (memcmp(page + offset, CRYPT_MAGIC, MAGIC_SZ) != 0) {
......@@ -288,12 +283,8 @@ fil_space_read_crypt_data(
page[offset + 3],
page[offset + 4],
page[offset + 5]);
/* Create memory cache for not system tablespace */
if (space != 0) {
return fil_space_create_crypt_data(FIL_SPACE_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);
} else {
return NULL;
}
/* Crypt data is not stored. */
return NULL;
}
ulint type = mach_read_from_1(page + offset + MAGIC_SZ + 0);
......@@ -461,12 +452,6 @@ fil_space_write_crypt_data(
return;
}
/* If tablespace encryption is disabled and encryption mode is
DEFAULT, then do not continue writing crypt data to page 0. */
if (!srv_encrypt_tables && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT) {
return;
}
fil_space_write_crypt_data_low(crypt_data, crypt_data->type,
page, offset, maxsize, mtr);
}
......@@ -1073,7 +1058,7 @@ fil_crypt_start_encrypting_space(
crypt_data->rotate_state.active_threads = 1;
mutex_enter(&crypt_data->mutex);
fil_space_set_crypt_data(space, crypt_data);
crypt_data = fil_space_set_crypt_data(space, crypt_data);
mutex_exit(&crypt_data->mutex);
fil_crypt_start_converting = true;
......@@ -1108,6 +1093,7 @@ fil_crypt_start_encrypting_space(
/* 3 - compute location to store crypt data */
byte* frame = buf_block_get_frame(block);
ulint maxsize;
ut_ad(crypt_data);
crypt_data->page0_offset =
fsp_header_get_crypt_offset(zip_size, &maxsize);
......@@ -1160,6 +1146,7 @@ fil_crypt_start_encrypting_space(
/* 5 - publish crypt data */
mutex_enter(&fil_crypt_threads_mutex);
ut_ad(crypt_data);
mutex_enter(&crypt_data->mutex);
crypt_data->type = CRYPT_SCHEME_1;
ut_a(crypt_data->rotate_state.active_threads == 1);
......@@ -1173,6 +1160,7 @@ fil_crypt_start_encrypting_space(
return pending_op;
} while (0);
ut_ad(crypt_data);
mutex_enter(&crypt_data->mutex);
ut_a(crypt_data->rotate_state.active_threads == 1);
crypt_data->rotate_state.active_threads = 0;
......
......@@ -6982,7 +6982,7 @@ fil_space_get_crypt_data(
/******************************************************************
Get crypt data for a tablespace */
UNIV_INTERN
void
fil_space_crypt_t*
fil_space_set_crypt_data(
/*==================*/
ulint id, /*!< in: space id */
......@@ -6990,6 +6990,7 @@ fil_space_set_crypt_data(
{
fil_space_t* space;
fil_space_crypt_t* free_crypt_data = NULL;
fil_space_crypt_t* ret_crypt_data = NULL;
ut_ad(fil_system);
......@@ -7008,9 +7009,11 @@ fil_space_set_crypt_data(
mutex_exit(&fil_system->mutex);
fil_space_merge_crypt_data(space->crypt_data,
crypt_data);
ret_crypt_data = space->crypt_data;
free_crypt_data = crypt_data;
} else {
space->crypt_data = crypt_data;
ret_crypt_data = space->crypt_data;
mutex_exit(&fil_system->mutex);
}
} else {
......@@ -7026,4 +7029,6 @@ fil_space_set_crypt_data(
*/
fil_space_destroy_crypt_data(&free_crypt_data);
}
return ret_crypt_data;
}
......@@ -134,7 +134,7 @@ fil_space_get_crypt_data(
/*********************************************************************
Set crypt data for a space*/
UNIV_INTERN
void
fil_space_crypt_t*
fil_space_set_crypt_data(
/*=====================*/
ulint space, /*!< in: tablespace id */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment