File mysql-5.0.67-CVE-2010-1849.patch of Package mysql
Index: include/mysql_com.h
===================================================================
--- include/mysql_com.h.orig
+++ include/mysql_com.h
@@ -219,6 +219,10 @@ typedef struct st_net {
my_bool report_error; /* We should report error (we have unreported error) */
my_bool return_errno;
+#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
+ /* Limit on how much data can be skipped if a packet is too big. */
+ unsigned char skip_rest_factor;
+#endif
} NET;
#define packet_error (~(unsigned long) 0)
Index: sql/net_serv.cc
===================================================================
--- sql/net_serv.cc.orig
+++ sql/net_serv.cc
@@ -141,6 +141,9 @@ my_bool my_net_init(NET *net, Vio* vio)
net->query_cache_query= 0;
#endif
net->report_error= 0;
+#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
+ net->skip_rest_factor= 0;
+#endif
if (vio != 0) /* If real connection */
{
@@ -724,6 +727,19 @@ static my_bool net_safe_read(NET *net, c
}
/*
+ Helper function to determine the skip factor.
+*/
+
+static ulonglong my_net_skip_rest_factor(NET *net)
+{
+#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
+ return net->max_packet_size * net->skip_rest_factor;
+#else
+ return net->max_packet_size * 2;
+#endif
+}
+
+/*
Help function to clear the commuication buffer when we get a too big packet.
SYNOPSIS
@@ -742,6 +758,7 @@ static my_bool my_net_skip_rest(NET *net
ALARM *alarm_buff)
{
uint32 old=remain;
+ ulonglong skippable= my_net_skip_rest_factor(net);
DBUG_ENTER("my_net_skip_rest");
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
@@ -757,6 +774,12 @@ static my_bool my_net_skip_rest(NET *net
}
for (;;)
{
+ /* Don't read packets indefinitely. */
+ if (remain >= skippable)
+ DBUG_RETURN(1);
+ else
+ skippable-= remain;
+
while (remain > 0)
{
uint length= min(remain, net->max_packet);
@@ -767,9 +790,12 @@ static my_bool my_net_skip_rest(NET *net
}
if (old != MAX_PACKET_LENGTH)
break;
+ else if (skippable < NET_HEADER_SIZE)
+ DBUG_RETURN(1);
if (net_safe_read(net, (char*) net->buff, NET_HEADER_SIZE, alarmed))
DBUG_RETURN(1);
old=remain= uint3korr(net->buff);
+ skippable-= NET_HEADER_SIZE;
net->pkt_nr++;
}
DBUG_RETURN(0);
Index: sql/sql_parse.cc
===================================================================
--- sql/sql_parse.cc.orig
+++ sql/sql_parse.cc
@@ -445,6 +445,8 @@ int check_user(THD *thd, enum enum_serve
}
send_ok(thd);
thd->password= test(passwd_len); // remember for error messages
+ /* Skip at most 2 * max_packet_size bytes. */
+ thd->net.skip_rest_factor= 2;
/* Ready to handle queries */
DBUG_RETURN(0);
}
Index: tests/mysql_client_test.c
===================================================================
--- tests/mysql_client_test.c.orig
+++ tests/mysql_client_test.c
@@ -16230,6 +16230,80 @@ static void test_bug32265()
DBUG_VOID_RETURN;
}
+/**
+ Bug#50974: Server keeps receiving big (> max_allowed_packet) packets indefinitely.
+*/
+
+#ifndef EMBEDDED_LIBRARY
+
+static void test_bug50974()
+{
+ int rc;
+ MYSQL *con;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ char query_buffer[128], packet[NET_HEADER_SIZE];
+
+ DBUG_ENTER("test_bug50974");
+ myheader("test_bug50974");
+
+ memset(query_buffer, 0, sizeof(query_buffer));
+
+ /* Save values and set them to 1024. */
+
+ rc= mysql_query(mysql, "SELECT @@net_buffer_length, @@max_allowed_packet");
+ myquery(rc);
+
+ res= mysql_store_result(mysql);
+ mytest(res);
+
+ row= mysql_fetch_row(res);
+ mytest(row);
+
+ rc= my_snprintf(query_buffer, sizeof(query_buffer) - 1,
+ "SET GLOBAL net_buffer_length = %s, "
+ "max_allowed_packet = %s", row[0], row[1]);
+ DIE_UNLESS((size_t) rc <= sizeof(query_buffer));
+
+ mysql_free_result(res);
+
+ rc= mysql_query(mysql, "SET GLOBAL net_buffer_length = 1024, "
+ "max_allowed_packet = 1024;");
+ myquery(rc);
+
+ /* New connection to test bug. */
+
+ con= mysql_init(NULL);
+ DIE_UNLESS(con);
+
+ con= mysql_real_connect(con, opt_host, opt_user, opt_password, "test",
+ opt_port, opt_unix_socket, 0);
+ DIE_UNLESS(con);
+
+ net_clear(&con->net);
+
+ /* Packet length and number. */
+ int3store(packet, 4096);
+ packet[3]= (char) con->net.pkt_nr++;
+
+ DIE_UNLESS(!net_real_write(&con->net, packet, NET_HEADER_SIZE));
+
+ /* A error is now expected. */
+ DIE_UNLESS(mysql_read_query_result(con));
+ /* ER_NET_PACKET_TOO_LARGE = 1153 */
+ DIE_UNLESS(mysql_errno(con) == 1153);
+
+ mysql_close(con);
+
+ /* Restore original values. */
+ rc= mysql_query(mysql, query_buffer);
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
+#endif
+
/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -16525,6 +16599,9 @@ static struct my_tests_st my_tests[]= {
{ "test_bug31669", test_bug31669 },
{ "test_bug32265", test_bug32265 },
{ "test_bug53371", test_bug53371 },
+#ifndef EMBEDDED_LIBRARY
+ { "test_bug50974", test_bug50974 },
+#endif
{ 0, 0 }
};