Commit 4032fc1d authored by Sujatha's avatar Sujatha

Merge branch '10.3' into 10.4

parents d2697dfb b365b6e7
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;
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;
[enable_checksum]
binlog_checksum=1
[disable_checksum]
binlog_checksum=0
# ==== 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;
[enable_checksum]
binlog_checksum=1
[disable_checksum]
binlog_checksum=0
# ==== 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;
...@@ -1052,9 +1052,14 @@ row_log_event_uncompress(const Format_description_log_event *description_event, ...@@ -1052,9 +1052,14 @@ row_log_event_uncompress(const Format_description_log_event *description_event,
uint32 binlog_get_uncompress_len(const char *buf) uint32 binlog_get_uncompress_len(const char *buf)
{ {
DBUG_ASSERT((buf[0] & 0xe0) == 0x80);
uint32 lenlen = buf[0] & 0x07;
uint32 len = 0; uint32 len = 0;
uint32 lenlen = 0;
if ((buf == NULL) || ((buf[0] & 0xe0) != 0x80))
return len;
lenlen = buf[0] & 0x07;
switch(lenlen) switch(lenlen)
{ {
case 1: case 1:
...@@ -4578,6 +4583,17 @@ code_name(int code) ...@@ -4578,6 +4583,17 @@ code_name(int code)
} }
#endif #endif
#define VALIDATE_BYTES_READ(CUR_POS, START, EVENT_LEN) \
do { \
uchar *cur_pos= (uchar *)CUR_POS; \
uchar *start= (uchar *)START; \
uint len= EVENT_LEN; \
uint bytes_read= (uint)(cur_pos - start); \
DBUG_PRINT("info", ("Bytes read: %u event_len:%u.\n",\
bytes_read, len)); \
if (bytes_read >= len) \
DBUG_VOID_RETURN; \
} while (0)
/** /**
Macro to check that there is enough space to read from memory. Macro to check that there is enough space to read from memory.
...@@ -4589,7 +4605,6 @@ code_name(int code) ...@@ -4589,7 +4605,6 @@ code_name(int code)
#define CHECK_SPACE(PTR,END,CNT) \ #define CHECK_SPACE(PTR,END,CNT) \
do { \ do { \
DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \ DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \
DBUG_ASSERT((PTR) + (CNT) <= (END)); \
if ((PTR) + (CNT) > (END)) { \ if ((PTR) + (CNT) > (END)) { \
DBUG_PRINT("info", ("query= 0")); \ DBUG_PRINT("info", ("query= 0")); \
query= 0; \ query= 0; \
...@@ -4924,7 +4939,9 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, ...@@ -4924,7 +4939,9 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
uint32 max_length= uint32(event_len - ((const char*)(end + db_len + 1) - uint32 max_length= uint32(event_len - ((const char*)(end + db_len + 1) -
(buf - common_header_len))); (buf - common_header_len)));
if (q_len != max_length) if (q_len != max_length ||
(event_len < uint((const char*)(end + db_len + 1) -
(buf - common_header_len))))
{ {
q_len= 0; q_len= 0;
query= NULL; query= NULL;
...@@ -7110,6 +7127,8 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, ...@@ -7110,6 +7127,8 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
{ {
DBUG_ENTER("Load_log_event::copy_log_event"); DBUG_ENTER("Load_log_event::copy_log_event");
uint data_len; uint data_len;
if ((int) event_len < body_offset)
DBUG_RETURN(1);
char* buf_end = (char*)buf + event_len; char* buf_end = (char*)buf + event_len;
/* this is the beginning of the post-header */ /* this is the beginning of the post-header */
const char* data_head = buf + description_event->common_header_len; const char* data_head = buf + description_event->common_header_len;
...@@ -7119,9 +7138,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, ...@@ -7119,9 +7138,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
table_name_len = (uint)data_head[L_TBL_LEN_OFFSET]; table_name_len = (uint)data_head[L_TBL_LEN_OFFSET];
db_len = (uint)data_head[L_DB_LEN_OFFSET]; db_len = (uint)data_head[L_DB_LEN_OFFSET];
num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET); num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET);
if ((int) event_len < body_offset)
DBUG_RETURN(1);
/* /*
Sql_ex.init() on success returns the pointer to the first byte after Sql_ex.init() on success returns the pointer to the first byte after
the sql_ex structure, which is the start of field lengths array. the sql_ex structure, which is the start of field lengths array.
...@@ -7130,7 +7147,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, ...@@ -7130,7 +7147,7 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
buf_end, buf_end,
(uchar)buf[EVENT_TYPE_OFFSET] != LOAD_EVENT))) (uchar)buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
DBUG_RETURN(1); DBUG_RETURN(1);
data_len = event_len - body_offset; data_len = event_len - body_offset;
if (num_fields > data_len) // simple sanity check against corruption if (num_fields > data_len) // simple sanity check against corruption
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -7695,7 +7712,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len, ...@@ -7695,7 +7712,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
uint8 post_header_len= description_event->post_header_len[ROTATE_EVENT-1]; uint8 post_header_len= description_event->post_header_len[ROTATE_EVENT-1];
uint ident_offset; uint ident_offset;
if (event_len < LOG_EVENT_MINIMAL_HEADER_LEN) if (event_len < (uint)(LOG_EVENT_MINIMAL_HEADER_LEN + post_header_len))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
buf+= LOG_EVENT_MINIMAL_HEADER_LEN; buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
pos= post_header_len ? uint8korr(buf + R_POS_OFFSET) : 4; pos= post_header_len ? uint8korr(buf + R_POS_OFFSET) : 4;
...@@ -9268,6 +9285,11 @@ User_var_log_event(const char* buf, uint event_len, ...@@ -9268,6 +9285,11 @@ User_var_log_event(const char* buf, uint event_len,
we keep the flags set to UNDEF_F. we keep the flags set to UNDEF_F.
*/ */
size_t bytes_read= (val + val_len) - buf_start; size_t bytes_read= (val + val_len) - buf_start;
if (bytes_read > event_len)
{
error= true;
goto err;
}
if ((data_written - bytes_read) > 0) if ((data_written - bytes_read) > 0)
{ {
flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + flags= (uint) *(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
...@@ -10891,7 +10913,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, ...@@ -10891,7 +10913,8 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
uint8 const common_header_len= description_event->common_header_len; uint8 const common_header_len= description_event->common_header_len;
Log_event_type event_type= (Log_event_type)(uchar)buf[EVENT_TYPE_OFFSET]; Log_event_type event_type= (Log_event_type)(uchar)buf[EVENT_TYPE_OFFSET];
m_type= event_type; m_type= event_type;
m_cols_ai.bitmap= 0;
uint8 const post_header_len= description_event->post_header_len[event_type-1]; uint8 const post_header_len= description_event->post_header_len[event_type-1];
DBUG_PRINT("enter",("event_len: %u common_header_len: %d " DBUG_PRINT("enter",("event_len: %u common_header_len: %d "
...@@ -10925,7 +10948,14 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, ...@@ -10925,7 +10948,14 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len,
which includes length bytes which includes length bytes
*/ */
var_header_len= uint2korr(post_start); var_header_len= uint2korr(post_start);
assert(var_header_len >= 2); /* Check length and also avoid out of buffer read */
if (var_header_len < 2 ||
event_len < static_cast<unsigned int>(var_header_len +
(post_start - buf)))
{
m_cols.bitmap= 0;
DBUG_VOID_RETURN;
}
var_header_len-= 2; var_header_len-= 2;
/* Iterate over var-len header, extracting 'chunks' */ /* Iterate over var-len header, extracting 'chunks' */
...@@ -12597,14 +12627,12 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, ...@@ -12597,14 +12627,12 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
m_data_size(0), m_field_metadata(0), m_field_metadata_size(0), m_data_size(0), m_field_metadata(0), m_field_metadata_size(0),
m_null_bits(0), m_meta_memory(NULL) m_null_bits(0), m_meta_memory(NULL)
{ {
unsigned int bytes_read= 0;
DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)"); DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)");
uint8 common_header_len= description_event->common_header_len; uint8 common_header_len= description_event->common_header_len;
uint8 post_header_len= description_event->post_header_len[TABLE_MAP_EVENT-1]; uint8 post_header_len= description_event->post_header_len[TABLE_MAP_EVENT-1];
DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d", DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d",
event_len, common_header_len, post_header_len)); event_len, common_header_len, post_header_len));
/* /*
Don't print debug messages when running valgrind since they can Don't print debug messages when running valgrind since they can
trigger false warnings. trigger false warnings.
...@@ -12613,6 +12641,9 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, ...@@ -12613,6 +12641,9 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
DBUG_DUMP("event buffer", (uchar*) buf, event_len); DBUG_DUMP("event buffer", (uchar*) buf, event_len);
#endif #endif
if (event_len < (uint)(common_header_len + post_header_len))
DBUG_VOID_RETURN;
/* Read the post-header */ /* Read the post-header */
const char *post_start= buf + common_header_len; const char *post_start= buf + common_header_len;
...@@ -12639,15 +12670,18 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, ...@@ -12639,15 +12670,18 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
/* Extract the length of the various parts from the buffer */ /* Extract the length of the various parts from the buffer */
uchar const *const ptr_dblen= (uchar const*)vpart + 0; uchar const *const ptr_dblen= (uchar const*)vpart + 0;
VALIDATE_BYTES_READ(ptr_dblen, buf, event_len);
m_dblen= *(uchar*) ptr_dblen; m_dblen= *(uchar*) ptr_dblen;
/* Length of database name + counter + terminating null */ /* Length of database name + counter + terminating null */
uchar const *const ptr_tbllen= ptr_dblen + m_dblen + 2; uchar const *const ptr_tbllen= ptr_dblen + m_dblen + 2;
VALIDATE_BYTES_READ(ptr_tbllen, buf, event_len);
m_tbllen= *(uchar*) ptr_tbllen; m_tbllen= *(uchar*) ptr_tbllen;
/* Length of table name + counter + terminating null */ /* Length of table name + counter + terminating null */
uchar const *const ptr_colcnt= ptr_tbllen + m_tbllen + 2; uchar const *const ptr_colcnt= ptr_tbllen + m_tbllen + 2;
uchar *ptr_after_colcnt= (uchar*) ptr_colcnt; uchar *ptr_after_colcnt= (uchar*) ptr_colcnt;
VALIDATE_BYTES_READ(ptr_after_colcnt, buf, event_len);
m_colcnt= net_field_length(&ptr_after_colcnt); m_colcnt= net_field_length(&ptr_after_colcnt);
DBUG_PRINT("info",("m_dblen: %lu off: %ld m_tbllen: %lu off: %ld m_colcnt: %lu off: %ld", DBUG_PRINT("info",("m_dblen: %lu off: %ld m_tbllen: %lu off: %ld m_colcnt: %lu off: %ld",
...@@ -12670,23 +12704,27 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len, ...@@ -12670,23 +12704,27 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
memcpy(m_coltype, ptr_after_colcnt, m_colcnt); memcpy(m_coltype, ptr_after_colcnt, m_colcnt);
ptr_after_colcnt= ptr_after_colcnt + m_colcnt; ptr_after_colcnt= ptr_after_colcnt + m_colcnt;
bytes_read= (uint) (ptr_after_colcnt - (uchar *)buf); VALIDATE_BYTES_READ(ptr_after_colcnt, buf, event_len);
DBUG_PRINT("info", ("Bytes read: %d", bytes_read)); m_field_metadata_size= net_field_length(&ptr_after_colcnt);
if (bytes_read < event_len) if(m_field_metadata_size <= (m_colcnt * 2))
{ {
m_field_metadata_size= net_field_length(&ptr_after_colcnt);
DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
uint num_null_bytes= (m_colcnt + 7) / 8; uint num_null_bytes= (m_colcnt + 7) / 8;
m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME), m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
&m_null_bits, num_null_bytes, &m_null_bits, num_null_bytes,
&m_field_metadata, m_field_metadata_size, &m_field_metadata, m_field_metadata_size,
NULL); NULL);
memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size); memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size; ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size;
memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes); memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes);
} }
else
{
m_coltype= NULL;
my_free(m_memory);
m_memory= NULL;
DBUG_VOID_RETURN;
}
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
#endif #endif
...@@ -14541,9 +14579,12 @@ void Update_rows_log_event::init(MY_BITMAP const *cols) ...@@ -14541,9 +14579,12 @@ void Update_rows_log_event::init(MY_BITMAP const *cols)
Update_rows_log_event::~Update_rows_log_event() Update_rows_log_event::~Update_rows_log_event()
{ {
if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened if (m_cols_ai.bitmap)
m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free {
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init(). if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init().
}
} }
......
...@@ -3975,6 +3975,11 @@ bool mysql_show_binlog_events(THD* thd) ...@@ -3975,6 +3975,11 @@ bool mysql_show_binlog_events(THD* thd)
List<Item> field_list; List<Item> field_list;
const char *errmsg = 0; const char *errmsg = 0;
bool ret = TRUE; 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; IO_CACHE log;
File file = -1; File file = -1;
MYSQL_BIN_LOG *binary_log= NULL; MYSQL_BIN_LOG *binary_log= NULL;
...@@ -4030,6 +4035,10 @@ bool mysql_show_binlog_events(THD* thd) ...@@ -4030,6 +4035,10 @@ bool mysql_show_binlog_events(THD* thd)
mi= 0; 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); unit->set_limit(thd->lex->current_select);
limit_start= unit->offset_limit_cnt; limit_start= unit->offset_limit_cnt;
limit_end= unit->select_limit_cnt; limit_end= unit->select_limit_cnt;
...@@ -4109,15 +4118,16 @@ bool mysql_show_binlog_events(THD* thd) ...@@ -4109,15 +4118,16 @@ bool mysql_show_binlog_events(THD* thd)
for (event_count = 0; for (event_count = 0;
(ev = Log_event::read_log_event(&log, (ev = Log_event::read_log_event(&log,
description_event, description_event,
opt_master_verify_checksum)); ) (opt_master_verify_checksum ||
verify_checksum_once))); )
{ {
if (event_count >= limit_start && 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"; errmsg = "Net error";
delete ev; delete ev;
mysql_mutex_unlock(log_lock); mysql_mutex_unlock(log_lock);
goto err; goto err;
} }
if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT) if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
...@@ -4143,10 +4153,11 @@ bool mysql_show_binlog_events(THD* thd) ...@@ -4143,10 +4153,11 @@ bool mysql_show_binlog_events(THD* thd)
delete ev; delete ev;
} }
verify_checksum_once= false;
pos = my_b_tell(&log); pos = my_b_tell(&log);
if (++event_count >= limit_end) if (++event_count >= limit_end)
break; break;
} }
if (unlikely(event_count < limit_end && log.error)) if (unlikely(event_count < limit_end && log.error))
......
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