3861 Nuno Carvalho 2012-03-26
Bug#13799555: ROWS_QUERY_LOG_EVENTS DOES NOT ESCAPE MULTI-LINE QUERIES PROPERLY
When binlog_rows_query_log_events = 1 and a statement is written to the
binary log in row format, the server generates a log event containing
the original query text. If mysqlbinlog is given the option --verbose
--verbose the original statement is printed. To prevent the statement
from being executed, it is prefixed by '#'. However, this is not enough
for multi-line statements: only the first line of the query will be
commented out.
If a malicious user knows that the binary log will be processed using
mysqlbinlog --verbose --verbose, then the user can execute arbitrary
statements on the server.
Prefix every line of a multi-line query with '#' to prevent the
statement from being executed when binary log will be processed
using 'mysqlbinlog --verbose --verbose'.
modified:
mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result
mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test
sql/log_event.cc
3860 Martin Zaun 2012-03-26
Bug#54854 - updated copyright headers
modified:
sql/rpl_slave.cc
sql/rpl_slave.h
=== modified file 'mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result'
--- a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result 2009-10-14 13:25:11 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result 2012-03-26 21:29:37 +0000
@@ -159,3 +159,9 @@ stmt
### WHERE
### @1=2
drop table raw_binlog_rows;
+SET @@SESSION.BINLOG_ROWS_QUERY_LOG_EVENTS = 1;
+CREATE TABLE t1 (a VARCHAR(50));
+INSERT INTO t1 VALUES ("
+ GRANT ALL ON *.* TO 'batman'/*!*/;
+ ")|
+DROP TABLE t1;
=== modified file 'mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test'
--- a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test 2009-10-14 13:25:11 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test 2012-03-26 21:29:37 +0000
@@ -32,9 +32,6 @@
# tool and the output is checked.
#
########################################################
-
-# We require binlog_format_row as we're independent of binlog format
-# and there's no point running the same test 3 times
-- source include/have_binlog_format_row.inc
--disable_query_log
@@ -84,3 +81,63 @@ create table raw_binlog_rows (txt varcha
# Output --verbose lines, with extra Windows CR's trimmed
select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%';
drop table raw_binlog_rows;
+
+
+#######################################################################
+# BUG#13799555: ROWS_QUERY_LOG_EVENTS DOES NOT ESCAPE MULTI-LINE QUERIES PROPERLY
+#
+# Check that when mysqlbinlog is given the option --verbose --verbose,
+# the multi-line original statement are properly escaped to prevent from
+# being executed.
+SET @@SESSION.BINLOG_ROWS_QUERY_LOG_EVENTS = 1;
+CREATE TABLE t1 (a VARCHAR(50));
+--let $binlog_start_position= query_get_value("SHOW MASTER STATUS", Position, 1)
+
+--delimiter |
+INSERT INTO t1 VALUES ("
+ GRANT ALL ON *.* TO 'batman'/*!*/;
+ ")|
+--delimiter ;
+
+--let $binlog_stop_position= query_get_value("SHOW MASTER STATUS", Position, 1)
+--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
+--let $datadir= `SELECT @@datadir`
+
+--let $_prefix= `SELECT UUID()`
+--let $TMP_FILE= $MYSQLTEST_VARDIR/tmp/$_prefix.tmp
+--exec $MYSQL_BINLOG --force-if-open --verbose --verbose --start-position=$binlog_start_position --stop-position=$binlog_stop_position $datadir/$binlog_file > $TMP_FILE
+
+--let TMP_FILE= $TMP_FILE
+--perl END_OF_FILE
+my $tmp_file= $ENV{'TMP_FILE'};
+
+my $escaped_query = <<END;
+# INSERT INTO t1 VALUES ("
+# GRANT ALL ON *.* TO 'batman'/*!*/;
+# ")
+END
+
+open(FILE, $tmp_file) or die("Unable to open $tmp_file: $!\n");
+my $contents = do { local $/; <FILE> };
+close(FILE) or die("Unable to close file.");
+
+$match= index($contents, $escaped_query) > -1;
+if (!$match)
+{
+ print "\n====================================================\n";
+ print "ESCAPED STRING DID NOT MATCH:\n";
+ print "====================================================\n";
+ print "$escaped_query";
+ print "====================================================\n";
+
+ print "\n====================================================\n";
+ print "BINLOG CONTENTS\n";
+ print "====================================================\n";
+ print "$contents";
+ print "====================================================\n";
+}
+END_OF_FILE
+
+# Clean up
+DROP TABLE t1;
+--remove_file $TMP_FILE
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2012-03-22 17:33:57 +0000
+++ b/sql/log_event.cc 2012-03-26 21:29:37 +0000
@@ -11807,9 +11807,21 @@ Rows_query_log_event::print(FILE *file,
{
IO_CACHE *const head= &print_event_info->head_cache;
IO_CACHE *const body= &print_event_info->body_cache;
+ uint m_rows_query_len= strlen(m_rows_query);
+ char rows_query_copy[m_rows_query_len + 1];
+ char *token= NULL, *saveptr= NULL;
+
print_header(head, print_event_info, FALSE);
my_b_printf(head, "\tRows_query\n");
- my_b_printf(head, "# %s\n", m_rows_query);
+ /*
+ Prefix every line of a multi-line query with '#' to prevent the
+ statement from being executed when binary log will be processed
+ using 'mysqlbinlog --verbose --verbose'.
+ */
+ strmake(rows_query_copy, m_rows_query, m_rows_query_len);
+ for (token= strtok_r(rows_query_copy, "\n", &saveptr); token;
+ token= strtok_r(NULL, "\n", &saveptr))
+ my_b_printf(head, "# %s\n", token);
print_base64(body, print_event_info, true);
}
}
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (nuno.carvalho:3860 to 3861) Bug#13799555 | Nuno Carvalho | 27 Mar |