List:Commits« Previous MessageNext Message »
From:Nuno Carvalho Date:March 26 2012 9:30pm
Subject:bzr push into mysql-trunk branch (nuno.carvalho:3860 to 3861) Bug#13799555
View as plain text  
 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#13799555Nuno Carvalho27 Mar