List:Commits« Previous MessageNext Message »
From:Sven Sandberg Date:November 8 2007 10:50am
Subject:Re: bk commit to 5.0 - BUG#31793
View as plain text  
Hi Mats,

The patch improves the situation by not crashing on the particular 
binlog attached to the bug report. But there are still many ways that 
similar errors could occur:

  - Each status case in the `switch (*pos++)' in this Query_log_event 
constructor can potentially read beyond `end'. I'd suggest adding a 
macro like this:

#define ENSURE_SPACE(N)       \
   do {                        \
     if (pos + N > end) {      \
       query = 0;              \
       DBUG_VOID_RETURN;       \
     }                         \
   } while (0);

And use it like this:

@@ log_event.cc:1496
     case Q_FLAGS2_CODE:
       flags2_inited= 1;
+     ENSURE_SPACE(4);
       flags2= uint4korr(pos);
       DBUG_PRINT("info",("In Query_log_event, read flags2: %lu", 
(ulong) flags2));
       pos+= 4;
       break;

etc.

  - The same should be tested for catalog and timezone too.

  - Other event types have similar problems. E.g., 
Load_log_event::copy_log_event should check field_block_len, 
table_name_len, and fname_len.

/Sven


Mats Kindahl wrote:
> Patch submitted manually
> 
> 
> ------------------------------------------------------------------------
> 
> # This is a BitKeeper generated diff -Nru style patch.
> #
> # ChangeSet
> #   2007/11/07 14:59:24+01:00 mats@stripped 
> #   BUG#31793 (log event corruption causes crash):
> #   
> #   When running mysqlbinlog on a 64-bit machine with a corrupt relay log,
> #   it causes mysqlbinlog to crash. In this case, the crash is caused
> #   because a request for 18446744073709534806U bytes is issued, which
> #   apparantly can be served on a 64-bit machine (speculatively, I assume)
> #   but this causes the memcpy() issued later to copy the data to segfault.
> #   
> #   The request for the number of bytes is caused by a computation
> #   of data_len - server_vars_len where server_vars_len is corrupt in such
> #   a sense that it is > data_len. This causes a wrap-around, with the
> #   the data_len given above.
> #   
> #   This patch adds a check that if server_vars_len is greater than
> #   data_len before the substraction, and aborts reading the event in
> #   that case marking the event as invalid. 
> # 
> # mysql-test/std_data/corrupt-relay-bin.000624
> #   2007/11/07 14:58:30+01:00 mats@stripped +2033 -0
> #   BitKeeper file
> /home/mats/devel/b31793-mysql-5.0-rpl/mysql-test/std_data/corrupt-relay-bin.000624
> # 
> # mysql-test/std_data/corrupt-relay-bin.000624
> #   2007/11/07 14:58:30+01:00 mats@stripped +0 -0
> # 
> # mysql-test/t/mysqlbinlog.test
> #   2007/11/07 14:59:22+01:00 mats@stripped +4 -0
> #   Adding test that it fails gracefully for a corrupt relay log.
> # 
> # sql/log_event.cc
> #   2007/11/07 14:59:22+01:00 mats@stripped +11 -0
> #   Adding check that status var length does not cause wrap-around
> #   when performing subtraction.
> # 
> Binary files a/mysql-test/std_data/corrupt-relay-bin.000624 and
> b/mysql-test/std_data/corrupt-relay-bin.000624 differ
> diff -Nru a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test
> --- a/mysql-test/t/mysqlbinlog.test	2007-11-07 15:00:13 +01:00
> +++ b/mysql-test/t/mysqlbinlog.test	2007-11-07 15:00:13 +01:00
> @@ -237,4 +237,8 @@
>  --echo $c
>  drop table t1;
>  
> +echo shell> mysqlbinlog std_data/corrupt-relay-bin.000624 >
> var/tmp/bug31793.sql;
> +error 1;
> +exec $MYSQL_BINLOG $MYSQL_TEST_DIR/std_data/corrupt-relay-bin.000624 >
> $MYSQLTEST_VARDIR/tmp/bug31793.sql;
> +
>  --echo End of 5.0 tests
> diff -Nru a/sql/log_event.cc b/sql/log_event.cc
> --- a/sql/log_event.cc	2007-11-07 15:00:13 +01:00
> +++ b/sql/log_event.cc	2007-11-07 15:00:13 +01:00
> @@ -1475,6 +1475,17 @@
>    if (tmp)
>    {
>      status_vars_len= uint2korr(buf + Q_STATUS_VARS_LEN_OFFSET);
> +    /*
> +      Check if status variable length is corrupt and will lead to very
> +      wrong data. We could be even more strict and require data_len to
> +      be even bigger, but this will suffice to catch most corruption
> +      errors that can lead to a crash.
> +    */
> +    if (status_vars_len >= data_len + 1)
> +    {
> +      query= 0;
> +      DBUG_VOID_RETURN;
> +    }
>      data_len-= status_vars_len;
>      DBUG_PRINT("info", ("Query_log_event has status_vars_len: %u",
>                          (uint) status_vars_len));
> 
> 
> 
> ------------------------------------------------------------------------
> 
> 

-- 
Sven Sandberg, Software Engineer
MySQL AB, www.mysql.com
Thread
bk commit to 5.0 - BUG#31793Mats Kindahl7 Nov
  • Re: bk commit to 5.0 - BUG#31793Sven Sandberg8 Nov
    • Re: bk commit to 5.0 - BUG#31793Mats Kindahl8 Nov
    • Re: bk commit to 5.0 - BUG#31793Mats Kindahl8 Nov
      • Re: bk commit to 5.0 - BUG#31793Andrei Elkin9 Nov
        • Re: bk commit to 5.0 - BUG#31793Mats Kindahl9 Nov
          • Re: bk commit to 5.0 - BUG#31793Andrei Elkin9 Nov