Skip to content

Commit 0d0c59f

Browse files
author
Sujatha Sivakumar
committed
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.
1 parent 0fc7b50 commit 0d0c59f

File tree

2 files changed

+15
-10
lines changed

2 files changed

+15
-10
lines changed

sql/log_event.cc

+13-8
Original file line numberDiff line numberDiff line change
@@ -1307,7 +1307,7 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
13071307
ev = new Execute_load_log_event(buf, event_len, description_event);
13081308
break;
13091309
case START_EVENT_V3: /* this is sent only by MySQL <=4.x */
1310-
ev = new Start_log_event_v3(buf, description_event);
1310+
ev = new Start_log_event_v3(buf, event_len, description_event);
13111311
break;
13121312
case STOP_EVENT:
13131313
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)
37883788
Start_log_event_v3::Start_log_event_v3()
37893789
*/
37903790

3791-
Start_log_event_v3::Start_log_event_v3(const char* buf,
3791+
Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
37923792
const Format_description_log_event
37933793
*description_event)
3794-
:Log_event(buf, description_event)
3794+
:Log_event(buf, description_event), binlog_version(BINLOG_VERSION)
37953795
{
3796+
if (event_len < (uint)description_event->common_header_len +
3797+
ST_COMMON_HEADER_LEN_OFFSET)
3798+
{
3799+
server_version[0]= 0;
3800+
return;
3801+
}
37963802
buf+= description_event->common_header_len;
37973803
binlog_version= uint2korr(buf+ST_BINLOG_VER_OFFSET);
37983804
memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
@@ -4082,16 +4088,15 @@ Format_description_log_event(const char* buf,
40824088
const
40834089
Format_description_log_event*
40844090
description_event)
4085-
:Start_log_event_v3(buf, description_event), event_type_permutation(0)
4091+
:Start_log_event_v3(buf, event_len, description_event),
4092+
common_header_len(0), post_header_len(NULL), event_type_permutation(0)
40864093
{
40874094
DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)");
4095+
if (!Start_log_event_v3::is_valid())
4096+
DBUG_VOID_RETURN; /* sanity check */
40884097
buf+= LOG_EVENT_MINIMAL_HEADER_LEN;
40894098
if ((common_header_len=buf[ST_COMMON_HEADER_LEN_OFFSET]) < OLD_HEADER_LEN)
4090-
{
4091-
/* this makes is_valid() return false. */
4092-
post_header_len= NULL;
40934099
DBUG_VOID_RETURN; /* sanity check */
4094-
}
40954100
number_of_event_types=
40964101
event_len-(LOG_EVENT_MINIMAL_HEADER_LEN+ST_COMMON_HEADER_LEN_OFFSET+1);
40974102
DBUG_PRINT("info", ("common_header_len=%d number_of_event_types=%d",

sql/log_event.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -2276,14 +2276,14 @@ class Start_log_event_v3: public Log_event
22762276
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
22772277
#endif
22782278

2279-
Start_log_event_v3(const char* buf,
2279+
Start_log_event_v3(const char* buf, uint event_len,
22802280
const Format_description_log_event* description_event);
22812281
~Start_log_event_v3() {}
22822282
Log_event_type get_type_code() { return START_EVENT_V3;}
22832283
#ifdef MYSQL_SERVER
22842284
bool write(IO_CACHE* file);
22852285
#endif
2286-
bool is_valid() const { return 1; }
2286+
bool is_valid() const { return server_version[0] != 0; }
22872287
int get_data_size()
22882288
{
22892289
return START_V3_HEADER_LEN; //no variable-sized part

0 commit comments

Comments
 (0)