List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:April 20 2010 12:42am
Subject:bzr commit into mysql-5.0-bugteam branch (davi:2858) Bug#50974
View as plain text  
# At a local mysql-5.0-bugteam repository of davi

 2858 Davi Arnaut	2010-04-19
      Bug#50974: Server keeps receiving big (> max_allowed_packet) packets indefinitely.
      
      The server could be tricked to read packets indefinitely if it
      received a packet larger than the maximum size of one packet.
      This problem is aggravated by the fact that it can be triggered
      before authentication.
      
      The solution is to skip at least twice the maximum packet size.
      If the packet (or following packets) are larger then twice the
      maximum size, a error is returned and the connection is closed.
      Skipping is only performed for authenticated users.
     @ include/mysql_com.h
        Add skip factor. Only used in server builds.
     @ sql/net_serv.cc
        Control the amount of data that can be skipped.
        Similar behavior for client and server.
     @ tests/mysql_client_test.c
        Add test case.

    modified:
      include/mysql_com.h
      sql/net_serv.cc
      sql/sql_parse.cc
      tests/mysql_client_test.c
=== modified file 'include/mysql_com.h'
--- a/include/mysql_com.h	2007-12-13 10:53:24 +0000
+++ b/include/mysql_com.h	2010-04-20 00:42:25 +0000
@@ -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)

=== modified file 'sql/net_serv.cc'
--- a/sql/net_serv.cc	2009-07-28 18:35:55 +0000
+++ b/sql/net_serv.cc	2010-04-20 00:42:25 +0000
@@ -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 */
   {
@@ -725,6 +728,21 @@ static my_bool net_safe_read(NET *net, c
   return 0;
 }
 
+
+/*
+  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.
 
@@ -744,6 +762,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));
 
@@ -759,6 +778,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);
@@ -769,9 +794,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);

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-02-25 14:57:15 +0000
+++ b/sql/sql_parse.cc	2010-04-20 00:42:25 +0000
@@ -493,6 +493,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);
     }

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2009-08-08 02:32:01 +0000
+++ b/tests/mysql_client_test.c	2010-04-20 00:42:25 +0000
@@ -16679,6 +16679,80 @@ static void test_bug45010()
 }
 
 
+/**
+  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_IF(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
 */
@@ -16982,6 +17056,9 @@ static struct my_tests_st my_tests[]= {
   { "test_bug41078", test_bug41078 },
   { "test_bug20023", test_bug20023 },
   { "test_bug45010", test_bug45010 },
+#ifndef EMBEDDED_LIBRARY
+  { "test_bug50974", test_bug50974 },
+#endif
   { 0, 0 }
 };
 


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20100420004225-pndny22npdqyq2r2.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (davi:2858) Bug#50974Davi Arnaut20 Apr
  • Re: bzr commit into mysql-5.0-bugteam branch (davi:2858) Bug#50974Konstantin Osipov20 Apr
Re: bzr commit into mysql-5.0-bugteam branch (davi:2858) Bug#50974Konstantin Osipov29 Apr