Details
-
Bug
-
Status: Open (View Workflow)
-
Major
-
Resolution: Unresolved
-
10.6, 10.11, 11.4, 11.8, 12.3
-
Can result in hang or crash
Description
Mariadb-binlog can overflow and show invalid data if a Table_map_log_event has a corrupted length for SET or ENUM types (when binlog_row_metadata=FULL). Function parse_set_str_value)( doesn't validate the length of the SET/ENUM value before creating a string for it:
static void parse_set_str_value(std::vector<Table_map_log_event:: |
Optional_metadata_fields::str_vector> &vec,
|
unsigned char *field, unsigned int length) |
{
|
unsigned char* p= field; |
|
|
while (p < field + length) |
{
|
unsigned int count= net_field_length(&p); |
|
|
vec.push_back(std::vector<std::string>());
|
for (unsigned int i= 0; i < count; i++) |
{
|
unsigned len1= net_field_length(&p);
|
vec.back().push_back(std::string(reinterpret_cast<char *>(p), len1)); |
p+= len1;
|
}
|
}
|
}
|
This can be reproduced with the following MTR test, .cnf, and patch (to use debug_dbug to corrupt the length).
MTR file
--source include/have_debug.inc
|
--source include/have_binlog_format_row.inc
|
|
|
--echo #
|
--echo # Setup
|
CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 SET('hello', 'world'));
|
|
|
--let $saved_dbug= `SELECT @@SESSION.debug_dbug`
|
SET @@SESSION.debug_dbug="+d,corrupted_too_large_str_length";
|
|
|
INSERT INTO t1 VALUES (1, 'hello');
|
|
|
SET @@SESSION.debug_dbug=$saved_dbug;
|
|
|
--echo #
|
--echo # Locate the master binary log file that contains the corrupted
|
--echo # Table_map_log_event, then flush logs so it is closed and safe for
|
--echo # mysqlbinlog to read.
|
--let $mysqld_datadir= `SELECT @@datadir`
|
--let $binlog_filename= query_get_value(SHOW MASTER STATUS, File, 1)
|
--let $binlog_file= $mysqld_datadir/$binlog_filename
|
FLUSH BINARY LOGS;
|
|
|
--echo #
|
--echo # Have mysqlbinlog read the (corrupted) binary log file.
|
--let $binlog_out= $MYSQLTEST_VARDIR/tmp/rpl_table_map_metadata_str_len_overflow.out
|
--let $binlog_err= $MYSQLTEST_VARDIR/tmp/rpl_table_map_metadata_str_len_overflow.err
|
--echo # MYSQL_BINLOG binlog_file --result-file=binlog_out --base64-output=never --print-table-metadata --verbose 2> binlog_out
|
--exec $MYSQL_BINLOG $binlog_file --result-file=$binlog_out --base64-output=never --print-table-metadata --verbose 2> $binlog_out
|
|
|
|
|
--echo #
|
--echo # Cleanup
|
DROP TABLE t1;
|
.cnf
!include ../my.cnf
|
|
|
[mysqld.1]
|
binlog_row_metadata=FULL
|
patch file
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
|
index ea04b6fc660..67a9c65af0a 100644
|
--- a/sql/log_event_server.cc
|
+++ b/sql/log_event_server.cc
|
@@ -7139,7 +7139,9 @@ bool Table_map_log_event::init_set_str_value_field()
|
store_compressed_length(buf, typelib->count);
|
for (unsigned int i= 0; i < typelib->count; i++)
|
{
|
- store_compressed_length(buf, typelib->type_lengths[i]);
|
+ store_compressed_length(buf, DBUG_IF("corrupted_too_large_str_length")
|
+ ? (1 << 12)
|
+ : typelib->type_lengths[i]);
|
buf.append(typelib->type_names[i], typelib->type_lengths[i]);
|
}
|
}
|
|
Results in mariadb-binlog output for the Table_map_log_event:
#260519 10:16:41 server id 1 end_log_pos 0 CRC32 0x20e69edd Table_map: `test`.`t1` mapped to number 32
|
# Columns(`c1` INT NOT NULL,
|
# `c2` SET('hello�\0world\b\0��h4z�������������\0\0\0\0\0\0�U\0\0p&U\0\0@\0\0\0\0\0\0G3#�\0\0#�\0\0N1��\0\0���\0\0���\0\0�\0\0(��\0\0E��\0\0\0\0����\0\0\0\0\0\0\0�R#����\0\0\0\0\0\0\0\0"\0\0\0\0\0\0\0\0\0\0������������\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 \0\0\0\0\0\0�������� \0\0\0\0\0\0\0\0U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0�U\0\0���������U\0\0�������� �U\0\0��������0�U\0\0��������@�U\0\0��������P�U\0\0��������`�U\0\0��������p�U\0\0����������U\0\0����������U\0\0����������U\0\0����������U\0\0����������U\0\0����������U\0\0����������U\0\0����������U\0\0��������\0\0\0��������\0\0�������� \0\0��������0\0\0��������@\0\0��������P\0\0��������`\0\0��������p\0\0���������\0\0���������\0\0���������\0\0���������\0\0���������\0\0���������\0\0���������\0\0���������\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0U\0\0��������U\0\0�������� U\0\0��������0U\0\0��������@U\0\0��������PU\0\0��������`U\0\0��������pU\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0���������U\0\0��������\0 U\0\0�������� U\0\0�������� U\0\0��������0 U\0\0��������@ U\0\0��������P U\0\0��������` U\0\0��������p U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������� U\0\0��������\0!U\0\0��������!U\0\0�������� !U\0\0��������0!U\0\0��������@!U\0\0��������P!U\0\0��������`!U\0\0��������p!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0���������!U\0\0��������\0"U\0\0��������"U\0\0�������� "U\0\0��������0"U\0\0��������@"U\0\0��������P"U\0\0��������`"U\0\0��������p"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0���������"U\0\0��������\0#U\0\0��������#U\0\0�������� #U\0\0��������0#U\0\0��������@#U\0\0��������P#U\0\0��������`#U\0\0��������p#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0���������#U\0\0��������\0$U\0\0��������$U\0\0�������� $U\0\0��������0$U\0\0��������@$U\0\0��������P$U\0\0��������`$U\0\0��������p$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0���������$U\0\0��������\0%U\0\0��������%U\0\0�������� %U\0\0��������0%U\0\0��������@%U\0\0��������P%U\0\0��������`%U\0\0��������p%U\0\0���������%U\0\0������','��%U\0\0���������%U\0\0���������%U\0\0���������%U\0\0���������%U\0\0���������%U\0\0���������%U\0\0��������\0&U\0\0��������&U\0\0�������� &U\0\0��������0&UHARSET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci)
|
# Primary Key(c1)
|
If the length is large enough, it could also result in a segfault.
This pattern likely exists elsewhere in the Table_map_log_event parsing metadata, and other functions/types should be validated/fixed.
Note that implementation should wrap validation conditions with unlikely() as explained here.
Reported by letchu_pkt
Attachments
Issue Links
- relates to
-
MDEV-39689 Slave Overflow on Malformed Table_map_log_event
-
- Open
-
-
MDEV-39674 Slave Shows Invalid Data on Malformed Table_map_log_event
-
- Open
-