From a46401a3a61d5d38339faa5e2f8fedcefc193502 Mon Sep 17 00:00:00 2001 From: ARaveala Date: Wed, 24 Jun 2026 13:13:20 +0300 Subject: [PATCH 1/5] MDEV-39762: add bounds check in query_event_uncompress and row_log_event_uncompress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Integer overflow in query_event_uncompress() and row_log_event_uncompress() when un_len is near UINT32_MAX. ALIGN_SIZE() truncation produces a wrong buffer size causing a stack overflow (SIGABRT) in binlog_buf_uncompress(). Fix: reject un_len > MAX_MAX_ALLOWED_PACKET before any buffer allocation in both uncompress functions and their constructors. Return value 2 surfaces ER_TOO_BIG_FOR_UNCOMPRESS (error 1256) in slave.cc rather than the generic ER_BINLOG_UNCOMPRESS_ERROR. This is non-idiomatic (everything else returns 0/1) — an enum return type may be preferable, left as reviewer decision. Test: Two Perl MITM proxy intercepts replication stream and patches un_len to 0xFFFFFFFC in QUERY_COMPRESSED_EVENT and WRITE_ROWS_COMPRESSED_EVENT respectively. Without fix: server crashes (SIGABRT). With fix: IO thread stops cleanly with ER_SLAVE_RELAY_LOG_WRITE_FAILURE (1595), logging ER_TOO_BIG_FOR_UNCOMPRESS (1256). Shared proxy infrastructure added: - mysql-test/lib/mtr_socket_relay.pm — generic socket relay setup - mysql-test/lib/rpl_binlog_mitm.pm — MySQL protocol helpers, replication handshake, pre-dump relay Coverage gap: constructor fix has no test - requires a different trigger condition, not reachable via the current replication proxy approach. Coverage gaps noted for reviewer: - Constructor paths (Query_compressed_log_event, Write/Update/Delete_rows_compressed_log_event) are fixed but not tested — not reachable via the replication proxy approach - assert_grep checks for ER_TOO_BIG_FOR_UNCOMPRESS message; if reviewer prefers generic error, change return 2 to return 1 and update assert_grep to "Uncompress the compressed binlog failed", test will also need updating. WIP: MDEV-39762 row event path and proxy refactor WIP: MDEV-39762 cleanup and final test fixes --- mysql-test/lib/mtr_socket_relay.pm | 57 +++++ mysql-test/lib/rpl_binlog_mitm.pm | 207 ++++++++++++++++++ .../rpl/r/rpl_binlog_compress_overflow.result | 41 ++++ .../r/rpl_binlog_compress_overflow_row.result | 39 ++++ .../rpl/t/rpl_binlog_compress_overflow.test | 94 ++++++++ .../t/rpl_binlog_compress_overflow_proxy.pl | 60 +++++ .../t/rpl_binlog_compress_overflow_row.test | 93 ++++++++ .../rpl_binlog_compress_overflow_row_proxy.pl | 90 ++++++++ sql/log_event.cc | 18 +- sql/slave.cc | 10 +- 10 files changed, 704 insertions(+), 5 deletions(-) create mode 100644 mysql-test/lib/mtr_socket_relay.pm create mode 100644 mysql-test/lib/rpl_binlog_mitm.pm create mode 100644 mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result create mode 100644 mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result create mode 100644 mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test create mode 100644 mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_proxy.pl create mode 100644 mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test create mode 100644 mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row_proxy.pl diff --git a/mysql-test/lib/mtr_socket_relay.pm b/mysql-test/lib/mtr_socket_relay.pm new file mode 100644 index 0000000000000..60b7aaf18d8fc --- /dev/null +++ b/mysql-test/lib/mtr_socket_relay.pm @@ -0,0 +1,57 @@ +package mtr_socket_relay; +use Exporter 'import'; +our @EXPORT = qw(setup_relay); + +use strict; +use warnings; +use IO::Socket::INET; +use POSIX qw(setsid); + +# setup_relay($listen_port, $target_host, $target_port) +# +# Generic two-ended socket setup for a relay or proxy script. +# Binds a listen socket, forks and daemonizes so the caller returns +# to MTR immediately, accepts one inbound connection, opens one +# outbound connection to the target, and returns both sockets. +# +# SIGCHLD is set to IGNORE before forking to prevent zombie processes. +# +# Returns ($listen_sock, $inbound, $outbound). + +sub setup_relay { + my ($listen_port, $target_host, $target_port) = @_; + + my $listen_sock = IO::Socket::INET->new( + LocalPort => $listen_port, + Type => SOCK_STREAM, + ReuseAddr => 1, + Listen => 5, + Timeout => 60, + ) or die "setup_relay: cannot bind $listen_port: $!"; + + warn "PROXY_DEBUG: listening on $listen_port, target at $target_host:$target_port\n"; + + local $SIG{CHLD} = 'IGNORE'; + close STDOUT; + fork and exit; + POSIX::setsid(); + open(STDOUT, '>', '/dev/null'); + + my $inbound = $listen_sock->accept() + or die "setup_relay: accept failed: $!"; + $inbound->autoflush(1); + warn "PROXY_DEBUG: inbound connection accepted\n"; + + my $outbound = IO::Socket::INET->new( + PeerHost => $target_host, + PeerPort => $target_port, + Type => SOCK_STREAM, + Timeout => 10, + ) or die "setup_relay: cannot connect to $target_host:$target_port: $!"; + $outbound->autoflush(1); + warn "PROXY_DEBUG: outbound connection established\n"; + + return ($listen_sock, $inbound, $outbound); +} + +1; diff --git a/mysql-test/lib/rpl_binlog_mitm.pm b/mysql-test/lib/rpl_binlog_mitm.pm new file mode 100644 index 0000000000000..dfe777809e17a --- /dev/null +++ b/mysql-test/lib/rpl_binlog_mitm.pm @@ -0,0 +1,207 @@ +#!/usr/bin/perl +# rpl_binlog_mitm.pl -- shared MySQL protocol helpers for replication MITM tests. +# +# Provides packet I/O, net_field_length decoding, and the three phases common +# to all replication MITM proxies: master auth, slave handshake, pre-dump relay. +# Each proxy script use() this file and implements its own event patching. +package rpl_binlog_mitm; +use Exporter 'import'; +our @EXPORT = qw( + EVENT_TYPE_OFFSET EVENT_LEN_OFFSET COMMON_HEADER_LEN + ROWS_HEADER_LEN_V1 ROWS_HEADER_LEN_V2 + FORMAT_DESCRIPTION_EVENT + WRITE_ROWS_COMPRESSED_EVENT WRITE_ROWS_COMPRESSED_EVENT_V1 + BAD_LEN_UINT32 + read_packet send_packet + net_field_length_size net_field_length_value + do_master_auth do_slave_handshake relay_pre_dump patch_un_len + +); +use strict; +use warnings; + +# --------------------------------------------------------------------------- +# Constants (from sql/log_event.h) +# --------------------------------------------------------------------------- +use constant EVENT_TYPE_OFFSET => 4; +use constant EVENT_LEN_OFFSET => 9; +use constant COMMON_HEADER_LEN => 19; +use constant ROWS_HEADER_LEN_V1 => 8; +use constant ROWS_HEADER_LEN_V2 => 10; + +use constant FORMAT_DESCRIPTION_EVENT => 15; # 0x0f +use constant WRITE_ROWS_COMPRESSED_EVENT => 169; # 0xa9 +use constant WRITE_ROWS_COMPRESSED_EVENT_V1 => 166; # 0xa6 + +# BAD_LEN_UINT32: a uint32 value exceeding MAX_MAX_ALLOWED_PACKET (1GB). +# Used to trigger integer overflow in length field validation tests. +# Value chosen so ALIGN_SIZE() truncation wraps to a small non-zero value. + +use constant BAD_LEN_UINT32 => 0xFFFFFFFC; + +# --------------------------------------------------------------------------- +# Packet I/O +# --------------------------------------------------------------------------- +sub read_packet { + my ($sock) = @_; + my $hdr = ''; + my $n = read($sock, $hdr, 4); + die "read_packet: short header (got " . ($n // 'undef') . ")" + unless defined($n) && $n == 4; + my ($l0, $l1, $l2, $seq) = unpack('CCCC', $hdr); + my $len = $l0 | ($l1 << 8) | ($l2 << 16); + my $data = ''; + if ($len > 0) { + $n = read($sock, $data, $len); + die "read_packet: short body" unless defined($n) && $n == $len; + } + return ($seq, $hdr, $data); +} + +sub send_packet { + my ($sock, $hdr, $data) = @_; + print $sock $hdr . $data; +} + +# --------------------------------------------------------------------------- +# net_field_length -- mirrors net_field_length() in sql/pack.cc +# NOTE: if the encoding changes, update both helpers below. +# --------------------------------------------------------------------------- +sub net_field_length_size { + my ($first) = @_; + return 1 if $first < 251; + return 3 if $first == 252; + return 4 if $first == 253; + return 9; +} + +sub net_field_length_value { + my ($data, $offset) = @_; + my $first = unpack('C', substr($data, $offset, 1)); + return $first if $first < 251; + return unpack('v', substr($data, $offset + 1, 2)) if $first == 252; + return unpack('V', substr($data, $offset + 1, 3) . "\x00") if $first == 253; + return 0; +} + +# --------------------------------------------------------------------------- +# Phase 1a -- authenticate to the real master as root (no password) +# --------------------------------------------------------------------------- +sub do_master_auth { + my ($master) = @_; + my ($seq, $hdr, $greeting) = read_packet($master); + warn "PROXY_DEBUG: master greeting seq=$seq len=" . length($greeting) . "\n"; + + my $caps = 0x0001 | 0x0200 | 0x8000; + my $auth = pack('V', $caps) . pack('V', 16777216) . pack('C', 8) + . "\x00" x 23 . "root\x00" . "\x00"; + + print $master pack('CCC', length($auth) & 0xFF, + (length($auth) >> 8) & 0xFF, + (length($auth) >> 16) & 0xFF) + . pack('C', 1) . $auth; + + my ($aseq, $ahdr, $ok) = read_packet($master); + my $first = unpack('C', substr($ok, 0, 1)); + warn "PROXY_DEBUG: master auth response=0x" . sprintf('%02x', $first) . "\n"; + die "PROXY_DEBUG: master auth failed" if $first == 0xff; + +} + +# --------------------------------------------------------------------------- +# Phase 1b -- send a fresh greeting to the slave and accept any credentials +# --------------------------------------------------------------------------- +sub do_slave_handshake { + my ($slave) = @_; + + my $greeting = + "\x0a" . "10.11.0-MariaDB\x00" + . pack('V', 100) + . "12345678\x00" + . pack('v', 0x0001 | 0x0002 | 0x0004 | 0x0200 | 0x8000) + . "\x08" . pack('v', 2) . pack('v', 0) . pack('C', 21) + . "\x00" x 10 + . "123456789012\x00"; + + my $len = length($greeting); + print $slave pack('CCC', $len & 0xFF, ($len >> 8) & 0xFF, ($len >> 16) & 0xFF) + . pack('C', 0) . $greeting; + + my ($slave_seq, $hdr, $auth) = read_packet($slave); + warn "PROXY_DEBUG: slave auth seq=$slave_seq\n"; + + my $ok = "\x00\x00\x00\x02\x00\x00"; + print $slave pack('CCC', length($ok), 0, 0) . pack('C', $slave_seq + 1) . $ok; + warn "PROXY_DEBUG: sent OK to slave\n"; + +} + +# --------------------------------------------------------------------------- +# Phase 2 -- relay all pre-dump packets transparently until COM_BINLOG_DUMP. +# Returns when COM_BINLOG_DUMP (0x12) has been forwarded to master. +# --------------------------------------------------------------------------- +sub relay_pre_dump { + my ($master, $slave) = @_; + warn "PROXY_DEBUG: phase2 - pre-dump relay\n"; + + while (1) { + my ($seq, $hdr, $cmd_data) = read_packet($slave); + my $cmd = unpack('C', substr($cmd_data, 0, 1)); + warn "PROXY_DEBUG: slave cmd=0x" . sprintf('%02x', $cmd) . "\n"; + + send_packet($master, $hdr, $cmd_data); + last if $cmd == 0x12; # COM_BINLOG_DUMP + + # relay master's response (OK/ERR or full result set) + my $field_count; + my $in_rows = 0; + while (1) { + my ($rseq, $rhdr, $resp) = read_packet($master); + send_packet($slave, $rhdr, $resp); + my $first = unpack('C', substr($resp, 0, 1)); + if (!defined $field_count) { + last if $first == 0x00 || $first == 0xff; + $field_count = $first; + } elsif (!$in_rows) { + $in_rows = 1 if $first == 0xfe && length($resp) < 9; + } else { + last if $first == 0xfe && length($resp) < 9; + } + } + } + warn "PROXY_DEBUG: COM_BINLOG_DUMP forwarded, entering event stream\n"; +} + +# --------------------------------------------------------------------------- +# patch_un_len($event_data_ref, $ehdr_ref, $flag_offset) +# +# Patches the un_len field at $flag_offset in a compressed binlog event. +# Updates the event length in the common header and the MySQL packet header. +# Operates on references so changes are reflected in the caller. +# --------------------------------------------------------------------------- +sub patch_un_len { + my ($event_data_ref, $ehdr_ref, $flag_offset) = @_; + + my $flag_byte = unpack('C', substr($$event_data_ref, $flag_offset, 1)); + my $old_len_bytes = $flag_byte & 0x07; + + substr($$event_data_ref, $flag_offset, 1 + $old_len_bytes) = + "\x84" . pack('V', BAD_LEN_UINT32); + + my $delta = 4 - $old_len_bytes; + if ($delta) { + my $old_len = unpack('V', substr($$event_data_ref, 1 + EVENT_LEN_OFFSET, 4)); + substr($$event_data_ref, 1 + EVENT_LEN_OFFSET, 4) = + pack('V', $old_len + $delta); + } + + my $new_len = length($$event_data_ref); + substr($$ehdr_ref, 0, 3) = pack('CCC', + $new_len & 0xFF, + ($new_len >> 8) & 0xFF, + ($new_len >> 16) & 0xFF); + + warn "PROXY_DEBUG: patched un_len to 0xFFFFFFFC at offset $flag_offset\n"; +} + +1; diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result new file mode 100644 index 0000000000000..d3ea59cd38bce --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result @@ -0,0 +1,41 @@ +include/master-slave.inc +[connection master] +connection slave; +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master"); +call mtr.add_suppression("Error reading packet from server"); +call mtr.add_suppression("Slave I/O thread.*exiting"); +call mtr.add_suppression("Uncompressed data size too large"); +connection master; +SET GLOBAL binlog_checksum = NONE; +SET GLOBAL log_bin_compress = 1; +SET GLOBAL log_bin_compress_min_len = 10; +CREATE TABLE t1 (a VARCHAR(300)); +connection slave; +include/stop_slave.inc +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=PROXY_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='', MASTER_LOG_POS=4, MASTER_USE_GTID=NO; +START SLAVE IO_THREAD; +connection master; +INSERT INTO t1 VALUES ('test'); +connection slave; +include/wait_for_slave_io_error.inc [errno=1595] +Last_IO_Error = 'Relay log write failure: could not queue event from master' +include/assert_grep.inc [Uncompressed data size too large] +connection slave; +STOP SLAVE; +Warnings: +Note 1255 Slave already has been stopped +RESET SLAVE ALL; +Warnings: +Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' to 'Slave_Pos' +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; +connection master; +connection slave; +SET GLOBAL gtid_slave_pos='0-1-2'; +include/start_slave.inc +connection master; +SET GLOBAL log_bin_compress = 0; +SET GLOBAL log_bin_compress_min_len = DEFAULT; +SET GLOBAL binlog_checksum = CRC32; +DROP TABLE t1; +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result new file mode 100644 index 0000000000000..6ee371ea4cfb1 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result @@ -0,0 +1,39 @@ +include/master-slave.inc +[connection master] +connection slave; +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master"); +call mtr.add_suppression("Error reading packet from server"); +call mtr.add_suppression("Slave I/O thread.*exiting"); +call mtr.add_suppression("Uncompressed data size too large"); +connection master; +SET GLOBAL binlog_checksum = NONE; +SET GLOBAL log_bin_compress = 1; +CREATE TABLE t1 (a VARCHAR(300)); +connection slave; +include/stop_slave.inc +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=PROXY_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='', MASTER_LOG_POS=4, MASTER_USE_GTID=NO; +START SLAVE IO_THREAD; +connection master; +INSERT INTO t1 VALUES (REPEAT('x', 256)); +connection slave; +include/wait_for_slave_io_error.inc [errno=1595] +Last_IO_Error = 'Relay log write failure: could not queue event from master' +include/assert_grep.inc [Uncompressed data size too large] +connection slave; +STOP SLAVE; +Warnings: +Note 1255 Slave already has been stopped +RESET SLAVE ALL; +Warnings: +Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' to 'Slave_Pos' +CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; +connection master; +connection slave; +SET GLOBAL gtid_slave_pos='0-1-2'; +include/start_slave.inc +connection master; +SET GLOBAL log_bin_compress = 0; +SET GLOBAL binlog_checksum = CRC32; +DROP TABLE t1; +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test new file mode 100644 index 0000000000000..9ffbb6dd5b773 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test @@ -0,0 +1,94 @@ +# +# MDEV-39762: query_event_uncompress() stack overflow via oversized un_len +# +# Regression test: the IO thread must reject a QUERY_COMPRESSED_EVENT +# whose un_len field exceeds MAX_MAX_ALLOWED_PACKET (1 GB) and stop +# cleanly rather than overflowing the stack or crashing. +# +# Approach +# -------- +# A QUERY_COMPRESSED_EVENT with un_len > 1 GB cannot be produced by any +# legitimate server. This test uses a man-in-the-middle proxy script +# (rpl_binlog_compress_overflow_proxy.pl) that sits between the real master and the replica +# IO thread. The proxy forwards all replication traffic transparently +# except when it sees a QUERY_COMPRESSED_EVENT, at which point it patches +# the un_len field to 0xFFFFFFFC before forwarding it to the replica. +# +# The replica IO thread must detect the invalid un_len and stop with +# ER_SLAVE_RELAY_LOG_WRITE_FAILURE (1595) rather than crashing. +# +# Debug output: grep for PROXY_DEBUG in test logs. +# + +--source include/have_binlog_format_statement.inc +--source include/not_embedded.inc +--source include/master-slave.inc + +--connection slave +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master"); +call mtr.add_suppression("Error reading packet from server"); +call mtr.add_suppression("Slave I/O thread.*exiting"); +call mtr.add_suppression("Uncompressed data size too large"); + +--connection master +SET GLOBAL binlog_checksum = NONE; +SET GLOBAL log_bin_compress = 1; +SET GLOBAL log_bin_compress_min_len = 10; + +CREATE TABLE t1 (a VARCHAR(300)); + +# Start the proxy. + +let $proxy_port = `SELECT @@port + 2`; + +--exec perl $MYSQL_TEST_DIR/suite/rpl/t/rpl_binlog_compress_overflow_proxy.pl $proxy_port 127.0.0.1 $MASTER_MYPORT + +# Point the replica IO thread at the proxy and start it. + +--connection slave +--source include/stop_slave.inc + +--replace_result $proxy_port PROXY_PORT +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$proxy_port, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='', MASTER_LOG_POS=4, MASTER_USE_GTID=NO + +START SLAVE IO_THREAD; + +--connection master +INSERT INTO t1 VALUES ('test'); + +# The IO thread must stop with error 1595 + +--connection slave +--let $slave_io_errno= 1595 +--let $show_slave_io_error= 1 +--source include/wait_for_slave_io_error.inc + +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.2.err +--let $assert_text= Uncompressed data size too large +--let $assert_select= Uncompressed data size too large +--let $assert_count= 1 +--source include/assert_grep.inc + +--connection slave +STOP SLAVE; +RESET SLAVE ALL; + +# Reconnect to real master and reset GTID position so rpl_end can sync +--replace_result $MASTER_MYPORT MASTER_PORT +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS + +# Reset slave GTID to match master so we can sync +--connection master +let $master_gtid= `SELECT @@gtid_binlog_pos`; +--connection slave +--eval SET GLOBAL gtid_slave_pos='$master_gtid' +--source include/start_slave.inc + +--connection master +SET GLOBAL log_bin_compress = 0; +SET GLOBAL log_bin_compress_min_len = DEFAULT; +SET GLOBAL binlog_checksum = CRC32; +DROP TABLE t1; + +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_proxy.pl b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_proxy.pl new file mode 100644 index 0000000000000..941b33ef55b81 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_proxy.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl +# rpl_binlog_compress_overflow_proxy.pl -- MITM proxy for MDEV-39762 query event path. +# Patches un_len to 0xFFFFFFFC in the first QUERY_COMPRESSED_EVENT (0xa5). +# Usage: perl rpl_binlog_compress_overflow_proxy.pl + +use strict; +use warnings; +use lib "$ENV{MYSQL_TEST_DIR}/lib"; +use rpl_binlog_mitm; +use mtr_socket_relay; + +my ($listen_port, $master_host, $master_port) = @ARGV; +die "Usage: $0 " + unless $listen_port && $master_host && $master_port; + + +# NOTE: offsets below reflect QUERY_HEADER_LEN=13, Q_DB_LEN_OFFSET=8, +# Q_STATUS_VARS_LEN_OFFSET=11 from sql/log_event.h. Update if post-header changes. +use constant QUERY_POST_HEADER_LEN => 13; +use constant Q_DB_LEN_OFFSET => 8; +use constant Q_STATUS_VARS_LEN_OFFSET => 11; +use constant QUERY_COMPRESSED_EVENT => 165; # 0xa5 + +my ($listen_sock, $slave, $master) = setup_relay($listen_port, $master_host, $master_port); +do_master_auth($master); +do_slave_handshake($slave); +relay_pre_dump($master, $slave); + +# Phase 3: patch first QUERY_COMPRESSED_EVENT +warn "PROXY_DEBUG: phase3 - event stream\n"; +my $patched = 0; +while (!$patched) { + my ($eseq, $ehdr, $event_data) = read_packet($master); + my $event_type = unpack('C', substr($event_data, 1 + EVENT_TYPE_OFFSET, 1)); + warn "PROXY_DEBUG: event type=0x" . sprintf('%02x', $event_type) . " len=" . length($event_data) . "\n"; + + if ($event_type == QUERY_COMPRESSED_EVENT) { + warn "PROXY_DEBUG: patching QUERY_COMPRESSED_EVENT\n"; + + # Locate un_len: 1(OK) + 19(hdr) + 13(post-hdr) + status_vars_len + db_len + 1(NUL) + my $ph_start = 1 + COMMON_HEADER_LEN; + my $db_len = unpack('C', substr($event_data, $ph_start + Q_DB_LEN_OFFSET, 1)); + my $status_vars_len = unpack('v', substr($event_data, $ph_start + Q_STATUS_VARS_LEN_OFFSET, 2)); + my $flag_offset = 1 + COMMON_HEADER_LEN + QUERY_POST_HEADER_LEN + + $status_vars_len + $db_len + 1; + patch_un_len(\$event_data, \$ehdr, $flag_offset); + send_packet($slave, $ehdr, $event_data); + $patched = 1; + } else { + send_packet($slave, $ehdr, $event_data); + } +} + +# Wait for slave to close connection after rejecting the patched event. +$slave->timeout(10); +my $buf; +read($slave, $buf, 1); +close($slave); close($master); close($listen_sock); +warn "PROXY_DEBUG: done\n"; +exit 0; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test new file mode 100644 index 0000000000000..faf897baaadd0 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test @@ -0,0 +1,93 @@ +# MDEV-39762: row_log_event_uncompress() stack overflow via oversized un_len +# +# Regression test: the IO thread must reject a WRITE_ROWS_COMPRESSED_EVENT +# whose un_len field exceeds MAX_MAX_ALLOWED_PACKET (1 GB) and stop +# cleanly rather than overflowing the stack or crashing. +# +# Approach +# -------- +# A WRITE_ROWS_COMPRESSED_EVENT with un_len > 1 GB cannot be produced by +# any legitimate server. This test uses a man-in-the-middle proxy script +# (rpl_binlog_compress_overflow_row_proxy.pl) that sits between the real master and the +# replica IO thread. The proxy forwards all replication traffic +# transparently except when it sees a WRITE_ROWS_COMPRESSED_EVENT, at +# which point it patches the un_len field to 0xFFFFFFFC before forwarding +# it to the replica. +# +# The replica IO thread must detect the invalid un_len and stop with +# ER_SLAVE_RELAY_LOG_WRITE_FAILURE (1595) rather than crashing. +# +# Debug output: grep for PROXY_DEBUG in test logs. + +--source include/have_binlog_format_row.inc +--source include/not_embedded.inc +--source include/master-slave.inc + +--connection slave +call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master"); +call mtr.add_suppression("Error reading packet from server"); +call mtr.add_suppression("Slave I/O thread.*exiting"); +call mtr.add_suppression("Uncompressed data size too large"); + +# binlog_format=ROW is enforced by have_binlog_format_row.inc. + +--connection master +SET GLOBAL binlog_checksum = NONE; +SET GLOBAL log_bin_compress = 1; + +CREATE TABLE t1 (a VARCHAR(300)); + +# rpl_binlog_compress_overflow_row_proxy.pl listens on the proxy port, connects to the +# real master, and forwards all replication traffic transparently +# until it sees a WRITE_ROWS_COMPRESSED_EVENT. At that point it +# patches un_len to 0xFFFFFFFC and forwards the patched event to +# the slave. + +let $proxy_port = `SELECT @@port + 2`; + +--exec perl $MYSQL_TEST_DIR/suite/rpl/t/rpl_binlog_compress_overflow_row_proxy.pl $proxy_port 127.0.0.1 $MASTER_MYPORT + +# Point the replica IO thread at the proxy and start it. + +--connection slave +--source include/stop_slave.inc + +--replace_result $proxy_port PROXY_PORT +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$proxy_port, MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='', MASTER_LOG_POS=4, MASTER_USE_GTID=NO + +START SLAVE IO_THREAD; + +--connection master +INSERT INTO t1 VALUES (REPEAT('x', 256)); + +--connection slave +--let $slave_io_errno= 1595 +--let $show_slave_io_error= 1 +--source include/wait_for_slave_io_error.inc + +--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.2.err +--let $assert_text= Uncompressed data size too large +--let $assert_select= Uncompressed data size too large +--let $assert_count= 1 +--source include/assert_grep.inc + +--connection slave +STOP SLAVE; +RESET SLAVE ALL; + +--replace_result $MASTER_MYPORT MASTER_PORT +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS + +--connection master +let $master_gtid= `SELECT @@gtid_binlog_pos`; +--connection slave +--eval SET GLOBAL gtid_slave_pos='$master_gtid' +--source include/start_slave.inc + +--connection master +SET GLOBAL log_bin_compress = 0; +SET GLOBAL binlog_checksum = CRC32; +DROP TABLE t1; + +--sync_slave_with_master +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row_proxy.pl b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row_proxy.pl new file mode 100644 index 0000000000000..1c34670fc6e0e --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row_proxy.pl @@ -0,0 +1,90 @@ +#!/usr/bin/perl +# rpl_binlog_compress_overflow_row_proxy.pl -- MITM proxy for MDEV-39762 row event path. +# Patches un_len to 0xFFFFFFFC in the first WRITE_ROWS_COMPRESSED_EVENT. +# Usage: perl rpl_binlog_compress_overflow_row_proxy.pl + +use strict; +use warnings; +use lib "$ENV{MYSQL_TEST_DIR}/lib"; +use rpl_binlog_mitm; +use mtr_socket_relay; + +my ($listen_port, $master_host, $master_port) = @ARGV; +die "Usage: $0 " + unless $listen_port && $master_host && $master_port; + + +# NOTE: ROWS_HEADER_LEN_V1=8, COMMON_HEADER_LEN=19 from sql/log_event.h. +# If those change, the $tmp initialisation below must be updated. + +my ($listen_sock, $slave, $master) = setup_relay($listen_port, $master_host, $master_port); +do_master_auth($master); +do_slave_handshake($slave); +relay_pre_dump($master, $slave); + +# Phase 3: patch first WRITE_ROWS_COMPRESSED_EVENT. +# post_header_len per event type is read from FORMAT_DESCRIPTION_EVENT +# so we handle V1 (0xa6) and V2 (0xa9) correctly regardless of master version. +warn "PROXY_DEBUG: phase3 - event stream\n"; +my %post_header_len; +my $patched = 0; + +while (!$patched) { + my ($eseq, $ehdr, $event_data) = read_packet($master); + my $event_type = unpack('C', substr($event_data, 1 + EVENT_TYPE_OFFSET, 1)); + warn "PROXY_DEBUG: event type=0x" . sprintf('%02x', $event_type) . " len=" . length($event_data) . "\n"; + + # Extract post_header_len for row event types from FDE + if ($event_type == FORMAT_DESCRIPTION_EVENT) { + # FDE body: 2(binlog_ver) + 50(server_ver) + 4(timestamp) + 1(hdr_len) = 57 bytes + # before the post_header_len array (1 byte per type, 1-indexed). + my $phl_start = 1 + COMMON_HEADER_LEN + 57; + for my $type (WRITE_ROWS_COMPRESSED_EVENT, WRITE_ROWS_COMPRESSED_EVENT_V1) { + if (length($event_data) > $phl_start + $type - 1) { + $post_header_len{$type} = unpack('C', + substr($event_data, $phl_start + $type - 1, 1)); + warn "PROXY_DEBUG: FDE post_header_len[$type]=$post_header_len{$type}\n"; + } + } + send_packet($slave, $ehdr, $event_data); + next; + } + + if ($event_type == WRITE_ROWS_COMPRESSED_EVENT || + $event_type == WRITE_ROWS_COMPRESSED_EVENT_V1) { + + warn "PROXY_DEBUG: patching WRITE_ROWS_COMPRESSED_EVENT\n"; + + # Mirror row_log_event_uncompress() walk to locate un_len. + # tmp = src + common_header_len + ROWS_HEADER_LEN_V1 = 19 + 8 = 27 + # In $event_data the OK prefix byte is at [0], so add 1. + my $tmp = 1 + COMMON_HEADER_LEN + ROWS_HEADER_LEN_V1; # = 28 + + my $ph_len = $post_header_len{$event_type} // ROWS_HEADER_LEN_V1; + if ($ph_len == ROWS_HEADER_LEN_V2) { + my $var_header_len = unpack('v', substr($event_data, $tmp, 2)); + warn "PROXY_DEBUG: V2 var_header_len=$var_header_len\n"; + $tmp += $var_header_len; + } + + my $nfl_first = unpack('C', substr($event_data, $tmp, 1)); + my $nfl_size = net_field_length_size($nfl_first); + my $m_width = net_field_length_value($event_data, $tmp); + warn "PROXY_DEBUG: m_width=$m_width\n"; + $tmp += $nfl_size + int(($m_width + 7) / 8); + + my $flag_offset = $tmp; + patch_un_len(\$event_data, \$ehdr, $flag_offset); + send_packet($slave, $ehdr, $event_data); + $patched = 1; + } else { + send_packet($slave, $ehdr, $event_data); + } +} +# Wait for slave to close connection after rejecting the patched event. +$slave->timeout(10); +my $buf; +read($slave, $buf, 1); +close($slave); close($master); close($listen_sock); +warn "PROXY_DEBUG: done\n"; +exit 0; diff --git a/sql/log_event.cc b/sql/log_event.cc index 3ff4abbace194..4e1e9cf9f0c49 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -407,11 +407,14 @@ query_event_uncompress(const Format_description_log_event *description_event, if (comp_len < 0 || un_len == 0) return 1; + // bad event + if (unlikely(un_len > MAX_MAX_ALLOWED_PACKET)) + return 2; *newlen= (ulong)(tmp - src) + un_len; if (contain_checksum) *newlen+= BINLOG_CHECKSUM_LEN; - uint32 alloc_size= (uint32)ALIGN_SIZE(*newlen); + size_t alloc_size= ALIGN_SIZE(*newlen); if (alloc_size <= buf_size) new_dst= buf; @@ -513,6 +516,8 @@ row_log_event_uncompress(const Format_description_log_event *description_event, if (un_len == 0) return 1; //bad event + if (unlikely(un_len > MAX_MAX_ALLOWED_PACKET)) + return 2; //bad event int32 comp_len= (int32)(len - (tmp - src) - (contain_checksum ? BINLOG_CHECKSUM_LEN : 0)); if (comp_len <=0) @@ -1843,6 +1848,12 @@ Query_compressed_log_event::Query_compressed_log_event(const uchar *buf, query= 0; return; } + if (unlikely(un_len > MAX_MAX_ALLOWED_PACKET)) + { + my_error(ER_TOO_BIG_FOR_UNCOMPRESS, MYF(0), MAX_MAX_ALLOWED_PACKET); + query= 0; + return; + } /* Reserve one byte for '\0' */ query_buf= (Log_event::Byte*) my_malloc(PSI_INSTRUMENT_ME, @@ -3542,6 +3553,11 @@ void Rows_log_event::uncompress_buf() if (!un_len) return; + if (unlikely(un_len > MAX_MAX_ALLOWED_PACKET)) + { + my_error(ER_TOO_BIG_FOR_UNCOMPRESS, MYF(0), MAX_MAX_ALLOWED_PACKET); + return; + } uchar *new_buf= (uchar*) my_malloc(PSI_INSTRUMENT_ME, ALIGN_SIZE(un_len), MYF(MY_WME)); if (new_buf) diff --git a/sql/slave.cc b/sql/slave.cc index 881744a7da3c7..05e82be088fba 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -7321,13 +7321,14 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len) */ case QUERY_COMPRESSED_EVENT: inc_pos= event_len; - if (query_event_uncompress(rli->relay_log.description_event_for_queue, + if (int uncompress_rc = query_event_uncompress(rli->relay_log.description_event_for_queue, checksum_alg == BINLOG_CHECKSUM_ALG_CRC32, buf, event_len, new_buf_arr, sizeof(new_buf_arr), &is_malloc, &new_buf, &event_len)) { char llbuf[22]; - error = ER_BINLOG_UNCOMPRESS_ERROR; + error= (uncompress_rc == 2) ? ER_TOO_BIG_FOR_UNCOMPRESS + : ER_BINLOG_UNCOMPRESS_ERROR; error_msg.append(STRING_WITH_LEN("binlog uncompress error, master log_pos: ")); llstr(mi->master_log_pos, llbuf); error_msg.append(llbuf, strlen(llbuf)); @@ -7345,14 +7346,15 @@ static int queue_event(Master_info* mi, const uchar *buf, ulong event_len) case DELETE_ROWS_COMPRESSED_EVENT_V1: inc_pos = event_len; { - if (row_log_event_uncompress(rli->relay_log.description_event_for_queue, + if (int uncompress_rc = row_log_event_uncompress(rli->relay_log.description_event_for_queue, checksum_alg == BINLOG_CHECKSUM_ALG_CRC32, buf, event_len, new_buf_arr, sizeof(new_buf_arr), &is_malloc, &new_buf, &event_len)) { char llbuf[22]; - error = ER_BINLOG_UNCOMPRESS_ERROR; + error= (uncompress_rc == 2) ? ER_TOO_BIG_FOR_UNCOMPRESS + : ER_BINLOG_UNCOMPRESS_ERROR; error_msg.append(STRING_WITH_LEN("binlog uncompress error, master log_pos: ")); llstr(mi->master_log_pos, llbuf); error_msg.append(llbuf, strlen(llbuf)); From 3ae07a45c262b4b74f2719365b7eebbc39334040 Mon Sep 17 00:00:00 2001 From: ARaveala Date: Mon, 20 Jul 2026 15:05:36 +0300 Subject: [PATCH 2/5] MDEV-39762: fix socket binding and fork error handling in mtr_socket_relay.pm --- mysql-test/lib/mtr_socket_relay.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_socket_relay.pm b/mysql-test/lib/mtr_socket_relay.pm index 60b7aaf18d8fc..db881b437c283 100644 --- a/mysql-test/lib/mtr_socket_relay.pm +++ b/mysql-test/lib/mtr_socket_relay.pm @@ -22,6 +22,7 @@ sub setup_relay { my ($listen_port, $target_host, $target_port) = @_; my $listen_sock = IO::Socket::INET->new( + LocalAddr => '127.0.0.1', LocalPort => $listen_port, Type => SOCK_STREAM, ReuseAddr => 1, @@ -33,7 +34,9 @@ sub setup_relay { local $SIG{CHLD} = 'IGNORE'; close STDOUT; - fork and exit; + my $pid = fork; + die "setup_relay: fork failed: $!" unless defined $pid; + exit if $pid; POSIX::setsid(); open(STDOUT, '>', '/dev/null'); From 57715538cffe68cefb2500a84b8f672ec067aa10 Mon Sep 17 00:00:00 2001 From: ARaveala Date: Fri, 24 Jul 2026 11:06:52 +0300 Subject: [PATCH 3/5] MDEV-39762: fix LocalAddr to use target_host in mtr_socket_relay.pm --- mysql-test/lib/mtr_socket_relay.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_socket_relay.pm b/mysql-test/lib/mtr_socket_relay.pm index db881b437c283..0ec0dbf676478 100644 --- a/mysql-test/lib/mtr_socket_relay.pm +++ b/mysql-test/lib/mtr_socket_relay.pm @@ -22,7 +22,7 @@ sub setup_relay { my ($listen_port, $target_host, $target_port) = @_; my $listen_sock = IO::Socket::INET->new( - LocalAddr => '127.0.0.1', + LocalAddr => $target_host, LocalPort => $listen_port, Type => SOCK_STREAM, ReuseAddr => 1, From 8074eba8261c077723fb9c2df6ebc3615aaa87ab Mon Sep 17 00:00:00 2001 From: ARaveala Date: Fri, 24 Jul 2026 12:21:36 +0300 Subject: [PATCH 4/5] MDEV-39762: mask GTID position in test cleanup to fix buildbot failure The GTID value set during cleanup is environment specific and differs between machines. Use --replace_result to mask it in the result file so the test passes consistently on any server. --- mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result | 2 +- mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result | 2 +- mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test | 1 + mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result index d3ea59cd38bce..d0d14fc75eef0 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result @@ -30,7 +30,7 @@ Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; connection master; connection slave; -SET GLOBAL gtid_slave_pos='0-1-2'; +SET GLOBAL gtid_slave_pos='MASTER_GTID'; include/start_slave.inc connection master; SET GLOBAL log_bin_compress = 0; diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result index 6ee371ea4cfb1..08e52e6a3ca79 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result @@ -29,7 +29,7 @@ Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; connection master; connection slave; -SET GLOBAL gtid_slave_pos='0-1-2'; +SET GLOBAL gtid_slave_pos='MASTER_GTID'; include/start_slave.inc connection master; SET GLOBAL log_bin_compress = 0; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test index 9ffbb6dd5b773..359f61fa0caca 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test @@ -81,6 +81,7 @@ RESET SLAVE ALL; --connection master let $master_gtid= `SELECT @@gtid_binlog_pos`; --connection slave +--replace_result $master_gtid MASTER_GTID --eval SET GLOBAL gtid_slave_pos='$master_gtid' --source include/start_slave.inc diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test index faf897baaadd0..40fb1460b9c08 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test @@ -81,6 +81,7 @@ RESET SLAVE ALL; --connection master let $master_gtid= `SELECT @@gtid_binlog_pos`; --connection slave +--replace_result $master_gtid MASTER_GTID --eval SET GLOBAL gtid_slave_pos='$master_gtid' --source include/start_slave.inc From ee01f1821fcdcc3933b5554aec27bf7c55dc2e18 Mon Sep 17 00:00:00 2001 From: ARaveala Date: Fri, 24 Jul 2026 15:00:15 +0300 Subject: [PATCH 5/5] MDEV-39762: fix GTID conflict in test cleanup on slave binary log Add RESET MASTER on slave before setting gtid_slave_pos to clear the slave's own binary log, preventing GTID conflict warning during cleanup. Mask the GTID position value in result files with --replace_result as it is environment-specific. --- mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result | 1 + mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result | 1 + mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test | 1 + mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test | 1 + 4 files changed, 4 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result index d0d14fc75eef0..372ae3bdde525 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow.result @@ -27,6 +27,7 @@ Note 1255 Slave already has been stopped RESET SLAVE ALL; Warnings: Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' to 'Slave_Pos' +RESET MASTER; CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; connection master; connection slave; diff --git a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result index 08e52e6a3ca79..51245f62f1c4f 100644 --- a/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result +++ b/mysql-test/suite/rpl/r/rpl_binlog_compress_overflow_row.result @@ -26,6 +26,7 @@ Note 1255 Slave already has been stopped RESET SLAVE ALL; Warnings: Note 4190 RESET SLAVE is implicitly changing the value of 'Using_Gtid' from 'No' to 'Slave_Pos' +RESET MASTER; CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS; connection master; connection slave; diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test index 359f61fa0caca..0d6dd795d569c 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow.test @@ -72,6 +72,7 @@ INSERT INTO t1 VALUES ('test'); --connection slave STOP SLAVE; RESET SLAVE ALL; +RESET MASTER; # Reconnect to real master and reset GTID position so rpl_end can sync --replace_result $MASTER_MYPORT MASTER_PORT diff --git a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test index 40fb1460b9c08..a0f10e68846d6 100644 --- a/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test +++ b/mysql-test/suite/rpl/t/rpl_binlog_compress_overflow_row.test @@ -74,6 +74,7 @@ INSERT INTO t1 VALUES (REPEAT('x', 256)); --connection slave STOP SLAVE; RESET SLAVE ALL; +RESET MASTER; --replace_result $MASTER_MYPORT MASTER_PORT --eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_PASSWORD='', MASTER_USE_GTID=SLAVE_POS