Commit ca6e7781 authored by Alexander Nozdrin's avatar Alexander Nozdrin

Patch for Bug#12394306: the sever may crash if mysql.event is corrupted.

The problem was that wrong structure of mysql.event was not detected and
the server continued to use wrongly-structured data.

The fix is to check the structure of mysql.event after opening before
any use. That makes operations with events more strict -- some operations
that might work before throw errors now. That seems to be Ok.

Another side-effect of the patch is that if mysql.event is corrupted,
unrelated DROP DATABASE statements issue an SQL warning about inability
to open mysql.event table. 
parent 4f666e8e
call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
drop database if exists events_test;
drop database if exists db_x;
drop database if exists mysqltest_db2;
......@@ -259,33 +260,36 @@ events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLE
Try to alter mysql.event: the server should fail to load
event information after mysql.event was tampered with.
First, let's add a column to the end and make sure everything
works as before
First, let's add a column to the end and check the error is emitted.
ALTER TABLE mysql.event ADD dummy INT;
SHOW EVENTS;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.events;
event_name
intact_check
ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
intact_check SYSTEM CREATE EVENT `intact_check` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO SELECT "nothing" latin1 latin1_swedish_ci latin1_swedish_ci
ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
ERROR HY000: Unknown event 'no_such_event'
ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
Warnings:
Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
......@@ -294,6 +298,7 @@ Variable_name Value
event_scheduler OFF
SET GLOBAL event_scheduler=OFF;
ALTER TABLE mysql.event DROP dummy;
DROP EVENT intact_check;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
Now let's add a column to the first position: the server
......@@ -301,30 +306,32 @@ expects to see event schema name there
ALTER TABLE mysql.event ADD dummy INT FIRST;
SHOW EVENTS;
ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.events;
ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
ERROR HY000: Unknown event 'intact_check'
ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
ERROR HY000: Unknown event 'no_such_event'
ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ERROR HY000: Failed to store event name. Error code 2 from storage engine.
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
ERROR HY000: Unknown event 'intact_check_2'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
ERROR HY000: Unknown event 'intact_check'
ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
Warnings:
Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
......@@ -345,29 +352,32 @@ Drop some columns and try more checks.
ALTER TABLE mysql.event DROP comment, DROP starts;
SHOW EVENTS;
ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
ERROR HY000: Unknown event 'no_such_event'
ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ERROR HY000: Column count of mysql.event is wrong. Expected 22, found 20. The table is probably corrupted
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
ERROR HY000: Unknown event 'intact_check_1'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
ERROR HY000: Unknown event 'intact_check_2'
ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
Warnings:
Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
......@@ -425,4 +435,42 @@ CREATE TABLE mysql.event like event_like;
DROP TABLE event_like;
SHOW EVENTS;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
#
# Bug#12394306: the sever may crash if mysql.event is corrupted
#
CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
CREATE TABLE event_original LIKE mysql.event;
INSERT INTO event_original SELECT * FROM mysql.event;
ALTER TABLE mysql.event MODIFY modified CHAR(1);
Warnings:
Warning 1265 Data truncated for column 'modified' at row 1
SHOW EVENTS;
ERROR HY000: Failed to open mysql.event
SELECT event_name, created, last_altered FROM information_schema.events;
ERROR HY000: Failed to open mysql.event
CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ERROR HY000: Failed to open mysql.event
ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9;
ERROR HY000: Failed to open mysql.event
DROP TABLE mysql.event;
RENAME TABLE event_original TO mysql.event;
DROP EVENT ev1;
SHOW EVENTS;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
#
# End of tests
#
drop database events_test;
call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
set global event_scheduler=off;
drop database if exists events_test;
create database events_test;
......@@ -52,6 +53,8 @@ Warnings:
Note 1008 Can't drop database 'mysqltest_database_not_exists'; database doesn't exist
create database mysqltest_db1;
drop database mysqltest_db1;
Warnings:
Error 1545 Failed to open mysql.event
Restore the original mysql.event table
drop table mysql.event;
rename table event_like to mysql.event;
......
......@@ -4,6 +4,8 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
--disable_warnings
drop database if exists events_test;
drop database if exists db_x;
......@@ -270,23 +272,28 @@ SHOW EVENTS;
--echo Try to alter mysql.event: the server should fail to load
--echo event information after mysql.event was tampered with.
--echo
--echo First, let's add a column to the end and make sure everything
--echo works as before
--echo First, let's add a column to the end and check the error is emitted.
--echo
ALTER TABLE mysql.event ADD dummy INT;
--replace_column 8 # 9 #
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.events;
--replace_regex /STARTS '[^']+'/STARTS '#'/
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
DROP DATABASE IF EXISTS mysqltest_no_such_database;
CREATE DATABASE mysqltest_db2;
......@@ -296,6 +303,7 @@ SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler=OFF;
# Clean up
ALTER TABLE mysql.event DROP dummy;
DROP EVENT intact_check;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
--echo
--echo Now let's add a column to the first position: the server
......@@ -303,24 +311,26 @@ CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
--echo
ALTER TABLE mysql.event ADD dummy INT FIRST;
--error ER_CANNOT_LOAD_FROM_TABLE
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
--error ER_CANNOT_LOAD_FROM_TABLE
--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.events;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
--error ER_EVENT_STORE_FAILED
--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
# Should work OK
DROP DATABASE IF EXISTS mysqltest_no_such_database;
......@@ -341,25 +351,25 @@ INSERT INTO event_like SELECT * FROM mysql.event;
--echo
--echo
ALTER TABLE mysql.event DROP comment, DROP starts;
--error ER_CANNOT_LOAD_FROM_TABLE
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
--error ER_CANNOT_LOAD_FROM_TABLE
--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
--error ER_CANNOT_LOAD_FROM_TABLE
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
--error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
--error ER_EVENT_DOES_NOT_EXIST
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
# Should succeed
--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
DROP DATABASE IF EXISTS mysqltest_no_such_database;
CREATE DATABASE mysqltest_db2;
......@@ -407,9 +417,54 @@ CREATE TABLE mysql.event like event_like;
DROP TABLE event_like;
--replace_column 8 # 9 #
SHOW EVENTS;
#
# End of tests
#
--echo
--echo #
--echo # Bug#12394306: the sever may crash if mysql.event is corrupted
--echo #
--echo
CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
--echo
CREATE TABLE event_original LIKE mysql.event;
INSERT INTO event_original SELECT * FROM mysql.event;
--echo
ALTER TABLE mysql.event MODIFY modified CHAR(1);
--echo
--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
--echo
--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name, created, last_altered FROM information_schema.events;
--echo
--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
--echo
--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9;
--echo
DROP TABLE mysql.event;
RENAME TABLE event_original TO mysql.event;
--echo
DROP EVENT ev1;
--echo
SHOW EVENTS;
--echo
--echo #
--echo # End of tests
--echo #
let $wait_condition=
select count(*) = 0 from information_schema.processlist
......
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
#
# Test that when the server is restarted, it checks mysql.event table,
# and disables the scheduler if it's not up to date.
......
......@@ -582,6 +582,14 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
*table= tables.table;
tables.table->use_all_columns();
if (table_intact.check(*table, &event_table_def))
{
close_thread_tables(thd);
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment