Skip to content

Commit 885577f

Browse files
author
Jan Lindström
committed
MDEV-11004: Unable to start (Segfault or os error 2) when encryption 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.
1 parent bc32372 commit 885577f

File tree

10 files changed

+211
-44
lines changed

10 files changed

+211
-44
lines changed

mysql-test/std_data/keys2.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
4;205379930183490D3BECA139BDF4DB5B
55
5;E2D944D5D837A1DCB22FF7FD397892EE
66
6;BAFE99B0BB87F2CD33A6AF26A11F6BD1
7+
19;678D6B0063824BACCE33224B385104B35F30FF5749F0EBC030A0955DBC7FAC34
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
2+
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.");
3+
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
4+
5+
# Start server with keys2.txt
6+
CREATE TABLE t1(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=19;
7+
CREATE TABLE t2(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
8+
CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO;
9+
INSERT INTO t1(b) VALUES ('thisissecredmessage');
10+
INSERT INTO t1(b) SELECT b FROM t1;
11+
INSERT INTO t1(b) SELECT b FROM t1;
12+
INSERT INTO t1(b) SELECT b FROM t1;
13+
INSERT INTO t1(b) SELECT b FROM t1;
14+
INSERT INTO t1(b) SELECT b FROM t1;
15+
INSERT INTO t1(b) SELECT b FROM t1;
16+
INSERT INTO t1(b) SELECT b FROM t1;
17+
INSERT INTO t1(b) SELECT b FROM t1;
18+
INSERT INTO t1(b) SELECT b FROM t1;
19+
INSERT INTO t1(b) SELECT b FROM t1;
20+
INSERT INTO t1(b) SELECT b FROM t1;
21+
INSERT INTO t2 SELECT * FROM t1;
22+
INSERT INTO t3 SELECT * FROM t1;
23+
24+
# Restart server with keys3.txt
25+
set global innodb_encryption_rotate_key_age = 1;
26+
use test;
27+
CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
28+
SELECT SLEEP(5);
29+
SLEEP(5)
30+
0
31+
SELECT COUNT(1) FROM t3;
32+
COUNT(1)
33+
2048
34+
SELECT COUNT(1) FROM t2;
35+
COUNT(1)
36+
2048
37+
SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a;
38+
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
39+
SELECT COUNT(1) FROM t1 where b = 'ab';
40+
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
41+
SELECT COUNT(1) FROM t1;
42+
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
43+
44+
# Start server with keys2.txt
45+
SELECT COUNT(1) FROM t1;
46+
COUNT(1)
47+
2048
48+
SELECT COUNT(1) FROM t2;
49+
COUNT(1)
50+
2048
51+
SELECT COUNT(1) FROM t3;
52+
COUNT(1)
53+
2048
54+
DROP TABLE t1, t2, t3;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
--innodb-encrypt-tables
2+
--innodb-encryption-rotate-key-age=15
3+
--innodb-encryption-threads=4
4+
--innodb-tablespaces-encryption
5+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
--source include/have_innodb.inc
2+
-- source include/have_file_key_management_plugin.inc
3+
# embedded does not support restart
4+
-- source include/not_embedded.inc
5+
-- source include/not_valgrind.inc
6+
# Avoid CrashReporter popup on Mac
7+
-- source include/not_crashrep.inc
8+
9+
#
10+
# MDEV-11004: Unable to start (Segfault or os error 2) when encryption key missing
11+
#
12+
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
13+
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.");
14+
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
15+
16+
--echo
17+
--echo # Start server with keys2.txt
18+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
19+
-- source include/restart_mysqld.inc
20+
21+
CREATE TABLE t1(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=19;
22+
CREATE TABLE t2(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
23+
CREATE TABLE t3(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=NO;
24+
INSERT INTO t1(b) VALUES ('thisissecredmessage');
25+
INSERT INTO t1(b) SELECT b FROM t1;
26+
INSERT INTO t1(b) SELECT b FROM t1;
27+
INSERT INTO t1(b) SELECT b FROM t1;
28+
INSERT INTO t1(b) SELECT b FROM t1;
29+
INSERT INTO t1(b) SELECT b FROM t1;
30+
INSERT INTO t1(b) SELECT b FROM t1;
31+
INSERT INTO t1(b) SELECT b FROM t1;
32+
INSERT INTO t1(b) SELECT b FROM t1;
33+
INSERT INTO t1(b) SELECT b FROM t1;
34+
INSERT INTO t1(b) SELECT b FROM t1;
35+
INSERT INTO t1(b) SELECT b FROM t1;
36+
INSERT INTO t2 SELECT * FROM t1;
37+
INSERT INTO t3 SELECT * FROM t1;
38+
39+
--echo
40+
--echo # Restart server with keys3.txt
41+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys3.txt
42+
-- source include/restart_mysqld.inc
43+
44+
set global innodb_encryption_rotate_key_age = 1;
45+
use test;
46+
CREATE TABLE t4(a int not null primary key auto_increment, b varchar(128)) engine=innodb ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
47+
SELECT SLEEP(5);
48+
SELECT COUNT(1) FROM t3;
49+
SELECT COUNT(1) FROM t2;
50+
--error 1296
51+
SELECT COUNT(1) FROM t2,t1 where t2.a = t1.a;
52+
--error 1296
53+
SELECT COUNT(1) FROM t1 where b = 'ab';
54+
--error 1296
55+
SELECT COUNT(1) FROM t1;
56+
57+
--echo
58+
--echo # Start server with keys2.txt
59+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
60+
-- source include/restart_mysqld.inc
61+
62+
SELECT COUNT(1) FROM t1;
63+
SELECT COUNT(1) FROM t2;
64+
SELECT COUNT(1) FROM t3;
65+
66+
DROP TABLE t1, t2, t3;
67+
68+

storage/innobase/buf/buf0buf.cc

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ on the io_type */
317317
? (counter##_READ) \
318318
: (counter##_WRITTEN))
319319

320+
/* prototypes for new functions added to ha_innodb.cc */
321+
trx_t* innobase_get_trx();
322+
320323
/********************************************************************//**
321324
Check if page is maybe compressed, encrypted or both when we encounter
322325
corrupted page. Note that we can't be 100% sure if page is corrupted
@@ -4485,7 +4488,6 @@ buf_page_check_corrupt(
44854488
ulint zip_size = buf_page_get_zip_size(bpage);
44864489
byte* dst_frame = (zip_size) ? bpage->zip.data :
44874490
((buf_block_t*) bpage)->frame;
4488-
unsigned key_version = bpage->key_version;
44894491
bool page_compressed = bpage->page_encrypted;
44904492
ulint stored_checksum = bpage->stored_checksum;
44914493
ulint calculated_checksum = bpage->stored_checksum;
@@ -4495,6 +4497,7 @@ buf_page_check_corrupt(
44954497
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
44964498
fil_space_t* space = fil_space_found_by_id(space_id);
44974499
bool corrupted = true;
4500+
ulint key_version = bpage->key_version;
44984501

44994502
if (key_version != 0 || page_compressed_encrypted) {
45004503
bpage->encrypted = true;
@@ -4524,7 +4527,7 @@ buf_page_check_corrupt(
45244527
stored_checksum, calculated_checksum);
45254528
}
45264529
ib_logf(IB_LOG_LEVEL_ERROR,
4527-
"Reason could be that key_version %u in page "
4530+
"Reason could be that key_version %lu in page "
45284531
"or in crypt_data %p could not be found.",
45294532
key_version, crypt_data);
45304533
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4538,7 +4541,7 @@ buf_page_check_corrupt(
45384541
"Block in space_id %lu in file %s encrypted.",
45394542
space_id, space ? space->name : "NULL");
45404543
ib_logf(IB_LOG_LEVEL_ERROR,
4541-
"However key management plugin or used key_id %u is not found or"
4544+
"However key management plugin or used key_id %lu is not found or"
45424545
" used encryption algorithm or method does not match.",
45434546
key_version);
45444547
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4718,6 +4721,7 @@ buf_page_io_complete(
47184721
return(false);
47194722
} else {
47204723
corrupted = buf_page_check_corrupt(bpage);
4724+
ulint key_version = bpage->key_version;
47214725

47224726
if (corrupted) {
47234727
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4726,12 +4730,12 @@ buf_page_io_complete(
47264730
ut_error;
47274731
}
47284732

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

47364740
if (bpage->space > TRX_SYS_SPACE) {
47374741
if (corrupted) {
@@ -4890,7 +4894,7 @@ buf_all_freed_instance(
48904894
const buf_block_t* block = buf_chunk_not_freed(chunk);
48914895

48924896
if (UNIV_LIKELY_NULL(block)) {
4893-
if (block->page.key_version == 0) {
4897+
if (block->page.key_version == 0) {
48944898
fil_space_t* space = fil_space_get(block->page.space);
48954899
ib_logf(IB_LOG_LEVEL_ERROR,
48964900
"Page %u %u still fixed or dirty.",

storage/innobase/fil/fil0crypt.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation(
13511351
}
13521352
}
13531353

1354+
/* If used key_id is not found from encryption plugin we can't
1355+
continue to rotate the tablespace */
1356+
if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) {
1357+
return false;
1358+
}
1359+
13541360
mutex_enter(&crypt_data->mutex);
13551361

13561362
do {

storage/innobase/handler/ha_innodb.cc

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,20 @@ check_trx_exists(
26012601
return(trx);
26022602
}
26032603

2604+
/*************************************************************************
2605+
Gets current trx. */
2606+
trx_t*
2607+
innobase_get_trx()
2608+
{
2609+
THD *thd=current_thd;
2610+
if (likely(thd != 0)) {
2611+
trx_t*& trx = thd_to_trx(thd);
2612+
return(trx);
2613+
} else {
2614+
return(NULL);
2615+
}
2616+
}
2617+
26042618
/*********************************************************************//**
26052619
Note that a transaction has been registered with MySQL.
26062620
@return true if transaction is registered with MySQL 2PC coordinator */
@@ -20664,15 +20678,17 @@ ib_push_warning(
2066420678
char *buf;
2066520679
#define MAX_BUF_SIZE 4*1024
2066620680

20667-
va_start(args, format);
20668-
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
20669-
vsprintf(buf,format, args);
20681+
if (thd) {
20682+
va_start(args, format);
20683+
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
20684+
vsprintf(buf,format, args);
2067020685

20671-
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
20672-
convert_error_code_to_mysql((dberr_t)error, 0, thd),
20673-
buf);
20674-
my_free(buf);
20675-
va_end(args);
20686+
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
20687+
convert_error_code_to_mysql((dberr_t)error, 0, thd),
20688+
buf);
20689+
my_free(buf);
20690+
va_end(args);
20691+
}
2067620692
}
2067720693

2067820694
/********************************************************************//**
@@ -20694,15 +20710,17 @@ ib_push_warning(
2069420710
thd = current_thd;
2069520711
}
2069620712

20697-
va_start(args, format);
20698-
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
20699-
vsprintf(buf,format, args);
20713+
if (thd) {
20714+
va_start(args, format);
20715+
buf = (char *)my_malloc(MAX_BUF_SIZE, MYF(MY_WME));
20716+
vsprintf(buf,format, args);
2070020717

20701-
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
20702-
convert_error_code_to_mysql((dberr_t)error, 0, thd),
20703-
buf);
20704-
my_free(buf);
20705-
va_end(args);
20718+
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
20719+
convert_error_code_to_mysql((dberr_t)error, 0, thd),
20720+
buf);
20721+
my_free(buf);
20722+
va_end(args);
20723+
}
2070620724
}
2070720725

2070820726
/********************************************************************//**

storage/xtradb/buf/buf0buf.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4601,7 +4601,6 @@ buf_page_check_corrupt(
46014601
ulint zip_size = buf_page_get_zip_size(bpage);
46024602
byte* dst_frame = (zip_size) ? bpage->zip.data :
46034603
((buf_block_t*) bpage)->frame;
4604-
unsigned key_version = bpage->key_version;
46054604
bool page_compressed = bpage->page_encrypted;
46064605
ulint stored_checksum = bpage->stored_checksum;
46074606
ulint calculated_checksum = bpage->stored_checksum;
@@ -4611,6 +4610,7 @@ buf_page_check_corrupt(
46114610
fil_space_crypt_t* crypt_data = fil_space_get_crypt_data(space_id);
46124611
fil_space_t* space = fil_space_found_by_id(space_id);
46134612
bool corrupted = true;
4613+
ulint key_version = bpage->key_version;
46144614

46154615
if (key_version != 0 || page_compressed_encrypted) {
46164616
bpage->encrypted = true;
@@ -4640,7 +4640,7 @@ buf_page_check_corrupt(
46404640
stored_checksum, calculated_checksum);
46414641
}
46424642
ib_logf(IB_LOG_LEVEL_ERROR,
4643-
"Reason could be that key_version %u in page "
4643+
"Reason could be that key_version %lu in page "
46444644
"or in crypt_data %p could not be found.",
46454645
key_version, crypt_data);
46464646
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4654,7 +4654,7 @@ buf_page_check_corrupt(
46544654
"Block in space_id %lu in file %s encrypted.",
46554655
space_id, space ? space->name : "NULL");
46564656
ib_logf(IB_LOG_LEVEL_ERROR,
4657-
"However key management plugin or used key_id %u is not found or"
4657+
"However key management plugin or used key_id %lu is not found or"
46584658
" used encryption algorithm or method does not match.",
46594659
key_version);
46604660
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4855,6 +4855,7 @@ buf_page_io_complete(
48554855
return(false);
48564856
} else {
48574857
corrupted = buf_page_check_corrupt(bpage);
4858+
ulint key_version = bpage->key_version;
48584859

48594860
if (corrupted) {
48604861
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -4865,10 +4866,10 @@ buf_page_io_complete(
48654866

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

48734874
if (bpage->space > TRX_SYS_SPACE) {
48744875
if (corrupted) {

storage/xtradb/fil/fil0crypt.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,12 @@ fil_crypt_space_needs_rotation(
13511351
}
13521352
}
13531353

1354+
/* If used key_id is not found from encryption plugin we can't
1355+
continue to rotate the tablespace */
1356+
if (fil_crypt_get_latest_key_version(crypt_data) == ENCRYPTION_KEY_VERSION_INVALID) {
1357+
return false;
1358+
}
1359+
13541360
mutex_enter(&crypt_data->mutex);
13551361

13561362
do {

0 commit comments

Comments
 (0)