Skip to content

Commit e197823

Browse files
author
Jan Lindström
committed
MDEV-8588: Assertion failure in file ha_innodb.cc line 21140 if at least one encrypted table exists and encryption service is not available
Analysis: Problem was that in fil_read_first_page we do find that table has encryption information and that encryption service or used key_id is not available. But, then we just printed fatal error message that causes above assertion. Fix: When we open single table tablespace if it has encryption information (crypt_data) store this crypt data to the table structure. When we open a table and we find out that tablespace is not available, check has table a encryption information and from there is encryption service or used key_id is not available. If it is, add additional warning for SQL-layer.
1 parent e9b6f95 commit e197823

File tree

17 files changed

+223
-33
lines changed

17 files changed

+223
-33
lines changed

mysql-test/mysql-test-run.pl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4435,6 +4435,20 @@ ($$)
44354435
qr|SSL error: Failed to set ciphers to use|,
44364436
qr/Plugin 'InnoDB' will be forced to shutdown/,
44374437
qr|Could not increase number of max_open_files to more than|,
4438+
qr/InnoDB: Error table encrypted but encryption service not available.*/,
4439+
qr/InnoDB: Could not find a valid tablespace file for*/,
4440+
qr/InnoDB: Tablespace open failed for*/,
4441+
qr/InnoDB: Failed to find tablespace for table*/,
4442+
qr/InnoDB: Space */,
4443+
qr|InnoDB: You may have to recover from a backup|,
4444+
qr|InnoDB: It is also possible that your operatingsystem has corrupted its own file cache|,
4445+
qr|InnoDB: and rebooting your computer removes the error|,
4446+
qr|InnoDB: If the corrupt page is an index page you can also try to|,
4447+
qr|nnoDB: fix the corruption by dumping, dropping, and reimporting|,
4448+
qr|InnoDB: the corrupt table. You can use CHECK|,
4449+
qr|InnoDB: TABLE to scan your table for corruption|,
4450+
qr/InnoDB: See also */
4451+
44384452
);
44394453

44404454
my $matched_lines= [];
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
2+
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
3+
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
4+
5+
# Start server with keys2.txt
6+
SET GLOBAL innodb_file_format = `Barracuda`;
7+
SET GLOBAL innodb_file_per_table = ON;
8+
CREATE TABLE t1 (c VARCHAR(8)) ENGINE=InnoDB ENCRYPTED=YES ENCRYPTION_KEY_ID=2;
9+
INSERT INTO t1 VALUES ('foobar');
10+
ALTER TABLE t1 ADD COLUMN c2 INT;
11+
INSERT INTO t1 VALUES ('foobar',2);
12+
SELECT * FROM t1;
13+
c c2
14+
foobar NULL
15+
foobar 2
16+
TRUNCATE TABLE t1;
17+
SELECT * FROM t1;
18+
c c2
19+
INSERT INTO t1 VALUES ('foobar',1);
20+
INSERT INTO t1 VALUES ('foobar',2);
21+
FLUSH TABLE WITH READ LOCK;
22+
SELECT * FROM t1;
23+
c c2
24+
foobar 1
25+
foobar 2
26+
27+
# Restart server with keysbad3.txt
28+
SELECT * FROM t1;
29+
ERROR 42S02: Table 'test.t1' doesn't exist in engine
30+
SHOW WARNINGS;
31+
Level Code Message
32+
Warning 1812 Tablespace is missing for table 'test/t1'
33+
Warning 155 Table test/t1 is encrypted but encryption service or used key_id 2 is not available. Can't continue reading table.
34+
Error 1932 Table 'test.t1' doesn't exist in engine
35+
DROP TABLE t1;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
6+
call mtr.add_suppression("Plugin 'file_key_management' init function returned error");
7+
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
8+
call mtr.add_suppression("Plugin 'file_key_management' registration.*failed");
9+
10+
--echo
11+
--echo # Start server with keys2.txt
12+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keys2.txt
13+
-- source include/restart_mysqld.inc
14+
15+
--disable_query_log
16+
let $innodb_file_format_orig = `SELECT @@innodb_file_format`;
17+
let $innodb_file_per_table_orig = `SELECT @@innodb_file_per_table`;
18+
--enable_query_log
19+
20+
SET GLOBAL innodb_file_format = `Barracuda`;
21+
SET GLOBAL innodb_file_per_table = ON;
22+
23+
CREATE TABLE t1 (c VARCHAR(8)) ENGINE=InnoDB ENCRYPTED=YES ENCRYPTION_KEY_ID=2;
24+
INSERT INTO t1 VALUES ('foobar');
25+
ALTER TABLE t1 ADD COLUMN c2 INT;
26+
INSERT INTO t1 VALUES ('foobar',2);
27+
SELECT * FROM t1;
28+
TRUNCATE TABLE t1;
29+
SELECT * FROM t1;
30+
INSERT INTO t1 VALUES ('foobar',1);
31+
INSERT INTO t1 VALUES ('foobar',2);
32+
FLUSH TABLE WITH READ LOCK;
33+
SELECT * FROM t1;
34+
35+
--echo
36+
--echo # Restart server with keysbad3.txt
37+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keysbad3.txt
38+
-- source include/restart_mysqld.inc
39+
40+
--error 1932
41+
SELECT * FROM t1;
42+
SHOW WARNINGS;
43+
44+
-- let $restart_parameters=--file-key-management-filename=$MYSQL_TEST_DIR/std_data/keysbad3.txt
45+
-- source include/restart_mysqld.inc
46+
DROP TABLE t1;

mysql-test/suite/innodb/r/innodb_bug14147491.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
12
CALL mtr.add_suppression("InnoDB: Error: Unable to read tablespace .* page no .* into the buffer pool after 100 attempts");
23
CALL mtr.add_suppression("InnoDB: Warning: database page corruption or a failed");
34
CALL mtr.add_suppression("InnoDB: Database page corruption on disk or a failed");

mysql-test/suite/innodb/t/innodb_bug14147491.test

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
-- source include/not_encrypted.inc
66

7+
call mtr.add_suppression("InnoDB: Database page corruption on disk or a failed.*");
8+
79
# Don't test under valgrind, memory leaks will occur
810
source include/not_valgrind.inc;
911
# Avoid CrashReporter popup on Mac

storage/innobase/dict/dict0load.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ dict_check_tablespaces_and_store_max_id(
11681168
dberr_t err = fil_open_single_table_tablespace(
11691169
read_page_0, srv_read_only_mode ? false : true,
11701170
space_id, dict_tf_to_fsp_flags(flags),
1171-
name, filepath);
1171+
name, filepath, NULL);
11721172

11731173
if (err != DB_SUCCESS) {
11741174
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -2412,7 +2412,7 @@ dict_load_table(
24122412
err = fil_open_single_table_tablespace(
24132413
true, false, table->space,
24142414
dict_tf_to_fsp_flags(table->flags),
2415-
name, filepath);
2415+
name, filepath, table);
24162416

24172417
if (err != DB_SUCCESS) {
24182418
/* We failed to find a sensible

storage/innobase/fil/fil0fil.cc

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,7 @@ fil_read_first_page(
19861986
const char* check_msg = NULL;
19871987
fil_space_crypt_t* cdata;
19881988

1989+
19891990
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
19901991

19911992
/* Align the memory for a possible read from a raw device */
@@ -2015,23 +2016,25 @@ fil_read_first_page(
20152016
fsp_flags_get_zip_size(*flags), NULL);
20162017
cdata = fil_space_read_crypt_data(space, page, offset);
20172018

2019+
if (crypt_data) {
2020+
*crypt_data = cdata;
2021+
}
2022+
20182023
/* If file space is encrypted we need to have at least some
20192024
encryption service available where to get keys */
20202025
if ((cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_ON) ||
20212026
(srv_encrypt_tables &&
20222027
cdata && cdata->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
20232028

20242029
if (!encryption_key_id_exists(cdata->key_id)) {
2025-
ib_logf(IB_LOG_LEVEL_FATAL,
2026-
"Tablespace id %ld encrypted but encryption service"
2027-
" not available. Can't continue opening tablespace.\n",
2028-
space);
2029-
ut_error;
2030-
}
2031-
}
2030+
ib_logf(IB_LOG_LEVEL_ERROR,
2031+
"Tablespace id %ld is encrypted but encryption service"
2032+
" or used key_id %u is not available. Can't continue opening tablespace.",
2033+
space, cdata->key_id);
20322034

2033-
if (crypt_data) {
2034-
*crypt_data = cdata;
2035+
return ("table encrypted but encryption service not available.");
2036+
2037+
}
20352038
}
20362039

20372040
ut_free(buf);
@@ -3621,7 +3624,8 @@ fil_open_single_table_tablespace(
36213624
ulint flags, /*!< in: tablespace flags */
36223625
const char* tablename, /*!< in: table name in the
36233626
databasename/tablename format */
3624-
const char* path_in) /*!< in: tablespace filepath */
3627+
const char* path_in, /*!< in: tablespace filepath */
3628+
dict_table_t* table) /*!< in: table */
36253629
{
36263630
dberr_t err = DB_SUCCESS;
36273631
bool dict_filepath_same_as_default = false;
@@ -3738,6 +3742,10 @@ fil_open_single_table_tablespace(
37383742
&def.lsn, &def.lsn, &def.crypt_data);
37393743
def.valid = !def.check_msg;
37403744

3745+
if (table) {
3746+
table->crypt_data = def.crypt_data;
3747+
}
3748+
37413749
/* Validate this single-table-tablespace with SYS_TABLES,
37423750
but do not compare the DATA_DIR flag, in case the
37433751
tablespace was relocated. */
@@ -3763,6 +3771,10 @@ fil_open_single_table_tablespace(
37633771
&remote.lsn, &remote.lsn, &remote.crypt_data);
37643772
remote.valid = !remote.check_msg;
37653773

3774+
if (table) {
3775+
table->crypt_data = remote.crypt_data;
3776+
}
3777+
37663778
/* Validate this single-table-tablespace with SYS_TABLES,
37673779
but do not compare the DATA_DIR flag, in case the
37683780
tablespace was relocated. */
@@ -3789,6 +3801,10 @@ fil_open_single_table_tablespace(
37893801
&dict.lsn, &dict.lsn, &dict.crypt_data);
37903802
dict.valid = !dict.check_msg;
37913803

3804+
if (table) {
3805+
table->crypt_data = dict.crypt_data;
3806+
}
3807+
37923808
/* Validate this single-table-tablespace with SYS_TABLES,
37933809
but do not compare the DATA_DIR flag, in case the
37943810
tablespace was relocated. */
@@ -3970,7 +3986,9 @@ fil_open_single_table_tablespace(
39703986
mem_free(remote.filepath);
39713987
}
39723988
if (remote.crypt_data && remote.crypt_data != crypt_data) {
3973-
fil_space_destroy_crypt_data(&remote.crypt_data);
3989+
if (err == DB_SUCCESS) {
3990+
fil_space_destroy_crypt_data(&remote.crypt_data);
3991+
}
39743992
}
39753993
if (dict.success) {
39763994
os_file_close(dict.file);
@@ -3985,7 +4003,9 @@ fil_open_single_table_tablespace(
39854003
os_file_close(def.file);
39864004
}
39874005
if (def.crypt_data && def.crypt_data != crypt_data) {
3988-
fil_space_destroy_crypt_data(&def.crypt_data);
4006+
if (err == DB_SUCCESS) {
4007+
fil_space_destroy_crypt_data(&def.crypt_data);
4008+
}
39894009
}
39904010

39914011
mem_free(def.filepath);

storage/innobase/handler/ha_innodb.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5629,6 +5629,26 @@ ha_innobase::open(
56295629
free_share(share);
56305630
my_errno = ENOENT;
56315631

5632+
/* If table has no talespace but it has crypt data, check
5633+
is tablespace made unaccessible because encryption service
5634+
or used key_id is not available. */
5635+
if (ib_table && ib_table->crypt_data) {
5636+
fil_space_crypt_t* crypt_data = ib_table->crypt_data;
5637+
if ((crypt_data->encryption == FIL_SPACE_ENCRYPTION_ON) ||
5638+
(srv_encrypt_tables &&
5639+
crypt_data && crypt_data->encryption == FIL_SPACE_ENCRYPTION_DEFAULT)) {
5640+
5641+
if (!encryption_key_id_exists(crypt_data->key_id)) {
5642+
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
5643+
HA_ERR_NO_SUCH_TABLE,
5644+
"Table %s is encrypted but encryption service or"
5645+
" used key_id %u is not available. "
5646+
" Can't continue reading table.",
5647+
ib_table->name, crypt_data->key_id);
5648+
}
5649+
}
5650+
}
5651+
56325652
dict_table_close(ib_table, FALSE, FALSE);
56335653

56345654
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);

storage/innobase/include/dict0mem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ Created 1/8/1996 Heikki Tuuri
4848
#include "trx0types.h"
4949
#include "fts0fts.h"
5050
#include "os0once.h"
51+
#include "fil0fil.h"
52+
#include <my_crypt.h>
53+
#include "fil0crypt.h"
5154
#include <set>
5255
#include <algorithm>
5356
#include <iterator>
@@ -1014,6 +1017,7 @@ struct dict_table_t{
10141017
table_id_t id; /*!< id of the table */
10151018
mem_heap_t* heap; /*!< memory heap */
10161019
char* name; /*!< table name */
1020+
fil_space_crypt_t *crypt_data; /*!< crypt data if present */
10171021
const char* dir_path_of_temp_table;/*!< NULL or the directory path
10181022
where a TEMPORARY table that was explicitly
10191023
created by a user should be placed if

storage/innobase/include/fil0fil.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ struct fsp_open_info {
213213
#ifdef UNIV_LOG_ARCHIVE
214214
ulint arch_log_no; /*!< latest archived log file number */
215215
#endif /* UNIV_LOG_ARCHIVE */
216-
fil_space_crypt_t* crypt_data; /*!< crypt data */
216+
fil_space_crypt_t* crypt_data; /*!< crypt data */
217+
dict_table_t* table; /*!< table */
217218
};
218219

219220
struct fil_space_t;
@@ -833,7 +834,8 @@ fil_open_single_table_tablespace(
833834
ulint flags, /*!< in: tablespace flags */
834835
const char* tablename, /*!< in: table name in the
835836
databasename/tablename format */
836-
const char* filepath) /*!< in: tablespace filepath */
837+
const char* filepath, /*!< in: tablespace filepath */
838+
dict_table_t* table) /*!< in: table */
837839
__attribute__((nonnull(5), warn_unused_result));
838840

839841
#endif /* !UNIV_HOTBACKUP */

0 commit comments

Comments
 (0)