Skip to content

Commit 0cf39f4

Browse files
committed
MDEV-8817: Failing assertion: new_state->key_version != ENCRYPTION_KEY_VERSION_INVALID
Analysis: Problem sees to be the fact that we allow creating or altering table to use encryption_key_id that does not exists in case where original table is not encrypted currently. Secondly we should not do key rotation to tables that are not encrypted or tablespaces that can't be found from tablespace cache. Fix: Do not allow creating unencrypted table with nondefault encryption key and do not rotate tablespaces that are not encrypted (FIL_SPACE_ENCRYPTION_OFF) or can't be found from tablespace cache.
1 parent 5c9c8ef commit 0cf39f4

File tree

7 files changed

+176
-22
lines changed

7 files changed

+176
-22
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
SET GLOBAL innodb_file_format = `Barracuda`;
2+
SET GLOBAL innodb_file_per_table = ON;
3+
SET GLOBAL innodb_encrypt_tables = ON;
4+
SET GLOBAL innodb_encryption_threads = 4;
5+
CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=4;
6+
ERROR HY000: Can't create table `test`.`t1` (errno: 140 "Wrong create options")
7+
CREATE TABLE t2 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
8+
CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
9+
ALTER TABLE t2 ENCRYPTION_KEY_ID=4;
10+
ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 140 "Wrong create options")
11+
ALTER TABLE t1 ENCRYPTION_KEY_ID=99;
12+
ERROR HY000: Can't create table `test`.`#sql-temporary` (errno: 140 "Wrong create options")
13+
drop table t1,t2;

mysql-test/suite/encryption/t/encrypt_and_grep.test

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ insert t3 values (repeat('dummy', 42));
2727

2828
--echo # Wait max 10 min for key encryption threads to encrypt all spaces
2929
--let $wait_timeout= 600
30-
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
30+
--let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0
3131
--source include/wait_condition.inc
3232

3333
--sleep 5
@@ -55,7 +55,7 @@ SET GLOBAL innodb_encrypt_tables = off;
5555

5656
--echo # Wait max 10 min for key encryption threads to decrypt all spaces
5757
--let $wait_timeout= 600
58-
--let $wait_condition=SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
58+
--let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0;
5959
--source include/wait_condition.inc
6060
--sleep 5
6161

@@ -82,7 +82,7 @@ SET GLOBAL innodb_encrypt_tables = on;
8282

8383
--echo # Wait max 10 min for key encryption threads to encrypt all spaces
8484
--let $wait_timeout= 600
85-
--let $wait_condition=SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
85+
--let $wait_condition=SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0;
8686
--source include/wait_condition.inc
8787
--sleep 5
8888

@@ -105,4 +105,4 @@ SET GLOBAL innodb_encrypt_tables = on;
105105

106106
--echo # TODO: add shutdown + grep tests
107107

108-
drop table t1, t2, t3;
108+
drop table t1, t2, t3;
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
-- source include/have_innodb.inc
2+
-- source include/have_file_key_management_plugin.inc
3+
4+
#
5+
# MDEV-8817: Failing assertion: new_state->key_version != ENCRYPTION_KEY_VERSION_INVALID
6+
#
7+
8+
--disable_query_log
9+
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
10+
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
11+
let $encrypt_tables = `SELECT @@innodb_encrypt_tables`;
12+
let $threads = `SELECT @@innodb_encryption_threads`;
13+
--enable_query_log
14+
15+
SET GLOBAL innodb_file_format = `Barracuda`;
16+
SET GLOBAL innodb_file_per_table = ON;
17+
SET GLOBAL innodb_encrypt_tables = ON;
18+
SET GLOBAL innodb_encryption_threads = 4;
19+
20+
--error 1005
21+
CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=4;
22+
CREATE TABLE t2 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
23+
CREATE TABLE t1 (pk INT PRIMARY KEY AUTO_INCREMENT, c VARCHAR(256)) ENGINE=INNODB ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
24+
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/
25+
--error 1005
26+
ALTER TABLE t2 ENCRYPTION_KEY_ID=4;
27+
--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/
28+
--error 1005
29+
ALTER TABLE t1 ENCRYPTION_KEY_ID=99;
30+
31+
--disable_warnings
32+
--disable_query_log
33+
let $i = 400;
34+
while ($i)
35+
{
36+
INSERT INTO t1 values(NULL, substring(MD5(RAND()), -128));
37+
dec $i;
38+
}
39+
commit;
40+
INSERT INTO t2 select * from t1;
41+
42+
--disable_abort_on_error
43+
44+
--connect (con1,localhost,root,,test)
45+
--connect (con2,localhost,root,,test)
46+
47+
let $i = 50;
48+
while ($i)
49+
{
50+
connection con1;
51+
send ALTER TABLE t1 ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
52+
connection con2;
53+
send ALTER TABLE t1 ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
54+
connection default;
55+
send ALTER TABLE t2 ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
56+
connection con1;
57+
--reap;
58+
ALTER TABLE t1 ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
59+
connection con2;
60+
--reap
61+
ALTER TABLE t1 ENCRYPTED=YES ENCRYPTION_KEY_ID=4;
62+
connection default;
63+
--reap
64+
ALTER TABLE t2 ENCRYPTED=YES ENCRYPTION_KEY_ID=1;
65+
ALTER TABLE t1 ENCRYPTED=NO ENCRYPTION_KEY_ID=1;
66+
dec $i;
67+
}
68+
69+
connection default;
70+
--disconnect con1
71+
--disconnect con2
72+
73+
--enable_abort_on_error
74+
--enable_warnings
75+
--enable_query_log
76+
77+
drop table t1,t2;
78+
79+
# reset system
80+
--disable_query_log
81+
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
82+
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
83+
EVAL SET GLOBAL innodb_encrypt_tables = $encrypt_tables;
84+
EVAL SET GLOBAL innodb_encryption_threads = $threads;
85+
--enable_query_log

storage/innobase/fil/fil0crypt.cc

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ fil_space_create_crypt_data(
199199
if (encrypt_mode == FIL_SPACE_ENCRYPTION_OFF ||
200200
(!srv_encrypt_tables && encrypt_mode == FIL_SPACE_ENCRYPTION_DEFAULT)) {
201201
crypt_data->type = CRYPT_SCHEME_UNENCRYPTED;
202-
crypt_data->min_key_version = 0;
203202
} else {
204203
crypt_data->type = CRYPT_SCHEME_1;
205204
crypt_data->min_key_version = encryption_key_get_latest_version(key_id);
@@ -210,8 +209,8 @@ fil_space_create_crypt_data(
210209
crypt_data->locker = crypt_data_scheme_locker;
211210
my_random_bytes(crypt_data->iv, sizeof(crypt_data->iv));
212211
crypt_data->encryption = encrypt_mode;
213-
crypt_data->key_id = key_id;
214212
crypt_data->inited = true;
213+
crypt_data->key_id = key_id;
215214
return crypt_data;
216215
}
217216

@@ -964,6 +963,13 @@ fil_crypt_get_key_state(
964963
new_state->key_version =
965964
encryption_key_get_latest_version(new_state->key_id);
966965
new_state->rotate_key_age = srv_fil_crypt_rotate_key_age;
966+
967+
if (new_state->key_version == ENCRYPTION_KEY_VERSION_INVALID) {
968+
ib_logf(IB_LOG_LEVEL_ERROR,
969+
"Used key_id %u can't be found from key file.",
970+
new_state->key_id);
971+
}
972+
967973
ut_a(new_state->key_version != ENCRYPTION_KEY_VERSION_INVALID);
968974
ut_a(new_state->key_version != ENCRYPTION_KEY_NOT_ENCRYPTED);
969975
} else {
@@ -1302,6 +1308,11 @@ fil_crypt_space_needs_rotation(
13021308
break;
13031309
}
13041310

1311+
/* No need to rotate space if encryption is disabled */
1312+
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
1313+
break;
1314+
}
1315+
13051316
if (crypt_data->key_id != key_state->key_id) {
13061317
key_state->key_id= crypt_data->key_id;
13071318
fil_crypt_get_key_state(key_state);
@@ -1549,13 +1560,16 @@ fil_crypt_find_space_to_rotate(
15491560
}
15501561

15511562
while (!state->should_shutdown() && state->space != ULINT_UNDEFINED) {
1552-
1553-
if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
1554-
ut_ad(key_state->key_id);
1555-
/* init state->min_key_version_found before
1556-
* starting on a space */
1557-
state->min_key_version_found = key_state->key_version;
1558-
return true;
1563+
fil_space_t* space = fil_space_found_by_id(state->space);
1564+
1565+
if (space) {
1566+
if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
1567+
ut_ad(key_state->key_id);
1568+
/* init state->min_key_version_found before
1569+
* starting on a space */
1570+
state->min_key_version_found = key_state->key_version;
1571+
return true;
1572+
}
15591573
}
15601574

15611575
state->space = fil_get_next_space_safe(state->space);

storage/innobase/handler/ha_innodb.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11504,6 +11504,20 @@ ha_innobase::check_table_options(
1150411504
}
1150511505
}
1150611506

11507+
/* Do not allow creating unencrypted table with nondefault
11508+
encryption key */
11509+
if ((encrypt == FIL_SPACE_ENCRYPTION_OFF ||
11510+
(encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && !srv_encrypt_tables)) &&
11511+
options->encryption_key_id != FIL_DEFAULT_ENCRYPTION_KEY) {
11512+
push_warning_printf(
11513+
thd, Sql_condition::WARN_LEVEL_WARN,
11514+
HA_WRONG_CREATE_OPTION,
11515+
"InnoDB: Incorrect ENCRYPTION_KEY_ID %u when encryption is disabled",
11516+
(uint)options->encryption_key_id
11517+
);
11518+
return "ENCRYPTION_KEY_ID";
11519+
}
11520+
1150711521
/* Check atomic writes requirements */
1150811522
if (awrites == ATOMIC_WRITES_ON ||
1150911523
(awrites == ATOMIC_WRITES_DEFAULT && srv_use_atomic_writes)) {

storage/xtradb/fil/fil0crypt.cc

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,6 @@ fil_space_create_crypt_data(
199199
if (encrypt_mode == FIL_SPACE_ENCRYPTION_OFF ||
200200
(!srv_encrypt_tables && encrypt_mode == FIL_SPACE_ENCRYPTION_DEFAULT)) {
201201
crypt_data->type = CRYPT_SCHEME_UNENCRYPTED;
202-
crypt_data->min_key_version = 0;
203202
} else {
204203
crypt_data->type = CRYPT_SCHEME_1;
205204
crypt_data->min_key_version = encryption_key_get_latest_version(key_id);
@@ -210,8 +209,8 @@ fil_space_create_crypt_data(
210209
crypt_data->locker = crypt_data_scheme_locker;
211210
my_random_bytes(crypt_data->iv, sizeof(crypt_data->iv));
212211
crypt_data->encryption = encrypt_mode;
213-
crypt_data->key_id = key_id;
214212
crypt_data->inited = true;
213+
crypt_data->key_id = key_id;
215214
return crypt_data;
216215
}
217216

@@ -964,6 +963,13 @@ fil_crypt_get_key_state(
964963
new_state->key_version =
965964
encryption_key_get_latest_version(new_state->key_id);
966965
new_state->rotate_key_age = srv_fil_crypt_rotate_key_age;
966+
967+
if (new_state->key_version == ENCRYPTION_KEY_VERSION_INVALID) {
968+
ib_logf(IB_LOG_LEVEL_ERROR,
969+
"Used key_id %u can't be found from key file.",
970+
new_state->key_id);
971+
}
972+
967973
ut_a(new_state->key_version != ENCRYPTION_KEY_VERSION_INVALID);
968974
ut_a(new_state->key_version != ENCRYPTION_KEY_NOT_ENCRYPTED);
969975
} else {
@@ -1302,6 +1308,11 @@ fil_crypt_space_needs_rotation(
13021308
break;
13031309
}
13041310

1311+
/* No need to rotate space if encryption is disabled */
1312+
if (crypt_data->encryption == FIL_SPACE_ENCRYPTION_OFF) {
1313+
break;
1314+
}
1315+
13051316
if (crypt_data->key_id != key_state->key_id) {
13061317
key_state->key_id= crypt_data->key_id;
13071318
fil_crypt_get_key_state(key_state);
@@ -1549,13 +1560,16 @@ fil_crypt_find_space_to_rotate(
15491560
}
15501561

15511562
while (!state->should_shutdown() && state->space != ULINT_UNDEFINED) {
1552-
1553-
if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
1554-
ut_ad(key_state->key_id);
1555-
/* init state->min_key_version_found before
1556-
* starting on a space */
1557-
state->min_key_version_found = key_state->key_version;
1558-
return true;
1563+
fil_space_t* space = fil_space_found_by_id(state->space);
1564+
1565+
if (space) {
1566+
if (fil_crypt_space_needs_rotation(state, key_state, recheck)) {
1567+
ut_ad(key_state->key_id);
1568+
/* init state->min_key_version_found before
1569+
* starting on a space */
1570+
state->min_key_version_found = key_state->key_version;
1571+
return true;
1572+
}
15591573
}
15601574

15611575
state->space = fil_get_next_space_safe(state->space);

storage/xtradb/handler/ha_innodb.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11987,6 +11987,20 @@ ha_innobase::check_table_options(
1198711987
}
1198811988
}
1198911989

11990+
/* Do not allow creating unencrypted table with nondefault
11991+
encryption key */
11992+
if ((encrypt == FIL_SPACE_ENCRYPTION_OFF ||
11993+
(encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && !srv_encrypt_tables)) &&
11994+
options->encryption_key_id != FIL_DEFAULT_ENCRYPTION_KEY) {
11995+
push_warning_printf(
11996+
thd, Sql_condition::WARN_LEVEL_WARN,
11997+
HA_WRONG_CREATE_OPTION,
11998+
"InnoDB: Incorrect ENCRYPTION_KEY_ID %u when encryption is disabled",
11999+
(uint)options->encryption_key_id
12000+
);
12001+
return "ENCRYPTION_KEY_ID";
12002+
}
12003+
1199012004
/* Check atomic writes requirements */
1199112005
if (awrites == ATOMIC_WRITES_ON ||
1199212006
(awrites == ATOMIC_WRITES_DEFAULT && srv_use_atomic_writes)) {

0 commit comments

Comments
 (0)