summaryrefslogtreecommitdiff
path: root/client/mysqlbinlog.cc
diff options
context:
space:
mode:
authorSujatha Sivakumar <sujatha.sivakumar@oracle.com>2013-03-18 15:01:16 +0530
committerSujatha Sivakumar <sujatha.sivakumar@oracle.com>2013-03-18 15:01:16 +0530
commitb95d5cdaa4c0231abe906d8ad3912fbdd2f685fc (patch)
tree83bf47910e19bf2ca4c46f12fdede6de407a957c /client/mysqlbinlog.cc
parenta6adbd05333f0cfc7365974caa452e03cbb6fa7d (diff)
downloadmariadb-git-b95d5cdaa4c0231abe906d8ad3912fbdd2f685fc.tar.gz
Bug#14771299 OUT-OF-BOUND READS WRITE IN MYSQLBINLOG
Problem: ======= Found using AddressSanitizer testing. The mysqlbinlog utility may result in out-of-bound heap buffer reads and thus, undefined behaviour, when processing RBR events in the old (pre-5.1 GA) format. The following code in process_event() would only be correct if Rows_log_event was the base class for Write,Update,Delete_rows_log_event_old classes: case PRE_GA_WRITE_ROWS_EVENT: case PRE_GA_DELETE_ROWS_EVENT: case PRE_GA_UPDATE_ROWS_EVENT: ... Rows_log_event *e= (Rows_log_event*) ev; Table_map_log_event *ignored_map= print_event_info->m_table_map_ignored.get_table(e->get_table_id()); ... if (e->get_flags(Rows_log_event::STMT_END_F)) { ... } However, Rows_log_event is only the base class for the Write,Update_Delete_rows_event family of classes, but not for their *_old counterparts. So the above typecasts are incorrect for the old-format RBR events and may result (and do result according to AddressSanitizer reports) in reading memory outside of the previously allocated on heap buffer. Fix: === The above mentioned invalid type cast has been replaced with appropriate old counterpart. Note:The above mentioned issue is present only mysql-5.1 and 5.5. This is fixed in mysql-5.6 and above as part of Bug#55790. Hence few of the relevant changes of Bug#55790 are being back ported to fix the current issue. client/mysqlbinlog.cc: The above mentioned invalid type cast of using new event object to read old events, has been replaced with appropriate old counterpart. Note:The above mentioned issue is present only mysql-5.1 and 5.5. This is fixed in mysql-5.6 and above as part of Bug#55790. Hence few of the relevant changes of Bug#55790 are being back ported to fix the current issue.
Diffstat (limited to 'client/mysqlbinlog.cc')
-rw-r--r--client/mysqlbinlog.cc46
1 files changed, 31 insertions, 15 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index c32f92ae149..8a8c7e98940 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -929,20 +929,37 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
case PRE_GA_DELETE_ROWS_EVENT:
case PRE_GA_UPDATE_ROWS_EVENT:
{
- if (ev_type != TABLE_MAP_EVENT)
+ bool stmt_end= FALSE;
+ Table_map_log_event *ignored_map= NULL;
+
+ if (ev_type == WRITE_ROWS_EVENT ||
+ ev_type == DELETE_ROWS_EVENT ||
+ ev_type == UPDATE_ROWS_EVENT)
{
- Rows_log_event *e= (Rows_log_event*) ev;
- Table_map_log_event *ignored_map=
- print_event_info->m_table_map_ignored.get_table(e->get_table_id());
- bool skip_event= (ignored_map != NULL);
-
- /*
- end of statement check:
- i) destroy/free ignored maps
- ii) if skip event, flush cache now
- */
- if (e->get_flags(Rows_log_event::STMT_END_F))
- {
+ Rows_log_event *new_ev= (Rows_log_event*) ev;
+ if (new_ev->get_flags(Rows_log_event::STMT_END_F))
+ stmt_end= TRUE;
+ ignored_map= print_event_info->m_table_map_ignored.get_table(new_ev->get_table_id());
+ }
+ else if (ev_type == PRE_GA_WRITE_ROWS_EVENT ||
+ ev_type == PRE_GA_DELETE_ROWS_EVENT ||
+ ev_type == PRE_GA_UPDATE_ROWS_EVENT)
+ {
+ Old_rows_log_event *old_ev= (Old_rows_log_event*) ev;
+ if (old_ev->get_flags(Rows_log_event::STMT_END_F))
+ stmt_end= TRUE;
+ ignored_map= print_event_info->m_table_map_ignored.get_table(old_ev->get_table_id());
+ }
+
+ bool skip_event= (ignored_map != NULL);
+ /*
+ end of statement check:
+ i) destroy/free ignored maps
+ ii) if skip event, flush cache now
+ */
+ if (stmt_end)
+ {
+
/*
Now is safe to clear ignored map (clear_tables will also
delete original table map events stored in the map).
@@ -969,7 +986,6 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
/* skip the event check */
if (skip_event)
goto end;
- }
/*
These events must be printed in base64 format, if printed.
base64 format requires a FD event to be safe, so if no FD