MDEV-26258 Various crashes/asserts/corruptions when Aria encryption is enabled/used, but the encryption plugin is not loaded

The reason for the MDEV reported failures is that the tests are enabling
encryption for Aria but not providing any encryption keys.

Fixed by checking if encryption keys exists before creating the table.

Other things:
- maria.encrypt_wrong-key changed as we now get the error on CREATE
  instead during insert.
This commit is contained in:
Monty 2023-03-16 17:24:12 +02:00
parent c6ef9b1c1a
commit 1ef22e28ad
14 changed files with 135 additions and 44 deletions

View file

@ -79,3 +79,4 @@
{ "HA_ERR_ABORTED_BY_USER", HA_ERR_ABORTED_BY_USER, "" },
{ "HA_ERR_DISK_FULL", HA_ERR_DISK_FULL, "" },
{ "HA_ERR_INCOMPATIBLE_DEFINITION", HA_ERR_INCOMPATIBLE_DEFINITION, "" },
{ "HA_ERR_NO_ENCRYPTION", HA_ERR_NO_ENCRYPTION, "" },

View file

@ -48,6 +48,7 @@
#define HA_OPEN_NO_PSI_CALL 1024U /* Don't call/connect PSI */
#define HA_OPEN_MERGE_TABLE 2048U
#define HA_OPEN_FOR_CREATE 4096U
#define HA_OPEN_FOR_DROP (1U << 13) /* Open part of drop */
/*
Allow opening even if table is incompatible as this is for ALTER TABLE which
@ -516,14 +517,15 @@ enum ha_base_keytype {
#define HA_ERR_DISK_FULL 189
#define HA_ERR_INCOMPATIBLE_DEFINITION 190
#define HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE 191 /* Too many words in a phrase */
#define HA_ERR_DECRYPTION_FAILED 192 /* Table encrypted but decypt failed */
#define HA_ERR_DECRYPTION_FAILED 192 /* Table encrypted but decrypt failed */
#define HA_ERR_FK_DEPTH_EXCEEDED 193 /* FK cascade depth exceeded */
#define HA_ERR_TABLESPACE_MISSING 194 /* Missing Tablespace */
#define HA_ERR_SEQUENCE_INVALID_DATA 195
#define HA_ERR_SEQUENCE_RUN_OUT 196
#define HA_ERR_COMMIT_ERROR 197
#define HA_ERR_PARTITION_LIST 198
#define HA_ERR_LAST 198 /* Copy of last error nr * */
#define HA_ERR_NO_ENCRYPTION 199
#define HA_ERR_LAST 199 /* Copy of last error nr * */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)

View file

@ -109,7 +109,8 @@ static const char *handler_error_messages[]=
"Sequence has been run out",
"Sequence values are conflicting",
"Error during commit",
"Cannot select partitions"
"Cannot select partitions",
"Cannot initialize encryption. Check that all encryption parameters have been set"
};
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */

View file

@ -11,7 +11,7 @@ let $counter= 5000;
let $mysql_errno= 9999;
while ($mysql_errno)
{
--error 0,ER_ACCESS_DENIED_ERROR,ER_SERVER_SHUTDOWN,ER_CONNECTION_KILLED,ER_LOCK_WAIT_TIMEOUT,2002,2006,2013
--error 0,ER_ACCESS_DENIED_ERROR,ER_SERVER_SHUTDOWN,ER_CONNECTION_KILLED,ER_LOCK_WAIT_TIMEOUT,2002,2006,2013,HA_ERR_NO_ENCRYPTION
show status;
dec $counter;
@ -30,6 +30,10 @@ while ($mysql_errno)
{
let $mysql_errno=0;
}
if ($mysql_errno == 199)
{
let $mysql_errno=0;
}
--sleep 0.1
}
--enable_query_log

View file

@ -1,15 +1,27 @@
call mtr.add_suppression('Unknown key id 1. Can''t continue');
call mtr.add_suppression("Initialization of encryption failed.*");
set global aria_encrypt_tables= 1;
create table t1 (pk int primary key, a int, key(a)) engine=aria transactional=1;
alter table t1 disable keys;
insert into t1 values (1,1);
alter table t1 enable keys;
ERROR HY000: Unknown key id 1. Can't continue!
repair table t1 use_frm;
Table Op Msg_type Msg_text
test.t1 repair warning Number of rows changed from 0 to 1
test.t1 repair Error Unknown key id 1. Can't continue!
test.t1 repair Error Unknown key id 1. Can't continue!
test.t1 repair status OK
drop table t1;
ERROR HY000: Initialization of encryption failed for ./test/t1
set global aria_encrypt_tables= default;
#
# MDEV-26258 Various crashes/asserts/corruptions when Aria encryption is
# enabled/used, but the encryption plugin is not loaded
#
SET GLOBAL aria_encrypt_tables=ON;
CREATE TABLE t1 (a INT KEY,b INT,KEY(b)) ENGINE=Aria;
ERROR HY000: Initialization of encryption failed for ./test/t1
# Restart with encryption enabled
CREATE TABLE t1 (a INT KEY,b INT,KEY(b)) ENGINE=Aria;
INSERT INTO t1 VALUES (4,0);
LOAD INDEX INTO CACHE t1 IGNORE LEAVES;
Table Op Msg_type Msg_text
test.t1 preload_keys status OK
LOAD INDEX INTO CACHE t1;
Table Op Msg_type Msg_text
test.t1 preload_keys status OK
SELECT * FROM t1;
ERROR HY000: Initialization of encryption failed for ./test/t1.MAD
DROP TABLE t1;
Warnings:
Warning 199 Initialization of encryption failed for ./test/t1.MAD
Cleanup

View file

@ -1,14 +1,55 @@
#
# MDEV-18496 Crash when Aria encryption is enabled but plugin not available
#
call mtr.add_suppression('Unknown key id 1. Can''t continue');
call mtr.add_suppression("Initialization of encryption failed.*");
set global aria_encrypt_tables= 1;
--error HA_ERR_NO_ENCRYPTION
create table t1 (pk int primary key, a int, key(a)) engine=aria transactional=1;
alter table t1 disable keys;
insert into t1 values (1,1);
error 192;
alter table t1 enable keys;
repair table t1 use_frm;
drop table t1;
set global aria_encrypt_tables= default;
--echo #
--echo # MDEV-26258 Various crashes/asserts/corruptions when Aria encryption is
--echo # enabled/used, but the encryption plugin is not loaded
--echo #
SET GLOBAL aria_encrypt_tables=ON;
--write_file $MYSQLTEST_VARDIR/keys1.txt
1;770A8A65DA156D24EE2A093277530142
EOF
--replace_result \\ /
--error HA_ERR_NO_ENCRYPTION
CREATE TABLE t1 (a INT KEY,b INT,KEY(b)) ENGINE=Aria;
--echo # Restart with encryption enabled
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--exec echo "restart:--aria-encrypt-tables=1 --plugin-load-add=file_key_management --file-key-management --file-key-management-filename=$MYSQLTEST_VARDIR/keys1.txt" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
CREATE TABLE t1 (a INT KEY,b INT,KEY(b)) ENGINE=Aria;
INSERT INTO t1 VALUES (4,0);
LOAD INDEX INTO CACHE t1 IGNORE LEAVES;
LOAD INDEX INTO CACHE t1;
# Restart without encryption. Above table should be unreadable
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
--source include/wait_until_disconnected.inc
--exec echo "restart:--aria-encrypt-tables=0" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--enable_reconnect
--source include/wait_until_connected_again.inc
--replace_result \\ /
--error HA_ERR_NO_ENCRYPTION
SELECT * FROM t1;
DROP TABLE t1;
--echo Cleanup
--remove_file $MYSQLTEST_VARDIR/keys1.txt

View file

@ -1,16 +1,16 @@
call mtr.add_suppression("file_key_management");
call mtr.add_suppression("System key id 1 is missing");
call mtr.add_suppression("Unknown key id 1");
call mtr.add_suppression("Failed to decrypt");
call mtr.add_suppression("Initialization of encryption failed.*");
CREATE TABLE t1 (i INT, KEY(i)) ENGINE=Aria;
INSERT INTO t1 VALUES (1);
repair table t1;
Table Op Msg_type Msg_text
test.t1 repair info Wrong CRC on datapage at 1
test.t1 repair warning Number of rows changed from 1 to 0
test.t1 repair status OK
test.t1 repair Error Initialization of encryption failed for ./test/t1.MAD
test.t1 repair error Corrupt
INSERT INTO t1 VALUES (2);
ERROR HY000: Initialization of encryption failed for ./test/t1.MAD
select * from t1;
ERROR HY000: failed to decrypt './test/t1' rc: -1 dstlen: 0 size: 8172
i
1
drop table t1;

View file

@ -7,7 +7,7 @@
call mtr.add_suppression("file_key_management");
call mtr.add_suppression("System key id 1 is missing");
call mtr.add_suppression("Unknown key id 1");
call mtr.add_suppression("Failed to decrypt");
call mtr.add_suppression("Initialization of encryption failed.*");
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
--shutdown_server
@ -36,8 +36,11 @@ EOF
--enable_reconnect
--source include/wait_until_connected_again.inc
--replace_result \\ /
repair table t1;
--replace_result \\ /
--error HA_ERR_NO_ENCRYPTION
INSERT INTO t1 VALUES (2);
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
@ -48,8 +51,6 @@ INSERT INTO t1 VALUES (2);
--enable_reconnect
--source include/wait_until_connected_again.inc
--replace_result \\ /
--error 192
select * from t1;
drop table t1;
--remove_file $MYSQLTEST_VARDIR/keys1.txt

View file

@ -292,7 +292,8 @@ static MYSQL_SYSVAR_BOOL(used_for_temp_tables,
"Whether temporary tables should be MyISAM or Aria", 0, 0,
1);
static MYSQL_SYSVAR_BOOL(encrypt_tables, maria_encrypt_tables, PLUGIN_VAR_OPCMDARG,
static MYSQL_SYSVAR_BOOL(encrypt_tables, maria_encrypt_tables,
PLUGIN_VAR_OPCMDARG,
"Encrypt tables (only for tables with ROW_FORMAT=PAGE (default) "
"and not FIXED/DYNAMIC)",
0, 0, 0);

View file

@ -1062,6 +1062,8 @@ int maria_create(const char *name, enum data_file_type datafile_type,
if (encrypted)
{
DBUG_ASSERT(share.data_file_name.length == 0);
share.data_file_name.str= (char*) name; /* For error reporting */
if (ma_crypt_create(&share) ||
ma_crypt_write(&share, file))
goto err;

View file

@ -100,6 +100,7 @@ static void crypt_data_scheme_locker(struct st_encryption_scheme *scheme,
int
ma_crypt_create(MARIA_SHARE* share)
{
uint key_version;
MARIA_CRYPT_DATA *crypt_data=
(MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL));
crypt_data->scheme.type= CRYPT_SCHEME_1;
@ -110,6 +111,16 @@ ma_crypt_create(MARIA_SHARE* share)
my_random_bytes((uchar*)&crypt_data->space, sizeof(crypt_data->space));
share->crypt_data= crypt_data;
share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE;
key_version = encryption_key_get_latest_version(crypt_data->scheme.key_id);
if (unlikely(key_version == ENCRYPTION_KEY_VERSION_INVALID))
{
my_errno= HA_ERR_NO_ENCRYPTION;
my_printf_error(HA_ERR_NO_ENCRYPTION,
"Initialization of encryption failed for %s", MYF(0),
share->data_file_name.str);
return 1;
}
return 0;
}
@ -145,7 +156,7 @@ ma_crypt_write(MARIA_SHARE* share, File file)
}
uchar*
ma_crypt_read(MARIA_SHARE* share, uchar *buff)
ma_crypt_read(MARIA_SHARE* share, uchar *buff, my_bool silent)
{
uchar type= buff[0];
uchar iv_length= buff[1];
@ -155,9 +166,9 @@ ma_crypt_read(MARIA_SHARE* share, uchar *buff)
iv_length != sizeof(((MARIA_CRYPT_DATA*)1)->scheme.iv) + 4)
{
my_printf_error(HA_ERR_UNSUPPORTED,
"Unsupported crypt scheme! type: %d iv_length: %d\n",
MYF(ME_FATAL|ME_ERROR_LOG),
type, iv_length);
"Unsupported crypt scheme type: %d iv_length: %d\n",
MYF(ME_ERROR_LOG | (silent ? ME_WARNING : ME_FATAL)),
type, iv_length);
return 0;
}
@ -166,6 +177,7 @@ ma_crypt_read(MARIA_SHARE* share, uchar *buff)
/* opening a table */
MARIA_CRYPT_DATA *crypt_data=
(MARIA_CRYPT_DATA*)my_malloc(sizeof(MARIA_CRYPT_DATA), MYF(MY_ZEROFILL));
uint key_version;
crypt_data->scheme.type= type;
mysql_mutex_init(key_CRYPT_DATA_lock, &crypt_data->lock,
@ -175,6 +187,17 @@ ma_crypt_read(MARIA_SHARE* share, uchar *buff)
crypt_data->space= uint4korr(buff + 2);
memcpy(crypt_data->scheme.iv, buff + 6, sizeof(crypt_data->scheme.iv));
share->crypt_data= crypt_data;
key_version= encryption_key_get_latest_version(crypt_data->scheme.key_id);
if (unlikely(key_version == ENCRYPTION_KEY_VERSION_INVALID))
{
my_errno= HA_ERR_NO_ENCRYPTION;
my_printf_error(HA_ERR_NO_ENCRYPTION,
"Initialization of encryption failed for %s",
MYF(ME_ERROR_LOG | (silent ? ME_WARNING : ME_FATAL)),
share->data_file_name.str);
return 0;
}
}
share->crypt_page_header_space= CRYPT_SCHEME_1_KEY_VERSION_SIZE;
@ -462,7 +485,7 @@ static int ma_encrypt(MARIA_SHARE *share, MARIA_CRYPT_DATA *crypt_data,
uint32 dstlen= 0; /* Must be set because of error message */
*key_version = encryption_key_get_latest_version(crypt_data->scheme.key_id);
if (*key_version == ENCRYPTION_KEY_VERSION_INVALID)
if (unlikely(*key_version == ENCRYPTION_KEY_VERSION_INVALID))
{
/*
We use this error for both encryption and decryption, as in normal
@ -470,7 +493,7 @@ static int ma_encrypt(MARIA_SHARE *share, MARIA_CRYPT_DATA *crypt_data,
*/
my_errno= HA_ERR_DECRYPTION_FAILED;
my_printf_error(HA_ERR_DECRYPTION_FAILED,
"Unknown key id %u. Can't continue!",
"Unknown encryption key id %u. Can't continue!",
MYF(ME_FATAL|ME_ERROR_LOG),
crypt_data->scheme.key_id);
return 1;

View file

@ -26,7 +26,8 @@ uint ma_crypt_get_index_page_header_space(struct st_maria_share *);
uint ma_crypt_get_file_length(); /* bytes needed in file */
int ma_crypt_create(struct st_maria_share *); /* create encryption data */
int ma_crypt_write(struct st_maria_share *, File); /* write encryption data */
uchar* ma_crypt_read(struct st_maria_share *, uchar *buff); /* read crypt data*/
uchar* ma_crypt_read(struct st_maria_share *, uchar *buff,
my_bool silent); /* read crypt data*/
void ma_crypt_set_data_pagecache_callbacks(struct st_pagecache_file *file,
struct st_maria_share *share);

View file

@ -43,12 +43,13 @@ int maria_delete_table(const char *name)
'open_for_repair' to be able to open even a crashed table.
*/
my_errno= 0;
if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR)))
if (!(info= maria_open(name, O_RDONLY, (HA_OPEN_FOR_DROP | HA_OPEN_FOR_REPAIR))))
{
sync_dir= 0;
/* Ignore not found errors and wrong symlink errors */
if (my_errno != ENOENT && my_errno != HA_WRONG_CREATE_OPTION)
got_error= my_errno;;
if (my_errno != ENOENT && my_errno != HA_WRONG_CREATE_OPTION &&
my_errno != HA_ERR_NO_ENCRYPTION)
got_error= my_errno;
}
else
{

View file

@ -863,7 +863,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
if (MY_TEST(share->base.extra_options & MA_EXTRA_OPTIONS_ENCRYPTED))
{
if (!(disk_pos= ma_crypt_read(share, disk_pos)))
if (!(disk_pos= ma_crypt_read(share, disk_pos,
MY_TEST(open_flags & HA_OPEN_FOR_DROP))))
goto err;
}