Skip to content

Commit ddaddf1

Browse files
author
Jan Lindström
committed
MDEV-8769: Server crash at file btr0btr.ic line 122 when defragmenting encrypted table using incorrect keys
Add error handling when getting block from encrypted table and decryption fails.
1 parent 71b1444 commit ddaddf1

File tree

13 files changed

+249
-40
lines changed

13 files changed

+249
-40
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
OPTIMIZE TABLE t1;
14+
Table Op Msg_type Msg_text
15+
test.t1 optimize Warning Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue checking table.
16+
test.t1 optimize Warning InnoDB: Cannot defragment table test/t1: returned error code 192
17+
18+
test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
19+
test.t1 optimize error 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
20+
test.t1 optimize status Operation failed
21+
Warnings:
22+
Warning 192 Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
23+
Error 1296 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
24+
SHOW WARNINGS;
25+
Level Code Message
26+
Warning 192 Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue reading table.
27+
Error 1296 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
28+
DROP TABLE t1;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--loose-innodb-buffer-pool-stats
2+
--loose-innodb-buffer-page
3+
--loose-innodb-buffer-page-lru
4+
--innodb-defragment=1
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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-8769: Server crash at file btr0btr.ic line 122 when defragmenting 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-defragment=1 --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-defragment=1 --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+
OPTIMIZE 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-defragment=1 --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+
--remove_file $MYSQLTEST_VARDIR/keys1.txt
82+
83+
# reset system
84+
--disable_query_log
85+
EVAL SET GLOBAL innodb_file_per_table = $innodb_file_per_table_orig;
86+
EVAL SET GLOBAL innodb_file_format = $innodb_file_format_orig;
87+
--enable_query_log

storage/innobase/btr/btr0defragment.cc

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (C) 2013, 2014 Facebook, Inc. All Rights Reserved.
4-
Copyright (C) 2014, SkySQL Ab. All Rights Reserved.
4+
Copyright (C) 2014, 2015, MariaDB Corporation. All Rights Reserved.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -22,7 +22,7 @@ Index defragmentation.
2222
2323
Created 05/29/2014 Rongrong Zhong
2424
Modified 16/07/2014 Sunguck Lee
25-
Modified 30/07/2014 Jan Lindström jan.lindstrom@skysql.com
25+
Modified 30/07/2014 Jan Lindström jan.lindstrom@mariadb.com
2626
*******************************************************/
2727

2828
#include "btr0defragment.h"
@@ -208,16 +208,27 @@ synchronized defragmentation. */
208208
os_event_t
209209
btr_defragment_add_index(
210210
dict_index_t* index, /*!< index to be added */
211-
bool async) /*!< whether this is an async defragmentation */
211+
bool async, /*!< whether this is an async
212+
defragmentation */
213+
dberr_t* err) /*!< out: error code */
212214
{
213215
mtr_t mtr;
214216
ulint space = dict_index_get_space(index);
215217
ulint zip_size = dict_table_zip_size(index->table);
216218
ulint page_no = dict_index_get_page(index);
219+
*err = DB_SUCCESS;
220+
217221
mtr_start(&mtr);
218222
// Load index rood page.
219223
page_t* page = btr_page_get(space, zip_size, page_no,
220224
RW_NO_LATCH, index, &mtr);
225+
226+
if (page == NULL && index->table->is_encrypted) {
227+
mtr_commit(&mtr);
228+
*err = DB_DECRYPTION_FAILED;
229+
return NULL;
230+
}
231+
221232
if (btr_page_get_level(page, &mtr) == 0) {
222233
// Index root is a leaf page, no need to defragment.
223234
mtr_commit(&mtr);

storage/innobase/handler/ha_innodb.cc

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12168,21 +12168,29 @@ ha_innobase::defragment_table(
1216812168
const char* index_name, /*!< in: index name */
1216912169
bool async) /*!< in: whether to wait until finish */
1217012170
{
12171-
char norm_name[FN_REFLEN];
12172-
dict_table_t* table;
12173-
dict_index_t* index;
12171+
char norm_name[FN_REFLEN];
12172+
dict_table_t* table = NULL;
12173+
dict_index_t* index = NULL;
1217412174
ibool one_index = (index_name != 0);
1217512175
int ret = 0;
12176+
dberr_t err = DB_SUCCESS;
12177+
1217612178
if (!srv_defragment) {
1217712179
return ER_FEATURE_DISABLED;
1217812180
}
12181+
1217912182
normalize_table_name(norm_name, name);
12183+
1218012184
table = dict_table_open_on_name(norm_name, FALSE,
1218112185
FALSE, DICT_ERR_IGNORE_NONE);
12186+
1218212187
for (index = dict_table_get_first_index(table); index;
1218312188
index = dict_table_get_next_index(index)) {
12184-
if (one_index && strcasecmp(index_name, index->name) != 0)
12189+
12190+
if (one_index && strcasecmp(index_name, index->name) != 0) {
1218512191
continue;
12192+
}
12193+
1218612194
if (btr_defragment_find_index(index)) {
1218712195
// We borrow this error code. When the same index is
1218812196
// already in the defragmentation queue, issue another
@@ -12197,7 +12205,23 @@ ha_innobase::defragment_table(
1219712205
ret = ER_SP_ALREADY_EXISTS;
1219812206
break;
1219912207
}
12200-
os_event_t event = btr_defragment_add_index(index, async);
12208+
12209+
os_event_t event = btr_defragment_add_index(index, async, &err);
12210+
12211+
if (err != DB_SUCCESS) {
12212+
push_warning_printf(
12213+
current_thd,
12214+
Sql_condition::WARN_LEVEL_WARN,
12215+
ER_NO_SUCH_TABLE,
12216+
"Table %s is encrypted but encryption service or"
12217+
" used key_id is not available. "
12218+
" Can't continue checking table.",
12219+
index->table->name);
12220+
12221+
ret = convert_error_code_to_mysql(err, 0, current_thd);
12222+
break;
12223+
}
12224+
1220112225
if (!async && event) {
1220212226
while(os_event_wait_time(event, 1000000)) {
1220312227
if (thd_killed(current_thd)) {
@@ -12208,18 +12232,23 @@ ha_innobase::defragment_table(
1220812232
}
1220912233
os_event_free(event);
1221012234
}
12235+
1221112236
if (ret) {
1221212237
break;
1221312238
}
12239+
1221412240
if (one_index) {
1221512241
one_index = FALSE;
1221612242
break;
1221712243
}
1221812244
}
12245+
1221912246
dict_table_close(table, FALSE, FALSE);
12247+
1222012248
if (ret == 0 && one_index) {
1222112249
ret = ER_NO_SUCH_INDEX;
1222212250
}
12251+
1222312252
return ret;
1222412253
}
1222512254

@@ -13536,7 +13565,6 @@ ha_innobase::check(
1353613565
"Table %s is encrypted but encryption service or"
1353713566
" used key_id is not available. "
1353813567
" Can't continue checking table.",
13539-
1354013568
index->table->name);
1354113569
} else {
1354213570
push_warning_printf(

storage/innobase/include/btr0btr.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,8 @@ btr_block_get_func(
259259
ulint mode, /*!< in: latch mode */
260260
const char* file, /*!< in: file name */
261261
ulint line, /*!< in: line where called */
262-
# ifdef UNIV_SYNC_DEBUG
263-
const dict_index_t* index, /*!< in: index tree, may be NULL
262+
dict_index_t* index, /*!< in: index tree, may be NULL
264263
if it is not an insert buffer tree */
265-
# endif /* UNIV_SYNC_DEBUG */
266264
mtr_t* mtr); /*!< in/out: mini-transaction */
267265
# ifdef UNIV_SYNC_DEBUG
268266
/** Gets a buffer page and declares its latching order level.
@@ -275,7 +273,7 @@ btr_block_get_func(
275273
@return the block descriptor */
276274
# define btr_block_get(space,zip_size,page_no,mode,index,mtr) \
277275
btr_block_get_func(space,zip_size,page_no,mode, \
278-
__FILE__,__LINE__,index,mtr)
276+
__FILE__,__LINE__,(dict_index_t*)index,mtr)
279277
# else /* UNIV_SYNC_DEBUG */
280278
/** Gets a buffer page and declares its latching order level.
281279
@param space tablespace identifier
@@ -286,7 +284,8 @@ btr_block_get_func(
286284
@param mtr mini-transaction handle
287285
@return the block descriptor */
288286
# define btr_block_get(space,zip_size,page_no,mode,idx,mtr) \
289-
btr_block_get_func(space,zip_size,page_no,mode,__FILE__,__LINE__,mtr)
287+
btr_block_get_func(space,zip_size,page_no,mode, \
288+
__FILE__,__LINE__,(dict_index_t*)idx,mtr)
290289
# endif /* UNIV_SYNC_DEBUG */
291290
/** Gets a buffer page and declares its latching order level.
292291
@param space tablespace identifier
@@ -297,7 +296,8 @@ btr_block_get_func(
297296
@param mtr mini-transaction handle
298297
@return the uncompressed page frame */
299298
# define btr_page_get(space,zip_size,page_no,mode,idx,mtr) \
300-
buf_block_get_frame(btr_block_get(space,zip_size,page_no,mode,idx,mtr))
299+
buf_block_get_frame(btr_block_get(space,zip_size,page_no, \
300+
mode,(dict_index_t*)idx,mtr))
301301
#endif /* !UNIV_HOTBACKUP */
302302
/**************************************************************//**
303303
Gets the index id field of a page.

storage/innobase/include/btr0btr.ic

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,19 @@ btr_block_get_func(
4949
ulint mode, /*!< in: latch mode */
5050
const char* file, /*!< in: file name */
5151
ulint line, /*!< in: line where called */
52-
#ifdef UNIV_SYNC_DEBUG
53-
const dict_index_t* index, /*!< in: index tree, may be NULL
52+
dict_index_t* index, /*!< in: index tree, may be NULL
5453
if it is not an insert buffer tree */
55-
#endif /* UNIV_SYNC_DEBUG */
5654
mtr_t* mtr) /*!< in/out: mtr */
5755
{
5856
buf_block_t* block;
57+
dberr_t err;
5958

6059
block = buf_page_get_gen(space, zip_size, page_no, mode,
61-
NULL, BUF_GET, file, line, mtr);
60+
NULL, BUF_GET, file, line, mtr, &err);
61+
62+
if (err == DB_DECRYPTION_FAILED) {
63+
index->table->is_encrypted = true;
64+
}
6265

6366
if (block) {
6467
if (mode != RW_NO_LATCH) {

storage/innobase/include/btr0defragment.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (C) 2013, 2014 Facebook, Inc. All Rights Reserved.
4+
Copyright (C) 2014, 2015, MariaDB Corporation.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License as published by the Free Software
@@ -67,7 +68,9 @@ is a synchronized defragmentation. */
6768
os_event_t
6869
btr_defragment_add_index(
6970
dict_index_t* index, /*!< index to be added */
70-
bool async); /*!< whether this is an async defragmentation */
71+
bool async, /*!< whether this is an async
72+
defragmentation */
73+
dberr_t* err); /*!< out: error code */
7174
/******************************************************************//**
7275
When table is dropped, this function is called to mark a table as removed in
7376
btr_efragment_wq. The difference between this function and the remove_index

storage/xtradb/btr/btr0defragment.cc

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (C) 2012, 2014 Facebook, Inc. All Rights Reserved.
4-
Copyright (C) 2014, SkySQL Ab. All Rights Reserved.
4+
Copyright (C) 2014, 2015, MariaDB Corporation. All Rights Reserved.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -22,7 +22,7 @@ Index defragmentation.
2222
2323
Created 05/29/2014 Rongrong Zhong
2424
Modified 16/07/2014 Sunguck Lee
25-
Modified 30/07/2014 Jan Lindström jan.lindstrom@skysql.com
25+
Modified 30/07/2014 Jan Lindström jan.lindstrom@mariadb.com
2626
*******************************************************/
2727

2828
#include "btr0defragment.h"
@@ -208,16 +208,27 @@ synchronized defragmentation. */
208208
os_event_t
209209
btr_defragment_add_index(
210210
dict_index_t* index, /*!< index to be added */
211-
bool async) /*!< whether this is an async defragmentation */
211+
bool async, /*!< whether this is an async
212+
defragmentation */
213+
dberr_t* err) /*!< out: error code */
212214
{
213215
mtr_t mtr;
214216
ulint space = dict_index_get_space(index);
215217
ulint zip_size = dict_table_zip_size(index->table);
216218
ulint page_no = dict_index_get_page(index);
219+
*err = DB_SUCCESS;
220+
217221
mtr_start(&mtr);
218222
// Load index rood page.
219223
page_t* page = btr_page_get(space, zip_size, page_no,
220224
RW_NO_LATCH, index, &mtr);
225+
226+
if (page == NULL && index->table->is_encrypted) {
227+
mtr_commit(&mtr);
228+
*err = DB_DECRYPTION_FAILED;
229+
return NULL;
230+
}
231+
221232
if (btr_page_get_level(page, &mtr) == 0) {
222233
// Index root is a leaf page, no need to defragment.
223234
mtr_commit(&mtr);

0 commit comments

Comments
 (0)