1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Bug#17632978 SLAVE CRASHES IF ROW EVENT IS CORRUPTED

(MYSQLBINLOG -V CRASHES WITH THAT BINLOG)

Problem: If slave receives a corrupted row event,
slave server is crashing.

Analysis: When slave is unpacking the row event, it is
not validating the data before applying the event. If the
data is corrupted for eg: the length of a field is wrong,
it could end up reading wrong data leading to a crash.
A similar problem happens when mysqlbinlog tool is used
against a corrupted binlog using '-v' option. Due to -v
option, the tool tries to print the values of all the
fields. Corrupted field length could lead to a crash.

Fix: Before unpacking the field, a verification
will be made on the length. If it falls into the event
range, only then it will be unpacked. Otherwise,
"ER_SLAVE_CORRUPT_EVENT" error will be thrown.
Incase mysqlbinlog -v case, the field value will not be
printed and the processing of the file will be stopped.

sql/field.h:
  Removed a function which is not required anymore
sql/log_event.cc:
  Adding a validation on the field length before
  the tool tries to print the value.
sql/log_event.h:
  Changing unpack_row call according to the new arguments
sql/log_event_old.h:
  Changing unpack_row call according to the new arguments
sql/rpl_record.cc:
  Adding a new argument 'row_end' which tells
  the end position of the complete data in the
  row event. It will be used to do validation
  before doing 'unpack' field.
sql/rpl_record.h:
  Adding a new argument 'row_end' which tells
  the end position of the complete data in the
  row event. It will be used to do validation
  before doing 'unpack' field.
sql/rpl_utility.cc:
  Now calc_field_size() is required for client too.
This commit is contained in:
Venkatesh Duggirala
2013-12-17 22:11:22 +05:30
parent afd24eb63d
commit 5fa9664b07
7 changed files with 41 additions and 45 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2007, 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
@ -169,11 +169,15 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
@param row_data
Packed row data
@param cols Pointer to bitset describing columns to fill in
@param row_end Pointer to variable that will hold the value of the
one-after-end position for the row
@param curr_row_end
Pointer to variable that will hold the value of the
one-after-end position for the current row
@param master_reclength
Pointer to variable that will be set to the length of the
record on the master side
@param row_end
Pointer to variable that will hold the value of the
end position for the data in the row event
@retval 0 No error
@ -185,7 +189,8 @@ int
unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
uchar const **const row_end, ulong *const master_reclength)
uchar const **const current_row_end, ulong *const master_reclength,
uchar const *const row_end)
{
DBUG_ENTER("unpack_row");
DBUG_ASSERT(row_data);
@ -303,6 +308,13 @@ unpack_row(Relay_log_info const *rli,
#ifndef DBUG_OFF
uchar const *const old_pack_ptr= pack_ptr;
#endif
uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr);
if ( pack_ptr + len > row_end )
{
pack_ptr+= len;
my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT);
}
pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE);
DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;"
" pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
@ -369,6 +381,11 @@ unpack_row(Relay_log_info const *rli,
uint32 len= tabledef->calc_field_size(i, (uchar *) pack_ptr);
DBUG_DUMP("field_data", pack_ptr, len);
pack_ptr+= len;
if ( pack_ptr > row_end )
{
my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT);
}
}
null_mask <<= 1;
}
@ -382,7 +399,7 @@ unpack_row(Relay_log_info const *rli,
DBUG_DUMP("row_data", row_data, pack_ptr - row_data);
*row_end = pack_ptr;
*current_row_end = pack_ptr;
if (master_reclength)
{
if (*field_ptr)