Skip to content

Commit 4032fc1

Browse files
committed
Merge branch '10.3' into 10.4
2 parents d2697df + b365b6e commit 4032fc1

8 files changed

+208
-31
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
RESET MASTER;
2+
call mtr.add_suppression("Error in Log_event::read_log_event*");
3+
call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
4+
DROP TABLE /*! IF EXISTS*/ t1;
5+
Warnings:
6+
Note 1051 Unknown table 'test.t1'
7+
CREATE TABLE `t1` (
8+
`col_int` int,
9+
pk integer auto_increment,
10+
`col_char_12_key` char(12),
11+
`col_int_key` int,
12+
`col_char_12` char(12),
13+
primary key (pk),
14+
key (`col_char_12_key` ),
15+
key (`col_int_key` )) ENGINE=InnoDB;
16+
INSERT /*! IGNORE */ INTO t1 VALUES (183173120, NULL, 'abcd', 1, 'efghijk'), (1, NULL, 'lmno', 2, 'p');
17+
ALTER TABLE `t1` ENABLE KEYS;
18+
DROP TABLE t1;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
RESET MASTER;
2+
call mtr.add_suppression("Error in Log_event::read_log_event*");
3+
call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
4+
DROP TABLE IF EXISTS t1;
5+
Warnings:
6+
Note 1051 Unknown table 'test.t1'
7+
CREATE TABLE t1 (c1 CHAR(255), c2 CHAR(255), c3 CHAR(255), c4 CHAR(255), c5 CHAR(255));
8+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
9+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
10+
UPDATE t1 SET c1=repeat('b',255);
11+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
12+
DROP TABLE t1;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[enable_checksum]
2+
binlog_checksum=1
3+
4+
[disable_checksum]
5+
binlog_checksum=0
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# ==== Purpose ====
2+
#
3+
# Test verifies that reading binary log by using "SHOW BINLOG EVENTS" command
4+
# from various random positions doesn't lead to crash. It should exit
5+
# gracefully with appropriate error.
6+
#
7+
# ==== References ====
8+
#
9+
# MDEV-18046:Assortment of crashes, assertion failures and ASAN errors in mysql_show_binlog_events
10+
11+
--source include/have_log_bin.inc
12+
--source include/have_innodb.inc
13+
14+
RESET MASTER;
15+
16+
call mtr.add_suppression("Error in Log_event::read_log_event*");
17+
call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
18+
19+
DROP TABLE /*! IF EXISTS*/ t1;
20+
CREATE TABLE `t1` (
21+
`col_int` int,
22+
pk integer auto_increment,
23+
`col_char_12_key` char(12),
24+
`col_int_key` int,
25+
`col_char_12` char(12),
26+
primary key (pk),
27+
key (`col_char_12_key` ),
28+
key (`col_int_key` )) ENGINE=InnoDB;
29+
30+
INSERT /*! IGNORE */ INTO t1 VALUES (183173120, NULL, 'abcd', 1, 'efghijk'), (1, NULL, 'lmno', 2, 'p');
31+
32+
--disable_warnings
33+
ALTER TABLE `t1` ENABLE KEYS;
34+
--enable_warnings
35+
36+
--let $max_pos= query_get_value(SHOW MASTER STATUS,Position,1)
37+
--let $pos= 1
38+
while ($pos <= $max_pos)
39+
{
40+
--disable_query_log
41+
--disable_result_log
42+
--error 0,1220
43+
eval SHOW BINLOG EVENTS FROM $pos;
44+
--inc $pos
45+
--enable_result_log
46+
--enable_query_log
47+
}
48+
DROP TABLE t1;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[enable_checksum]
2+
binlog_checksum=1
3+
4+
[disable_checksum]
5+
binlog_checksum=0
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# ==== Purpose ====
2+
#
3+
# Test verifies that reading binary log by using "SHOW BINLOG EVENTS" command
4+
# from various random positions doesn't lead to crash. It should exit
5+
# gracefully with appropriate error.
6+
#
7+
# ==== References ====
8+
#
9+
# MDEV-18046:Assortment of crashes, assertion failures and ASAN errors in mysql_show_binlog_events
10+
11+
--source include/have_log_bin.inc
12+
--source include/have_innodb.inc
13+
14+
RESET MASTER;
15+
call mtr.add_suppression("Error in Log_event::read_log_event*");
16+
call mtr.add_suppression("Replication event checksum verification failed while reading from a log file*");
17+
18+
DROP TABLE IF EXISTS t1;
19+
CREATE TABLE t1 (c1 CHAR(255), c2 CHAR(255), c3 CHAR(255), c4 CHAR(255), c5 CHAR(255));
20+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
21+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
22+
UPDATE t1 SET c1=repeat('b',255);
23+
INSERT INTO t1 VALUES (repeat('a', 255), repeat('a', 255),repeat('a', 255),repeat('a', 255),repeat('a', 255));
24+
--let $max_pos= query_get_value(SHOW MASTER STATUS,Position,1)
25+
--let $pos= 1
26+
while ($pos <= $max_pos)
27+
{
28+
--disable_query_log
29+
--disable_result_log
30+
--error 0,1220
31+
eval SHOW BINLOG EVENTS FROM $pos LIMIT 100;
32+
--inc $pos
33+
--enable_result_log
34+
--enable_query_log
35+
}
36+
37+
DROP TABLE t1;

sql/log_event.cc

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,9 +1052,14 @@ row_log_event_uncompress(const Format_description_log_event *description_event,
10521052

10531053
uint32 binlog_get_uncompress_len(const char *buf)
10541054
{
1055-
DBUG_ASSERT((buf[0] & 0xe0) == 0x80);
1056-
uint32 lenlen = buf[0] & 0x07;
10571055
uint32 len = 0;
1056+
uint32 lenlen = 0;
1057+
1058+
if ((buf == NULL) || ((buf[0] & 0xe0) != 0x80))
1059+
return len;
1060+
1061+
lenlen = buf[0] & 0x07;
1062+
10581063
switch(lenlen)
10591064
{
10601065
case 1:
@@ -4578,6 +4583,17 @@ code_name(int code)
45784583
}
45794584
#endif
45804585

4586+
#define VALIDATE_BYTES_READ(CUR_POS, START, EVENT_LEN) \
4587+
do { \
4588+
uchar *cur_pos= (uchar *)CUR_POS; \
4589+
uchar *start= (uchar *)START; \
4590+
uint len= EVENT_LEN; \
4591+
uint bytes_read= (uint)(cur_pos - start); \
4592+
DBUG_PRINT("info", ("Bytes read: %u event_len:%u.\n",\
4593+
bytes_read, len)); \
4594+
if (bytes_read >= len) \
4595+
DBUG_VOID_RETURN; \
4596+
} while (0)
45814597

45824598
/**
45834599
Macro to check that there is enough space to read from memory.
@@ -4589,7 +4605,6 @@ code_name(int code)
45894605
#define CHECK_SPACE(PTR,END,CNT) \
45904606
do { \
45914607
DBUG_PRINT("info", ("Read %s", code_name(pos[-1]))); \
4592-
DBUG_ASSERT((PTR) + (CNT) <= (END)); \
45934608
if ((PTR) + (CNT) > (END)) { \
45944609
DBUG_PRINT("info", ("query= 0")); \
45954610
query= 0; \
@@ -4924,7 +4939,9 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
49244939

49254940
uint32 max_length= uint32(event_len - ((const char*)(end + db_len + 1) -
49264941
(buf - common_header_len)));
4927-
if (q_len != max_length)
4942+
if (q_len != max_length ||
4943+
(event_len < uint((const char*)(end + db_len + 1) -
4944+
(buf - common_header_len))))
49284945
{
49294946
q_len= 0;
49304947
query= NULL;
@@ -7110,6 +7127,8 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
71107127
{
71117128
DBUG_ENTER("Load_log_event::copy_log_event");
71127129
uint data_len;
7130+
if ((int) event_len < body_offset)
7131+
DBUG_RETURN(1);
71137132
char* buf_end = (char*)buf + event_len;
71147133
/* this is the beginning of the post-header */
71157134
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,
71197138
table_name_len = (uint)data_head[L_TBL_LEN_OFFSET];
71207139
db_len = (uint)data_head[L_DB_LEN_OFFSET];
71217140
num_fields = uint4korr(data_head + L_NUM_FIELDS_OFFSET);
7122-
7123-
if ((int) event_len < body_offset)
7124-
DBUG_RETURN(1);
7141+
71257142
/*
71267143
Sql_ex.init() on success returns the pointer to the first byte after
71277144
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,
71307147
buf_end,
71317148
(uchar)buf[EVENT_TYPE_OFFSET] != LOAD_EVENT)))
71327149
DBUG_RETURN(1);
7133-
7150+
71347151
data_len = event_len - body_offset;
71357152
if (num_fields > data_len) // simple sanity check against corruption
71367153
DBUG_RETURN(1);
@@ -7695,7 +7712,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
76957712
// The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
76967713
uint8 post_header_len= description_event->post_header_len[ROTATE_EVENT-1];
76977714
uint ident_offset;
7698-
if (event_len < LOG_EVENT_MINIMAL_HEADER_LEN)
7715+
if (event_len < (uint)(LOG_EVENT_MINIMAL_HEADER_LEN + post_header_len))
76997716
DBUG_VOID_RETURN;
77007717
buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
77017718
pos= post_header_len ? uint8korr(buf + R_POS_OFFSET) : 4;
@@ -9268,6 +9285,11 @@ User_var_log_event(const char* buf, uint event_len,
92689285
we keep the flags set to UNDEF_F.
92699286
*/
92709287
size_t bytes_read= (val + val_len) - buf_start;
9288+
if (bytes_read > event_len)
9289+
{
9290+
error= true;
9291+
goto err;
9292+
}
92719293
if ((data_written - bytes_read) > 0)
92729294
{
92739295
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,
1089110913
uint8 const common_header_len= description_event->common_header_len;
1089210914
Log_event_type event_type= (Log_event_type)(uchar)buf[EVENT_TYPE_OFFSET];
1089310915
m_type= event_type;
10894-
10916+
m_cols_ai.bitmap= 0;
10917+
1089510918
uint8 const post_header_len= description_event->post_header_len[event_type-1];
1089610919

1089710920
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,
1092510948
which includes length bytes
1092610949
*/
1092710950
var_header_len= uint2korr(post_start);
10928-
assert(var_header_len >= 2);
10951+
/* Check length and also avoid out of buffer read */
10952+
if (var_header_len < 2 ||
10953+
event_len < static_cast<unsigned int>(var_header_len +
10954+
(post_start - buf)))
10955+
{
10956+
m_cols.bitmap= 0;
10957+
DBUG_VOID_RETURN;
10958+
}
1092910959
var_header_len-= 2;
1093010960

1093110961
/* 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,
1259712627
m_data_size(0), m_field_metadata(0), m_field_metadata_size(0),
1259812628
m_null_bits(0), m_meta_memory(NULL)
1259912629
{
12600-
unsigned int bytes_read= 0;
1260112630
DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)");
1260212631

1260312632
uint8 common_header_len= description_event->common_header_len;
1260412633
uint8 post_header_len= description_event->post_header_len[TABLE_MAP_EVENT-1];
1260512634
DBUG_PRINT("info",("event_len: %u common_header_len: %d post_header_len: %d",
1260612635
event_len, common_header_len, post_header_len));
12607-
1260812636
/*
1260912637
Don't print debug messages when running valgrind since they can
1261012638
trigger false warnings.
@@ -12613,6 +12641,9 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
1261312641
DBUG_DUMP("event buffer", (uchar*) buf, event_len);
1261412642
#endif
1261512643

12644+
if (event_len < (uint)(common_header_len + post_header_len))
12645+
DBUG_VOID_RETURN;
12646+
1261612647
/* Read the post-header */
1261712648
const char *post_start= buf + common_header_len;
1261812649

@@ -12639,15 +12670,18 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
1263912670

1264012671
/* Extract the length of the various parts from the buffer */
1264112672
uchar const *const ptr_dblen= (uchar const*)vpart + 0;
12673+
VALIDATE_BYTES_READ(ptr_dblen, buf, event_len);
1264212674
m_dblen= *(uchar*) ptr_dblen;
1264312675

1264412676
/* Length of database name + counter + terminating null */
1264512677
uchar const *const ptr_tbllen= ptr_dblen + m_dblen + 2;
12678+
VALIDATE_BYTES_READ(ptr_tbllen, buf, event_len);
1264612679
m_tbllen= *(uchar*) ptr_tbllen;
1264712680

1264812681
/* Length of table name + counter + terminating null */
1264912682
uchar const *const ptr_colcnt= ptr_tbllen + m_tbllen + 2;
1265012683
uchar *ptr_after_colcnt= (uchar*) ptr_colcnt;
12684+
VALIDATE_BYTES_READ(ptr_after_colcnt, buf, event_len);
1265112685
m_colcnt= net_field_length(&ptr_after_colcnt);
1265212686

1265312687
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,
1267012704
memcpy(m_coltype, ptr_after_colcnt, m_colcnt);
1267112705

1267212706
ptr_after_colcnt= ptr_after_colcnt + m_colcnt;
12673-
bytes_read= (uint) (ptr_after_colcnt - (uchar *)buf);
12674-
DBUG_PRINT("info", ("Bytes read: %d", bytes_read));
12675-
if (bytes_read < event_len)
12707+
VALIDATE_BYTES_READ(ptr_after_colcnt, buf, event_len);
12708+
m_field_metadata_size= net_field_length(&ptr_after_colcnt);
12709+
if(m_field_metadata_size <= (m_colcnt * 2))
1267612710
{
12677-
m_field_metadata_size= net_field_length(&ptr_after_colcnt);
12678-
DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
1267912711
uint num_null_bytes= (m_colcnt + 7) / 8;
1268012712
m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
12681-
&m_null_bits, num_null_bytes,
12682-
&m_field_metadata, m_field_metadata_size,
12683-
NULL);
12713+
&m_null_bits, num_null_bytes,
12714+
&m_field_metadata, m_field_metadata_size,
12715+
NULL);
1268412716
memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
1268512717
ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size;
1268612718
memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes);
1268712719
}
12720+
else
12721+
{
12722+
m_coltype= NULL;
12723+
my_free(m_memory);
12724+
m_memory= NULL;
12725+
DBUG_VOID_RETURN;
12726+
}
1268812727
}
12689-
1269012728
DBUG_VOID_RETURN;
1269112729
}
1269212730
#endif
@@ -14541,9 +14579,12 @@ void Update_rows_log_event::init(MY_BITMAP const *cols)
1454114579

1454214580
Update_rows_log_event::~Update_rows_log_event()
1454314581
{
14544-
if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
14545-
m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free
14546-
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init().
14582+
if (m_cols_ai.bitmap)
14583+
{
14584+
if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
14585+
m_cols_ai.bitmap= 0; // so no my_free in my_bitmap_free
14586+
my_bitmap_free(&m_cols_ai); // To pair with my_bitmap_init().
14587+
}
1454714588
}
1454814589

1454914590

0 commit comments

Comments
 (0)