summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSujatha Sivakumar <sujatha.sivakumar@oracle.com>2014-10-08 10:50:02 +0530
committerSujatha Sivakumar <sujatha.sivakumar@oracle.com>2014-10-08 10:50:02 +0530
commit929680913417e6a09330376b9d99f3bf33db7ff3 (patch)
tree0bbf2b0d55a5ee1b7647bfdd713511cfa54bd6a6 /sql
parent27938d14bb5a0313f13e99556d051f3df13d4237 (diff)
downloadmariadb-git-929680913417e6a09330376b9d99f3bf33db7ff3.tar.gz
Bug#19145698: READ OUT OF BOUNDS ISSUE
Problem: ======== In a master slave replication if a slave receives a Start_log_event_v3 the payload is expected to be of fixed size. If a payload which is smaller than the fixed size is received it causes a read out of bounds issue. Analysis: ======== According to documentation the fixed data part of Start_log_event_v3 looks as shown below. 2 bytes: The binary log format version 50 bytes: The MySQL server's version 4 bytes: Timestamp in seconds when this event was created Since the payload is expected to be of fixed size, therefore ST_SERVER_VER_LEN (50) bytes are memcpy'ed into server_version. But if a malicious master sends a shorter payload it causes a read out of bounds issue. Fix: === In Start_log_event_v3 event's constructor a check has been added which expects the minimum payload length to be of size common_header_len + ST_COMMON_HEADER_LEN_OFFSET bytes. If a malicious packet of lesser length is received it will be considered as an invalid event. sql/log_event.cc: Added code changes to check the minimum packet length of Start_log_event_v3 should be > 56. sql/log_event.h: Moved server_version from stack to heap and modified is_valid function for Start_log_event_v3.
Diffstat (limited to 'sql')
-rw-r--r--sql/log_event.cc21
-rw-r--r--sql/log_event.h4
2 files changed, 15 insertions, 10 deletions
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 71ca722ffd6..403c512ab3a 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1307,7 +1307,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Execute_load_log_event(buf, event_len, description_event);
break;
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
- ev = new Start_log_event_v3(buf, description_event);
+ ev = new Start_log_event_v3(buf, event_len, description_event);
break;
case STOP_EVENT:
ev = new Stop_log_event(buf, description_event);
@@ -3788,11 +3788,17 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
Start_log_event_v3::Start_log_event_v3()
*/
-Start_log_event_v3::Start_log_event_v3(const char* buf,
+Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
const Format_description_log_event
*description_event)
- :Log_event(buf, description_event)
+ :Log_event(buf, description_event), binlog_version(BINLOG_VERSION)
{
+ if (event_len < (uint)description_event->common_header_len +
+ ST_COMMON_HEADER_LEN_OFFSET)
+ {
+ server_version[0]= 0;
+ return;
+ }
buf+= description_event->common_header_len;
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
@@ -4082,16 +4088,15 @@ Format_description_log_event(const char* buf,
const
Format_description_log_event*
description_event)
- :Start_log_event_v3(buf, description_event), event_type_permutation(0)
+ :Start_log_event_v3(buf, event_len, description_event),
+ common_header_len(0), post_header_len(NULL), event_type_permutation(0)
{
DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)");
+ if (!Start_log_event_v3::is_valid())
+ DBUG_VOID_RETURN; /* sanity check */
buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < OLD_HEADER_LEN)
- {
- /* this makes is_valid() return false. */
- post_header_len= NULL;
DBUG_VOID_RETURN; /* sanity check */
- }
number_of_event_types=
event_len-(LOG_EVENT_MINIMAL_HEADER_LEN+ST_COMMON_HEADER_LEN_OFFSET+1);
DBUG_PRINT("info", ("common_header_len=%d number_of_event_types=%d",
diff --git a/sql/log_event.h b/sql/log_event.h
index d8f04454a7a..0dd1a9f41e6 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2276,14 +2276,14 @@ public:
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
#endif
- Start_log_event_v3(const char* buf,
+ Start_log_event_v3(const char* buf, uint event_len,
const Format_description_log_event* description_event);
~Start_log_event_v3() {}
Log_event_type get_type_code() { return START_EVENT_V3;}
#ifdef MYSQL_SERVER
bool write(IO_CACHE* file);
#endif
- bool is_valid() const { return 1; }
+ bool is_valid() const { return server_version[0] != 0; }
int get_data_size()
{
return START_V3_HEADER_LEN; //no variable-sized part