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 }
 };
 
openSUSE Build Service is sponsored by