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