summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSujatha <sujatha.sivakumar@mariadb.com>2019-12-18 14:59:44 +0530
committerSujatha <sujatha.sivakumar@mariadb.com>2020-01-07 18:27:05 +0530
commita6dd827a4d987a5c779ac0ce2658214f8678832f (patch)
tree58614e557774094a685558bdf15a050b83df022b
parent1adc559370cc53ca69e225739a942287eba1b974 (diff)
downloadmariadb-git-a6dd827a4d987a5c779ac0ce2658214f8678832f.tar.gz
MDEV-18046: Assortment of crashes, assertion failures and ASAN errors in mysql_show_binlog_events
Problem: ======== SHOW BINLOG EVENTS FROM <pos> causes a variety of failures, some of which are listed below. It is not a race condition issue, but there is some non-determinism in it. Analysis: ======== "show binlog events from <pos>" code considers the user given position as a valid event start position. The code starts reading data from this event start position onwards and tries to map it to a set of known events. Each event has a specific event structure and asserts have been added to ensure that read event data satisfies the event specific requirements. When a random position is supplied to "show binlog events command" the event structure specific checks will fail and they result in assert. Fix: ==== The fix is split into different parts. Each part addresses either an ASAN issue or an assert/crash. **Part1: Checksum based position validation when checksum is enabled** Using checksum validate the very first event read at the user specified position. If there is a checksum mismatch report an appropriate error for the invalid event.
-rw-r--r--mysql-test/suite/binlog/r/binlog_invalid_read_in_rotate.result18
-rw-r--r--mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result12
-rw-r--r--mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.combinations5
-rw-r--r--mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.test48
-rw-r--r--mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.combinations5
-rw-r--r--mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test37
-rw-r--r--sql/sql_repl.cc23
7 files changed, 142 insertions, 6 deletions
diff --git a/mysql-test/suite/binlog/r/binlog_invalid_read_in_rotate.result b/mysql-test/suite/binlog/r/binlog_invalid_read_in_rotate.result
new file mode 100644
index 00000000000..442fc951289
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_invalid_read_in_rotate.result
@@ -0,0 +1,18 @@
+RESET MASTER;
+call mtr.add_suppression("Error in Log_event::read_log_event*");
+call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
+DROP TABLE /*! IF EXISTS*/ t1;
+Warnings:
+Note 1051 Unknown table 'test.t1'
+CREATE TABLE `t1` (
+`col_int` int,
+pk integer auto_increment,
+`col_char_12_key` char(12),
+`col_int_key` int,
+`col_char_12` char(12),
+primary key (pk),
+key (`col_char_12_key` ),
+key (`col_int_key` )) ENGINE=InnoDB;
+INSERT /*! IGNORE */ INTO t1 VALUES (183173120, NULL, 'abcd', 1, 'efghijk'), (1, NULL, 'lmno', 2, 'p');
+ALTER TABLE `t1` ENABLE KEYS;
+DROP TABLE t1;
diff --git a/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result b/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result
new file mode 100644
index 00000000000..358422c5842
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_show_binlog_event_random_pos.result
@@ -0,0 +1,12 @@
+RESET MASTER;
+call mtr.add_suppression("Error in Log_event::read_log_event*");
+call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
+DROP TABLE IF EXISTS t1;
+Warnings:
+Note 1051 Unknown table 'test.t1'
+CREATE TABLE t1 (c1 CHAR(255), c2 CHAR(255), c3 CHAR(255), c4 CHAR(255), c5 CHAR(255));
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+UPDATE t1 SET c1=repeat('b',255);
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+DROP TABLE t1;
diff --git a/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.combinations b/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.combinations
new file mode 100644
index 00000000000..72076e12d48
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.combinations
@@ -0,0 +1,5 @@
+[enable_checksum]
+binlog_checksum=1
+
+[disable_checksum]
+binlog_checksum=0
diff --git a/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.test b/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.test
new file mode 100644
index 00000000000..36bb56c8342
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_invalid_read_in_rotate.test
@@ -0,0 +1,48 @@
+# ==== Purpose ====
+#
+# Test verifies that reading binary log by using "SHOW BINLOG EVENTS" command
+# from various random positions doesn't lead to crash. It should exit
+# gracefully with appropriate error.
+#
+# ==== References ====
+#
+# MDEV-18046:Assortment of crashes, assertion failures and ASAN errors in mysql_show_binlog_events
+
+--source include/have_log_bin.inc
+--source include/have_innodb.inc
+
+RESET MASTER;
+
+call mtr.add_suppression("Error in Log_event::read_log_event*");
+call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
+
+DROP TABLE /*! IF EXISTS*/ t1;
+CREATE TABLE `t1` (
+`col_int` int,
+pk integer auto_increment,
+`col_char_12_key` char(12),
+`col_int_key` int,
+`col_char_12` char(12),
+primary key (pk),
+key (`col_char_12_key` ),
+key (`col_int_key` )) ENGINE=InnoDB;
+
+INSERT /*! IGNORE */ INTO t1 VALUES (183173120, NULL, 'abcd', 1, 'efghijk'), (1, NULL, 'lmno', 2, 'p');
+
+--disable_warnings
+ALTER TABLE `t1` ENABLE KEYS;
+--enable_warnings
+
+--let $max_pos= query_get_value(SHOW MASTER STATUS,Position,1)
+--let $pos= 1
+while ($pos <= $max_pos)
+{
+ --disable_query_log
+ --disable_result_log
+ --error 0,1220
+ eval SHOW BINLOG EVENTS FROM $pos;
+ --inc $pos
+ --enable_result_log
+ --enable_query_log
+}
+DROP TABLE t1;
diff --git a/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.combinations b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.combinations
new file mode 100644
index 00000000000..72076e12d48
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.combinations
@@ -0,0 +1,5 @@
+[enable_checksum]
+binlog_checksum=1
+
+[disable_checksum]
+binlog_checksum=0
diff --git a/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test
new file mode 100644
index 00000000000..e6a9e1cb2c1
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_show_binlog_event_random_pos.test
@@ -0,0 +1,37 @@
+# ==== Purpose ====
+#
+# Test verifies that reading binary log by using "SHOW BINLOG EVENTS" command
+# from various random positions doesn't lead to crash. It should exit
+# gracefully with appropriate error.
+#
+# ==== References ====
+#
+# MDEV-18046:Assortment of crashes, assertion failures and ASAN errors in mysql_show_binlog_events
+
+--source include/have_log_bin.inc
+--source include/have_innodb.inc
+
+RESET MASTER;
+call mtr.add_suppression("Error in Log_event::read_log_event*");
+call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
+
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (c1 CHAR(255), c2 CHAR(255), c3 CHAR(255), c4 CHAR(255), c5 CHAR(255));
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+UPDATE t1 SET c1=repeat('b',255);
+INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
+--let $max_pos= query_get_value(SHOW MASTER STATUS,Position,1)
+--let $pos= 1
+while ($pos <= $max_pos)
+{
+ --disable_query_log
+ --disable_result_log
+ --error 0,1220
+ eval SHOW BINLOG EVENTS FROM $pos LIMIT 100;
+ --inc $pos
+ --enable_result_log
+ --enable_query_log
+}
+
+DROP TABLE t1;
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 48d2781cd46..851bff5fd24 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3840,6 +3840,11 @@ bool mysql_show_binlog_events(THD* thd)
List<Item> field_list;
const char *errmsg = 0;
bool ret = TRUE;
+ /*
+ Using checksum validate the correctness of event pos specified in show
+ binlog events command.
+ */
+ bool verify_checksum_once= false;
IO_CACHE log;
File file = -1;
MYSQL_BIN_LOG *binary_log= NULL;
@@ -3895,6 +3900,10 @@ bool mysql_show_binlog_events(THD* thd)
mi= 0;
}
+ /* Validate user given position using checksum */
+ if (lex_mi->pos == pos && !opt_master_verify_checksum)
+ verify_checksum_once= true;
+
unit->set_limit(thd->lex->current_select);
limit_start= unit->offset_limit_cnt;
limit_end= unit->select_limit_cnt;
@@ -3977,15 +3986,16 @@ bool mysql_show_binlog_events(THD* thd)
for (event_count = 0;
(ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
description_event,
- opt_master_verify_checksum)); )
+ (opt_master_verify_checksum ||
+ verify_checksum_once))); )
{
if (event_count >= limit_start &&
- ev->net_send(protocol, linfo.log_file_name, pos))
+ ev->net_send(protocol, linfo.log_file_name, pos))
{
- errmsg = "Net error";
- delete ev;
+ errmsg = "Net error";
+ delete ev;
mysql_mutex_unlock(log_lock);
- goto err;
+ goto err;
}
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
@@ -4011,10 +4021,11 @@ bool mysql_show_binlog_events(THD* thd)
delete ev;
}
+ verify_checksum_once= false;
pos = my_b_tell(&log);
if (++event_count >= limit_end)
- break;
+ break;
}
if (event_count < limit_end && log.error)