diff options
author | Sujatha Sivakumar <sujatha.sivakumar@oracle.com> | 2014-10-08 10:50:02 +0530 |
---|---|---|
committer | Sujatha Sivakumar <sujatha.sivakumar@oracle.com> | 2014-10-08 10:50:02 +0530 |
commit | 929680913417e6a09330376b9d99f3bf33db7ff3 (patch) | |
tree | 0bbf2b0d55a5ee1b7647bfdd713511cfa54bd6a6 | |
parent | 27938d14bb5a0313f13e99556d051f3df13d4237 (diff) | |
download | mariadb-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.
-rw-r--r-- | sql/log_event.cc | 21 | ||||
-rw-r--r-- | sql/log_event.h | 4 |
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 |