Skip to content

Commit

Permalink
MDEV-11004: Unable to start (Segfault or os error 2) when encryption …
Browse files Browse the repository at this point in the history
…key missing

Two problems:

(1) When pushing warning to sql-layer we need to check that thd != NULL
to avoid NULL-pointer reference.

(2) At tablespace key rotation if used key_id is not found from
encryption plugin tablespace should not be rotated.
  • Loading branch information
Jan Lindström committed Oct 29, 2016
1 parent bc32372 commit 885577f
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 44 deletions.
1 change: 1 addition & 0 deletions mysql-test/std_data/keys2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
4;205379930183490D3BECA139BDF4DB5B
5;E2D944D5D837A1DCB22FF7FD397892EE
6;BAFE99B0BB87F2CD33A6AF26A11F6BD1
19;678D6B0063824BACCE33224B385104B35F30FF5749F0EBC030A0955DBC7FAC34
54 changes: 54 additions & 0 deletions mysql-test/suite/encryption/r/innodb-missing-key.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
call mtr.add_suppression("InnoDB: However key management plugin or used key_id .* is not found or used encryption algorithm or method does not match.");
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");

# Start server with keys2.txt
CREATE TABLE t1(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=19;
CREATE TABLE t2(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO;
INSERT INTO t1(b) VALUES ('thisissecredmessage');
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t3 SELECT * FROM t1;

# Restart server with keys3.txt
set global innodb_encryption_rotate_key_age = 1;
use test;
CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
SELECT SLEEP(5);
SLEEP(5)
0
SELECT COUNT(1) FROM t3;
COUNT(1)
2048
SELECT COUNT(1) FROM t2;
COUNT(1)
2048
SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a;
ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
SELECT COUNT(1) FROM t1 where b = 'ab';
ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB
SELECT COUNT(1) FROM t1;
ERROR HY000: Got error 192 'Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.' from InnoDB

# Start server with keys2.txt
SELECT COUNT(1) FROM t1;
COUNT(1)
2048
SELECT COUNT(1) FROM t2;
COUNT(1)
2048
SELECT COUNT(1) FROM t3;
COUNT(1)
2048
DROP TABLE t1, t2, t3;
5 changes: 5 additions & 0 deletions mysql-test/suite/encryption/t/innodb-missing-key.opt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
--innodb-encrypt-tables
--innodb-encryption-rotate-key-age=15
--innodb-encryption-threads=4
--innodb-tablespaces-encryption

68 changes: 68 additions & 0 deletions mysql-test/suite/encryption/t/innodb-missing-key.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
--source include/have_innodb.inc
-- source include/have_file_key_management_plugin.inc
# embedded does not support restart
-- source include/not_embedded.inc
-- source include/not_valgrind.inc
# Avoid CrashReporter popup on Mac
-- source include/not_crashrep.inc

#
# MDEV-11004: Unable to start (Segfault or os error 2) when encryption key missing
#
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
call mtr.add_suppression("InnoDB: However key management plugin or used key_id .* is not found or used encryption algorithm or method does not match.");
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");

--echo
--echo # Start server with keys2.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
-- source include/restart_mysqld.inc

CREATE TABLE t1(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=19;
CREATE TABLE t2(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO;
INSERT INTO t1(b) VALUES ('thisissecredmessage');
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t1(b) SELECT b FROM t1;
INSERT INTO t2 SELECT * FROM t1;
INSERT INTO t3 SELECT * FROM t1;

--echo
--echo # Restart server with keys3.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys3.txt
-- source include/restart_mysqld.inc

set global innodb_encryption_rotate_key_age = 1;
use test;
CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
SELECT SLEEP(5);
SELECT COUNT(1) FROM t3;
SELECT COUNT(1) FROM t2;
--error 1296
SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a;
--error 1296
SELECT COUNT(1) FROM t1 where b = 'ab';
--error 1296
SELECT COUNT(1) FROM t1;

--echo
--echo # Start server with keys2.txt
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
-- source include/restart_mysqld.inc

SELECT COUNT(1) FROM t1;
SELECT COUNT(1) FROM t2;
SELECT COUNT(1) FROM t3;

DROP TABLE t1, t2, t3;


18 changes: 11 additions & 7 deletions storage/innobase/buf/buf0buf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@ on the io_type */
? (counter##_READ) \
: (counter##_WRITTEN))

/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();

/********************************************************************//**
Check if page is maybe compressed, encrypted or both when we encounter
corrupted page. Note that we can't be 100% sure if page is corrupted
Expand Down Expand Up @@ -4485,7 +4488,6 @@ buf_page_check_corrupt(
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
ulint stored_checksum = bpage->stored_checksum;
ulint calculated_checksum = bpage->stored_checksum;
Expand All @@ -4495,6 +4497,7 @@ buf_page_check_corrupt(
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
fil_space_t* space = fil_space_found_by_id(space_id);
bool corrupted = true;
ulint key_version = bpage->key_version;

if (key_version != 0 || page_compressed_encrypted) {
bpage->encrypted = true;
Expand Down Expand Up @@ -4524,7 +4527,7 @@ buf_page_check_corrupt(
stored_checksum, calculated_checksum);
}
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be that key_version %u in page "
"Reason could be that key_version %lu in page "
"or in crypt_data %p could not be found.",
key_version, crypt_data);
ib_logf(IB_LOG_LEVEL_ERROR,
Expand All @@ -4538,7 +4541,7 @@ buf_page_check_corrupt(
"Block in space_id %lu in file %s encrypted.",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"However key management plugin or used key_id %u is not found or"
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match.",
key_version);
ib_logf(IB_LOG_LEVEL_ERROR,
Expand Down Expand Up @@ -4718,6 +4721,7 @@ buf_page_io_complete(
return(false);
} else {
corrupted = buf_page_check_corrupt(bpage);
ulint key_version = bpage->key_version;

if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
Expand All @@ -4726,12 +4730,12 @@ buf_page_io_complete(
ut_error;
}

ib_push_warning((void *)NULL, DB_DECRYPTION_FAILED,
ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
"Table in tablespace %lu encrypted."
"However key management plugin or used key_id %u is not found or"
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.",
(ulint)bpage->space, bpage->key_version);
(ulint)bpage->space, key_version);

if (bpage->space > TRX_SYS_SPACE) {
if (corrupted) {
Expand Down Expand Up @@ -4890,7 +4894,7 @@ buf_all_freed_instance(
const buf_block_t* block = buf_chunk_not_freed(chunk);

if (UNIV_LIKELY_NULL(block)) {
if (block->page.key_version == 0) {
if (block->page.key_version == 0) {
fil_space_t* space = fil_space_get(block->page.space);
ib_logf(IB_LOG_LEVEL_ERROR,
"Page %u %u still fixed or dirty.",
Expand Down
6 changes: 6 additions & 0 deletions storage/innobase/fil/fil0crypt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation(
}
}

/* If used key_id is not found from encryption plugin we can't
continue to rotate the tablespace */
if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) {
return false;
}

mutex_enter(&crypt_data->mutex);

do {
Expand Down
50 changes: 34 additions & 16 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2601,6 +2601,20 @@ check_trx_exists(
return(trx);
}

/*************************************************************************
Gets current trx. */
trx_t*
innobase_get_trx()
{
THD *thd=current_thd;
if (likely(thd != 0)) {
trx_t*& trx = thd_to_trx(thd);
return(trx);
} else {
return(NULL);
}
}

/*********************************************************************//**
Note that a transaction has been registered with MySQL.
@return true if transaction is registered with MySQL 2PC coordinator */
Expand Down Expand Up @@ -20664,15 +20678,17 @@ ib_push_warning(
char *buf;
#define MAX_BUF_SIZE 4*1024

va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
if (thd) {
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);

push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}
}

/********************************************************************//**
Expand All @@ -20694,15 +20710,17 @@ ib_push_warning(
thd = current_thd;
}

va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);
if (thd) {
va_start(args, format);
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
vsprintf(buf,format, args);

push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
convert_error_code_to_mysql((dberr_t)error, 0, thd),
buf);
my_free(buf);
va_end(args);
}
}

/********************************************************************//**
Expand Down
11 changes: 6 additions & 5 deletions storage/xtradb/buf/buf0buf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4601,7 +4601,6 @@ buf_page_check_corrupt(
ulint zip_size = buf_page_get_zip_size(bpage);
byte* dst_frame = (zip_size) ? bpage->zip.data :
((buf_block_t*) bpage)->frame;
unsigned key_version = bpage->key_version;
bool page_compressed = bpage->page_encrypted;
ulint stored_checksum = bpage->stored_checksum;
ulint calculated_checksum = bpage->stored_checksum;
Expand All @@ -4611,6 +4610,7 @@ buf_page_check_corrupt(
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
fil_space_t* space = fil_space_found_by_id(space_id);
bool corrupted = true;
ulint key_version = bpage->key_version;

if (key_version != 0 || page_compressed_encrypted) {
bpage->encrypted = true;
Expand Down Expand Up @@ -4640,7 +4640,7 @@ buf_page_check_corrupt(
stored_checksum, calculated_checksum);
}
ib_logf(IB_LOG_LEVEL_ERROR,
"Reason could be that key_version %u in page "
"Reason could be that key_version %lu in page "
"or in crypt_data %p could not be found.",
key_version, crypt_data);
ib_logf(IB_LOG_LEVEL_ERROR,
Expand All @@ -4654,7 +4654,7 @@ buf_page_check_corrupt(
"Block in space_id %lu in file %s encrypted.",
space_id, space ? space->name : "NULL");
ib_logf(IB_LOG_LEVEL_ERROR,
"However key management plugin or used key_id %u is not found or"
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match.",
key_version);
ib_logf(IB_LOG_LEVEL_ERROR,
Expand Down Expand Up @@ -4855,6 +4855,7 @@ buf_page_io_complete(
return(false);
} else {
corrupted = buf_page_check_corrupt(bpage);
ulint key_version = bpage->key_version;

if (corrupted) {
ib_logf(IB_LOG_LEVEL_ERROR,
Expand All @@ -4865,10 +4866,10 @@ buf_page_io_complete(

ib_push_warning(innobase_get_trx(), DB_DECRYPTION_FAILED,
"Table in tablespace %lu encrypted."
"However key management plugin or used key_id %u is not found or"
"However key management plugin or used key_id %lu is not found or"
" used encryption algorithm or method does not match."
" Can't continue opening the table.",
(ulint)bpage->space, bpage->key_version);
(ulint)bpage->space, key_version);

if (bpage->space > TRX_SYS_SPACE) {
if (corrupted) {
Expand Down
6 changes: 6 additions & 0 deletions storage/xtradb/fil/fil0crypt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation(
}
}

/* If used key_id is not found from encryption plugin we can't
continue to rotate the tablespace */
if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) {
return false;
}

mutex_enter(&crypt_data->mutex);

do {
Expand Down
Loading

0 comments on commit 885577f

Please sign in to comment.