Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions mysql-test/main/mdev_38010.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include/master-slave.inc
[connection master]
connection slave;
include/stop_slave.inc
call mtr.add_suppression("Error reading master configuration");
call mtr.add_suppression("Failed to initialize the master info structure");
call mtr.add_suppression("error connecting to master");
include/rpl_restart_server.inc [server_number=2]
connection slave;
# Verifying that trailing garbage causes parsing to fail.
# Rejection successful.
# Restoring the slave to original replication state
include/rpl_restart_server.inc [server_number=2]
CHANGE MASTER TO MASTER_HOST='MASTER_HOST', MASTER_PORT=MASTER_PORT, MASTER_USER='MASTER_USER';
include/start_slave.inc
connection master;
include/rpl_end.inc
89 changes: 89 additions & 0 deletions mysql-test/main/mdev_38010.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#
# MDEV-38010: Trailing garbage in master.info numeric fields leads to corruption.
# This test verifis that the server strictly validates numeric lines in master.info.
# If trailing non-whitespace characters are found, the line is rejected as corrupted.
#

--source include/master-slave.inc
--source include/have_binlog_format_mixed.inc

--connection slave

# Step1: Capture the current working replication state.
# We need these to restore a clean environment after we've intentionally
# "broken" the master.info file for the test.
--let $master_host= query_get_value(SHOW SLAVE STATUS, Master_Host, 1)
--let $master_port= query_get_value(SHOW SLAVE STATUS, Master_Port, 1)
--let $master_user= query_get_value(SHOW SLAVE STATUS, Master_User, 1)

--source include/stop_slave.inc

# Suppress the err we expect to see in the log during this test.
# The server will log these when it hits our new strict validation logic.
call mtr.add_suppression("Error reading master configuration");
call mtr.add_suppression("Failed to initialize the master info structure");
call mtr.add_suppression("error connecting to master");

--let $MYSQLD_DATADIR= `select @@datadir`

# Step2: Simulate a corrupted master.info file.
# We manually rewrite the file with "garbage" appended to numeric fields
# (Port and Connect_Retry) to trigger the new validation check.
--remove_file $MYSQLD_DATADIR/master.info
--write_file $MYSQLD_DATADIR/master.info
17
master-bin.000001
4
127.0.0.1
root

3306abcdefghijklmnopqrstuvwxyz&10
60
0
0



0

60.000abcdefghijklm
1 1
EOF

# Step3: Restart the slave to force it to parse the corrupted file.
--let $rpl_server_number= 2
--source include/rpl_restart_server.inc

--connection slave

--echo # Verifying that trailing garbage causes parsing to fail.
# If the fix works, the server should reject the bad port "3306abcdef..."
# This may lead to Master_Port being unset or the slave failing to show up.
--let $port= query_get_value(SHOW SLAVE STATUS, Master_Port, 1)

if ($port != 3306) {
if ($port != No such row) {
if ($port != "") {
--echo Error: The garbage in master.info was accepted! Port evaluated to $port.
--die "Test failed: Fix is not preventing garbage parsing."
}
}
}
--echo # Rejection successful.

# Step4: Cleanup and Restoration.
# We remove the bad master.info and use CHANGE MASTER TO with our saved
# parameters to restore the slave to its original state.
--remove_file $MYSQLD_DATADIR/master.info

--echo # Restoring the slave to original replication state
--let $rpl_server_number= 2
--source include/rpl_restart_server.inc

--replace_result $master_port MASTER_PORT $master_host MASTER_HOST $master_user MASTER_USER
--eval CHANGE MASTER TO MASTER_HOST='$master_host', MASTER_PORT=$master_port, MASTER_USER='$master_user'
--source include/start_slave.inc

--connection master
--source include/rpl_end.inc

2 changes: 2 additions & 0 deletions sql/rpl_mi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg,
{
char *tmp;
host[0] = 0; user[0] = 0; password[0] = 0;
master_log_pos = 0;
master_log_name[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
ssl_cipher[0]= 0; ssl_key[0]= 0;
ssl_crl[0]= 0; ssl_crlpath[0]= 0;
Expand Down
73 changes: 51 additions & 22 deletions sql/slave.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1699,47 +1699,67 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
DBUG_RETURN(1);
}

/*
when moving these functions to mysys, don't forget to
remove slave.cc from libmysqld/CMakeLists.txt
*/


int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
DBUG_ENTER("init_intvar_from_file");

*var= default_val;

if (my_b_gets(f, buf, sizeof(buf)))
{
*var = atoi(buf);
char *endptr= buf + strlen(buf);
int error= 0;
longlong val= my_strtoll10(buf, &endptr, &error);

if (error && error != MY_ERRNO_EDOM)
DBUG_RETURN(1);

while (my_isspace(&my_charset_latin1, *endptr))
endptr++;
if (*endptr != '\0')
DBUG_RETURN(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you need to assign something to *var here. Otherwise msan complains.


*var= (int) val;
DBUG_RETURN(0);
}
else if (default_val)
{
*var = default_val;

if (default_val)
DBUG_RETURN(0);
}

DBUG_RETURN(1);
}

int init_ulonglongvar_from_file(ulonglong* var, IO_CACHE* f,
ulonglong default_val)
{
char buf[MY_INT64_NUM_DECIMAL_DIGITS];
int error;
int error= 0;
DBUG_ENTER("init_ulonglongvar_from_file");

*var= default_val;

if (my_b_gets(f, buf, sizeof(buf)))
{
*var = (ulonglong) my_strtoll10(buf, (char**) 0, &error);
char *endptr= buf + strlen(buf);
*var= (ulonglong) my_strtoll10(buf, &endptr, &error);

if (error && error != MY_ERRNO_EDOM)
DBUG_RETURN(1);

while (my_isspace(&my_charset_latin1, *endptr))
endptr++;
if (*endptr != '\0')
DBUG_RETURN(1);

DBUG_RETURN(0);
}
else if (default_val)
{
*var = default_val;

if (default_val)
DBUG_RETURN(0);
}

DBUG_RETURN(1);
}

Expand All @@ -1748,19 +1768,28 @@ int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val)
char buf[16];
DBUG_ENTER("init_floatvar_from_file");

*var= default_val;

if (my_b_gets(f, buf, sizeof(buf)))
{
if (sscanf(buf, "%f", var) != 1)
char *endptr= buf + strlen(buf);
int error= 0;
double val= my_strtod(buf, &endptr, &error);
if (error && error != MY_ERRNO_EDOM)
DBUG_RETURN(1);
else
DBUG_RETURN(0);
}
else if (default_val != 0.0)
{
*var = default_val;

while (my_isspace(&my_charset_latin1, *endptr))
endptr++;
if (*endptr != '\0')
DBUG_RETURN(1);

*var= (float) val;
DBUG_RETURN(0);
}

if (default_val != 0.0)
DBUG_RETURN(0);

DBUG_RETURN(1);
}

Expand Down