mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -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
|
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
|
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_DELETE_ROWS_EVENT:
|
||||||
case PRE_GA_UPDATE_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;
|
||||||
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);
|
|
||||||
|
|
||||||
|
if (ev_type == WRITE_ROWS_EVENT ||
|
||||||
|
ev_type == DELETE_ROWS_EVENT ||
|
||||||
|
ev_type == UPDATE_ROWS_EVENT)
|
||||||
|
{
|
||||||
|
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:
|
end of statement check:
|
||||||
i) destroy/free ignored maps
|
i) destroy/free ignored maps
|
||||||
ii) if skip event, flush cache now
|
ii) if skip event, flush cache now
|
||||||
*/
|
*/
|
||||||
if (e->get_flags(Rows_log_event::STMT_END_F))
|
if (stmt_end)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Now is safe to clear ignored map (clear_tables will also
|
Now is safe to clear ignored map (clear_tables will also
|
||||||
delete original table map events stored in the map).
|
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 */
|
/* skip the event check */
|
||||||
if (skip_event)
|
if (skip_event)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
These events must be printed in base64 format, if printed.
|
These events must be printed in base64 format, if printed.
|
||||||
base64 format requires a FD event to be safe, so if no FD
|
base64 format requires a FD event to be safe, so if no FD
|
||||||
|
Reference in New Issue
Block a user