Skip to content

Commit 71b1444

Browse files
author
Jan Lindström
committed
MDEV-8768: Server crash at file btr0btr.ic line 122 when checking encrypted table using incorrect keys
Add error handling to btr_validate_index when index root block can't be read because block decryption fails.
1 parent d581ef5 commit 71b1444

File tree

8 files changed

+188
-37
lines changed

8 files changed

+188
-37
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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 1 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+
call mtr.add_suppression(".*InnoDB: Cannot open table test/.* from the internal data dictionary of InnoDB though the .frm file for the table exists. See .* for how you can resolve the problem.");
5+
call mtr.add_suppression("InnoDB: .ibd file is missing for table test/.*");
6+
call mtr.add_suppression("Couldn't load plugins from 'file_key_management*");
7+
SET GLOBAL innodb_file_format = `Barracuda`;
8+
SET GLOBAL innodb_file_per_table = ON;
9+
CREATE TABLE t1 (pk INT PRIMARY KEY, f VARCHAR(8)) ENGINE=InnoDB ENCRYPTION_KEY_ID=4;
10+
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
11+
SET GLOBAL innodb_file_format = `Barracuda`;
12+
SET GLOBAL innodb_file_per_table = ON;
13+
CHECK TABLE t1;
14+
Table Op Msg_type Msg_text
15+
test.t1 check Warning Table test/t1 in tablespace 4 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
16+
test.t1 check Warning Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue checking table.
17+
test.t1 check error Corrupt
18+
SHOW WARNINGS;
19+
Level Code Message
20+
DROP TABLE t1;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
--source include/have_innodb.inc
2+
# embedded does not support restart
3+
-- source include/not_embedded.inc
4+
-- source include/not_valgrind.inc
5+
# Avoid CrashReporter popup on Mac
6+
-- source include/not_crashrep.inc
7+
#
8+
# MDEV-8768: Server crash at file btr0btr.ic line 122 when checking encrypted table using incorrect keys
9+
#
10+
call mtr.add_suppression("InnoDB: Block in space_id .* in file test/.* encrypted");
11+
call mtr.add_suppression("InnoDB: However key management plugin or used key_id 1 is not found or used encryption algorithm or method does not match.");
12+
call mtr.add_suppression("InnoDB: Marking tablespace as missing. You may drop this table or install correct key management plugin and key file.");
13+
call mtr.add_suppression(".*InnoDB: Cannot open table test/.* from the internal data dictionary of InnoDB though the .frm file for the table exists. See .* for how you can resolve the problem.");
14+
call mtr.add_suppression("InnoDB: .ibd file is missing for table test/.*");
15+
# Suppression for builds where file_key_management plugin is linked statically
16+
call mtr.add_suppression("Couldn't load plugins from 'file_key_management*");
17+
18+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
19+
--shutdown_server
20+
--source include/wait_until_disconnected.inc
21+
22+
--write_file $MYSQLTEST_VARDIR/keys1.txt
23+
1;770A8A65DA156D24EE2A093277530142
24+
4;770A8A65DA156D24EE2A093277530143
25+
EOF
26+
27+
--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
28+
--enable_reconnect
29+
--source include/wait_until_connected_again.inc
30+
31+
--let $MYSQLD_TMPDIR = `SELECT @@tmpdir`
32+
--let $MYSQLD_DATADIR = `SELECT @@datadir`
33+
34+
--disable_query_log
35+
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
36+
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
37+
--enable_query_log
38+
39+
SET GLOBAL innodb_file_format = `Barracuda`;
40+
SET GLOBAL innodb_file_per_table = ON;
41+
42+
CREATE TABLE t1 (pk INT PRIMARY KEY, f VARCHAR(8)) ENGINE=InnoDB ENCRYPTION_KEY_ID=4;
43+
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
44+
45+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
46+
--shutdown_server
47+
--source include/wait_until_disconnected.inc
48+
49+
--write_file $MYSQLTEST_VARDIR/keys2.txt
50+
1;770A8A65DA156D24EE2A093277530142
51+
4;770A8A65DA156D24EE2A093277530144
52+
EOF
53+
54+
--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys2.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
55+
--enable_reconnect
56+
--source include/wait_until_connected_again.inc
57+
58+
SET GLOBAL innodb_file_format = `Barracuda`;
59+
SET GLOBAL innodb_file_per_table = ON;
60+
61+
CHECK TABLE t1;
62+
SHOW WARNINGS;
63+
64+
--remove_file $MYSQLTEST_VARDIR/keys1.txt
65+
--remove_file $MYSQLTEST_VARDIR/keys2.txt
66+
67+
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
68+
--shutdown_server
69+
--source include/wait_until_disconnected.inc
70+
71+
--write_file $MYSQLTEST_VARDIR/keys1.txt
72+
1;770A8A65DA156D24EE2A093277530142
73+
4;770A8A65DA156D24EE2A093277530143
74+
EOF
75+
76+
--exec echo "restart:--innodb-encrypt-tables --innodb-stats-persistent --plugin-load-add=file_key_management.so --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
77+
--enable_reconnect
78+
--source include/wait_until_connected_again.inc
79+
80+
DROP TABLE t1;
81+
82+
--remove_file $MYSQLTEST_VARDIR/keys1.txt
83+
84+
# reset system
85+
--disable_query_log
86+
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
87+
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
88+
--enable_query_log

storage/innobase/btr/btr0btr.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5123,18 +5123,20 @@ btr_validate_level(
51235123

51245124
/**************************************************************//**
51255125
Checks the consistency of an index tree.
5126-
@return TRUE if ok */
5126+
@return DB_SUCCESS if ok, error code if not */
51275127
UNIV_INTERN
5128-
bool
5128+
dberr_t
51295129
btr_validate_index(
51305130
/*===============*/
51315131
dict_index_t* index, /*!< in: index */
51325132
const trx_t* trx) /*!< in: transaction or NULL */
51335133
{
5134+
dberr_t err = DB_SUCCESS;
5135+
51345136
/* Full Text index are implemented by auxiliary tables,
51355137
not the B-tree */
51365138
if (dict_index_is_online_ddl(index) || (index->type & DICT_FTS)) {
5137-
return(true);
5139+
return(err);
51385140
}
51395141

51405142
mtr_t mtr;
@@ -5143,21 +5145,27 @@ btr_validate_index(
51435145

51445146
mtr_x_lock(dict_index_get_lock(index), &mtr);
51455147

5146-
bool ok = true;
51475148
page_t* root = btr_root_get(index, &mtr);
5149+
5150+
if (root == NULL && index->table->is_encrypted) {
5151+
err = DB_DECRYPTION_FAILED;
5152+
mtr_commit(&mtr);
5153+
return err;
5154+
}
5155+
51485156
ulint n = btr_page_get_level(root, &mtr);
51495157

51505158
for (ulint i = 0; i <= n; ++i) {
51515159

51525160
if (!btr_validate_level(index, trx, n - i)) {
5153-
ok = false;
5161+
err = DB_CORRUPTION;
51545162
break;
51555163
}
51565164
}
51575165

51585166
mtr_commit(&mtr);
51595167

5160-
return(ok);
5168+
return(err);
51615169
}
51625170

51635171
/**************************************************************//**

storage/innobase/handler/ha_innodb.cc

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13512,7 +13512,7 @@ ha_innobase::check(
1351213512
server_mutex,
1351313513
srv_fatal_semaphore_wait_threshold,
1351413514
SRV_SEMAPHORE_WAIT_EXTENSION);
13515-
bool valid = btr_validate_index(index, prebuilt->trx);
13515+
dberr_t err = btr_validate_index(index, prebuilt->trx);
1351613516

1351713517
/* Restore the fatal lock wait timeout after
1351813518
CHECK TABLE. */
@@ -13521,19 +13521,33 @@ ha_innobase::check(
1352113521
srv_fatal_semaphore_wait_threshold,
1352213522
SRV_SEMAPHORE_WAIT_EXTENSION);
1352313523

13524-
if (!valid) {
13524+
if (err != DB_SUCCESS) {
1352513525
is_ok = false;
1352613526

1352713527
innobase_format_name(
1352813528
index_name, sizeof index_name,
1352913529
index->name, TRUE);
13530-
push_warning_printf(
13531-
thd,
13532-
Sql_condition::WARN_LEVEL_WARN,
13533-
ER_NOT_KEYFILE,
13534-
"InnoDB: The B-tree of"
13535-
" index %s is corrupted.",
13536-
index_name);
13530+
13531+
if (err == DB_DECRYPTION_FAILED) {
13532+
push_warning_printf(
13533+
thd,
13534+
Sql_condition::WARN_LEVEL_WARN,
13535+
ER_NO_SUCH_TABLE,
13536+
"Table %s is encrypted but encryption service or"
13537+
" used key_id is not available. "
13538+
" Can't continue checking table.",
13539+
13540+
index->table->name);
13541+
} else {
13542+
push_warning_printf(
13543+
thd,
13544+
Sql_condition::WARN_LEVEL_WARN,
13545+
ER_NOT_KEYFILE,
13546+
"InnoDB: The B-tree of"
13547+
" index %s is corrupted.",
13548+
index_name);
13549+
}
13550+
1353713551
continue;
1353813552
}
1353913553
}

storage/innobase/include/btr0btr.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2012, Facebook Inc.
5-
Copyright (c) 2014, SkySQL Ab. All Rights Reserved.
5+
Copyright (c) 2014, 2015, MariaDB Corporation. All Rights Reserved.
66
77
This program is free software; you can redistribute it and/or modify it under
88
the terms of the GNU General Public License as published by the Free Software
@@ -797,9 +797,9 @@ btr_index_rec_validate(
797797
__attribute__((nonnull, warn_unused_result));
798798
/**************************************************************//**
799799
Checks the consistency of an index tree.
800-
@return TRUE if ok */
800+
@return DB_SUCCESS if ok, error code if not */
801801
UNIV_INTERN
802-
bool
802+
dberr_t
803803
btr_validate_index(
804804
/*===============*/
805805
dict_index_t* index, /*!< in: index */

storage/xtradb/btr/btr0btr.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5159,18 +5159,20 @@ btr_validate_level(
51595159

51605160
/**************************************************************//**
51615161
Checks the consistency of an index tree.
5162-
@return TRUE if ok */
5162+
@return DB_SUCCESS if ok, error code if not */
51635163
UNIV_INTERN
5164-
bool
5164+
dberr_t
51655165
btr_validate_index(
51665166
/*===============*/
51675167
dict_index_t* index, /*!< in: index */
51685168
const trx_t* trx) /*!< in: transaction or NULL */
51695169
{
5170+
dberr_t err = DB_SUCCESS;
5171+
51705172
/* Full Text index are implemented by auxiliary tables,
51715173
not the B-tree */
51725174
if (dict_index_is_online_ddl(index) || (index->type & DICT_FTS)) {
5173-
return(true);
5175+
return(err);
51745176
}
51755177

51765178
mtr_t mtr;
@@ -5179,28 +5181,33 @@ btr_validate_index(
51795181

51805182
mtr_x_lock(dict_index_get_lock(index), &mtr);
51815183

5182-
bool ok = true;
51835184
page_t* root = btr_root_get(index, &mtr);
51845185

5186+
if (root == NULL && index->table->is_encrypted) {
5187+
err = DB_DECRYPTION_FAILED;
5188+
mtr_commit(&mtr);
5189+
return err;
5190+
}
5191+
51855192
SRV_CORRUPT_TABLE_CHECK(root,
51865193
{
51875194
mtr_commit(&mtr);
5188-
return(FALSE);
5195+
return(DB_CORRUPTION);
51895196
});
51905197

51915198
ulint n = btr_page_get_level(root, &mtr);
51925199

51935200
for (ulint i = 0; i <= n; ++i) {
51945201

51955202
if (!btr_validate_level(index, trx, n - i)) {
5196-
ok = false;
5203+
err = DB_CORRUPTION;
51975204
break;
51985205
}
51995206
}
52005207

52015208
mtr_commit(&mtr);
52025209

5203-
return(ok);
5210+
return(err);
52045211
}
52055212

52065213
/**************************************************************//**

storage/xtradb/handler/ha_innodb.cc

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14041,7 +14041,7 @@ ha_innobase::check(
1404114041
server_mutex,
1404214042
srv_fatal_semaphore_wait_threshold,
1404314043
SRV_SEMAPHORE_WAIT_EXTENSION);
14044-
bool valid = btr_validate_index(index, prebuilt->trx);
14044+
dberr_t err = btr_validate_index(index, prebuilt->trx);
1404514045

1404614046
/* Restore the fatal lock wait timeout after
1404714047
CHECK TABLE. */
@@ -14050,19 +14050,33 @@ ha_innobase::check(
1405014050
srv_fatal_semaphore_wait_threshold,
1405114051
SRV_SEMAPHORE_WAIT_EXTENSION);
1405214052

14053-
if (!valid) {
14053+
if (err != DB_SUCCESS) {
1405414054
is_ok = false;
1405514055

1405614056
innobase_format_name(
1405714057
index_name, sizeof index_name,
1405814058
index->name, TRUE);
14059-
push_warning_printf(
14060-
thd,
14061-
Sql_condition::WARN_LEVEL_WARN,
14062-
ER_NOT_KEYFILE,
14063-
"InnoDB: The B-tree of"
14064-
" index %s is corrupted.",
14065-
index_name);
14059+
14060+
if (err == DB_DECRYPTION_FAILED) {
14061+
push_warning_printf(
14062+
thd,
14063+
Sql_condition::WARN_LEVEL_WARN,
14064+
ER_NO_SUCH_TABLE,
14065+
"Table %s is encrypted but encryption service or"
14066+
" used key_id is not available. "
14067+
" Can't continue checking table.",
14068+
14069+
index->table->name);
14070+
} else {
14071+
push_warning_printf(
14072+
thd,
14073+
Sql_condition::WARN_LEVEL_WARN,
14074+
ER_NOT_KEYFILE,
14075+
"InnoDB: The B-tree of"
14076+
" index %s is corrupted.",
14077+
index_name);
14078+
}
14079+
1406614080
continue;
1406714081
}
1406814082
}

storage/xtradb/include/btr0btr.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2012, Facebook Inc.
5-
Copyright (c) 2014, SkySQL Ab. All Rights Reserved.
5+
Copyright (c) 2014, 2015, MariaDB Corporation. All Rights Reserved.
66
77
This program is free software; you can redistribute it and/or modify it under
88
the terms of the GNU General Public License as published by the Free Software
@@ -800,9 +800,9 @@ btr_index_rec_validate(
800800
__attribute__((nonnull, warn_unused_result));
801801
/**************************************************************//**
802802
Checks the consistency of an index tree.
803-
@return TRUE if ok */
803+
@return DB_SUCCESS if ok, error code if not */
804804
UNIV_INTERN
805-
bool
805+
dberr_t
806806
btr_validate_index(
807807
/*===============*/
808808
dict_index_t* index, /*!< in: index */

0 commit comments

Comments
 (0)