Skip to content

Commit 2292970

Browse files
committed
Bug #14525642: SEVERAL COM_* COMMANDS DON'T CHECK PACKET-LENGTH
Added length checks reading the incoming network packets in the places they were missing. Test cases added.
1 parent c873269 commit 2292970

File tree

4 files changed

+85
-16
lines changed

4 files changed

+85
-16
lines changed

sql/rpl_master.cc

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,14 @@ extern TYPELIB binlog_checksum_typelib;
4343

4444
#define get_object(p, obj, msg) \
4545
{\
46-
uint len = (uint)*p++; \
46+
uint len; \
47+
if (p >= p_end) \
48+
{ \
49+
my_error(ER_MALFORMED_PACKET, MYF(0)); \
50+
my_free(si); \
51+
return 1; \
52+
} \
53+
len= (uint)*p++; \
4754
if (p + len > p_end || len >= sizeof(obj)) \
4855
{\
4956
errmsg= msg;\
@@ -126,6 +133,14 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
126133
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
127134
goto err2;
128135

136+
/* 4 bytes for the server id */
137+
if (p + 4 > p_end)
138+
{
139+
my_error(ER_MALFORMED_PACKET, MYF(0));
140+
my_free(si);
141+
return 1;
142+
}
143+
129144
thd->server_id= si->server_id= uint4korr(p);
130145
p+= 4;
131146
get_object(p,si->host, "Failed to register slave: too long 'report-host'");

sql/sql_parse.cc

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,12 +1296,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
12961296
}
12971297
case COM_STMT_CLOSE:
12981298
{
1299-
mysqld_stmt_close(thd, packet);
1299+
mysqld_stmt_close(thd, packet, packet_length);
13001300
break;
13011301
}
13021302
case COM_STMT_RESET:
13031303
{
1304-
mysqld_stmt_reset(thd, packet);
1304+
mysqld_stmt_reset(thd, packet, packet_length);
13051305
break;
13061306
}
13071307
case COM_QUERY:
@@ -1536,6 +1536,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
15361536
{
15371537
int not_used;
15381538

1539+
if (packet_length < 1)
1540+
{
1541+
my_error(ER_MALFORMED_PACKET, MYF(0));
1542+
break;
1543+
}
1544+
15391545
/*
15401546
Initialize thd->lex since it's used in many base functions, such as
15411547
open_tables(). Otherwise, it remains unitialized and may cause crash
@@ -1584,6 +1590,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
15841590
#ifndef EMBEDDED_LIBRARY
15851591
case COM_SHUTDOWN:
15861592
{
1593+
if (packet_length < 1)
1594+
{
1595+
my_error(ER_MALFORMED_PACKET, MYF(0));
1596+
break;
1597+
}
15871598
status_var_increment(thd->status_var.com_other);
15881599
if (check_global_access(thd,SHUTDOWN_ACL))
15891600
break; /* purecov: inspected */
@@ -1670,6 +1681,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
16701681
{
16711682
if (thread_id & (~0xfffffffful))
16721683
my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "thread_id", "mysql_kill()");
1684+
else if (packet_length < 4)
1685+
my_error(ER_MALFORMED_PACKET, MYF(0));
16731686
else
16741687
{
16751688
status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]);
@@ -1680,6 +1693,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
16801693
}
16811694
case COM_SET_OPTION:
16821695
{
1696+
1697+
if (packet_length < 2)
1698+
{
1699+
my_error(ER_MALFORMED_PACKET, MYF(0));
1700+
break;
1701+
}
16831702
status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]);
16841703
uint opt_command= uint2korr(packet);
16851704

sql/sql_prepare.cc

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -959,6 +959,9 @@ static bool setup_conversion_functions(Prepared_statement *stmt,
959959

960960
DBUG_ENTER("setup_conversion_functions");
961961

962+
if (read_pos >= data_end)
963+
DBUG_RETURN(1);
964+
962965
if (*read_pos++) //types supplied / first execute
963966
{
964967
/*
@@ -2624,8 +2627,8 @@ static void reset_stmt_params(Prepared_statement *stmt)
26242627
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
26252628
{
26262629
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
2627-
ulong stmt_id= uint4korr(packet);
2628-
ulong flags= (ulong) packet[4];
2630+
ulong stmt_id;
2631+
ulong flags;
26292632
/* Query text for binary, general or slow log, if any of them is open */
26302633
String expanded_query;
26312634
uchar *packet_end= packet + packet_length;
@@ -2634,6 +2637,14 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
26342637
bool open_cursor;
26352638
DBUG_ENTER("mysqld_stmt_execute");
26362639

2640+
if (packet + 9 > packet_end)
2641+
{
2642+
my_error(ER_MALFORMED_PACKET, MYF(0));
2643+
DBUG_VOID_RETURN;
2644+
}
2645+
2646+
stmt_id= uint4korr(packet);
2647+
flags= (ulong) packet[4];
26372648
packet+= 9; /* stmt_id + 5 bytes of flags */
26382649

26392650
/* First of all clear possible warnings from the previous command */
@@ -2728,13 +2739,21 @@ void mysql_sql_stmt_execute(THD *thd)
27282739
void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
27292740
{
27302741
/* assume there is always place for 8-16 bytes */
2731-
ulong stmt_id= uint4korr(packet);
2732-
ulong num_rows= uint4korr(packet+4);
2742+
ulong stmt_id;
2743+
ulong num_rows;
27332744
Prepared_statement *stmt;
27342745
Statement stmt_backup;
27352746
Server_side_cursor *cursor;
27362747
DBUG_ENTER("mysqld_stmt_fetch");
27372748

2749+
if (packet_length < 8)
2750+
{
2751+
my_error(ER_MALFORMED_PACKET, MYF(0));
2752+
DBUG_VOID_RETURN;
2753+
}
2754+
stmt_id= uint4korr(packet);
2755+
num_rows= uint4korr(packet+4);
2756+
27382757
/* First of all clear possible warnings from the previous command */
27392758
mysql_reset_thd_for_next_command(thd);
27402759
status_var_increment(thd->status_var.com_stmt_fetch);
@@ -2785,15 +2804,23 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
27852804
27862805
@param thd Thread handle
27872806
@param packet Packet with stmt id
2807+
@param packet_length length of data in packet
27882808
*/
27892809

2790-
void mysqld_stmt_reset(THD *thd, char *packet)
2810+
void mysqld_stmt_reset(THD *thd, char *packet, uint packet_length)
27912811
{
2792-
/* There is always space for 4 bytes in buffer */
2793-
ulong stmt_id= uint4korr(packet);
2812+
ulong stmt_id;
27942813
Prepared_statement *stmt;
27952814
DBUG_ENTER("mysqld_stmt_reset");
27962815

2816+
if (packet_length < 4)
2817+
{
2818+
my_error(ER_MALFORMED_PACKET, MYF(0));
2819+
DBUG_VOID_RETURN;
2820+
}
2821+
2822+
stmt_id= uint4korr(packet);
2823+
27972824
/* First of all clear possible warnings from the previous command */
27982825
mysql_reset_thd_for_next_command(thd);
27992826

@@ -2831,13 +2858,21 @@ void mysqld_stmt_reset(THD *thd, char *packet)
28312858
we don't send any reply to this command.
28322859
*/
28332860

2834-
void mysqld_stmt_close(THD *thd, char *packet)
2861+
void mysqld_stmt_close(THD *thd, char *packet, uint packet_length)
28352862
{
28362863
/* There is always space for 4 bytes in packet buffer */
2837-
ulong stmt_id= uint4korr(packet);
2864+
ulong stmt_id;
28382865
Prepared_statement *stmt;
28392866
DBUG_ENTER("mysqld_stmt_close");
28402867

2868+
if (packet_length < 4)
2869+
{
2870+
my_error(ER_MALFORMED_PACKET, MYF(0));
2871+
DBUG_VOID_RETURN;
2872+
}
2873+
2874+
stmt_id= uint4korr(packet);
2875+
28412876
thd->get_stmt_da()->disable_status();
28422877

28432878
if (!(stmt= find_prepared_statement(thd, stmt_id)))

sql/sql_prepare.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#ifndef SQL_PREPARE_H
22
#define SQL_PREPARE_H
3-
/* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
3+
/* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
44
55
This program is free software; you can redistribute it and/or modify
66
it under the terms of the GNU General Public License as published by
@@ -67,12 +67,12 @@ class Reprepare_observer
6767

6868
void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length);
6969
void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length);
70-
void mysqld_stmt_close(THD *thd, char *packet);
70+
void mysqld_stmt_close(THD *thd, char *packet, uint packet_length);
7171
void mysql_sql_stmt_prepare(THD *thd);
7272
void mysql_sql_stmt_execute(THD *thd);
7373
void mysql_sql_stmt_close(THD *thd);
7474
void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length);
75-
void mysqld_stmt_reset(THD *thd, char *packet);
75+
void mysqld_stmt_reset(THD *thd, char *packet, uint packet_length);
7676
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
7777
void reinit_stmt_before_use(THD *thd, LEX *lex);
7878

0 commit comments

Comments
 (0)