List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:February 1 2011 3:36pm
Subject:bzr commit into mysql-5.5 branch (alexander.barkov:3294)
View as plain text  
#At file:///home/bar/mysql-bzr/mysql-5.5.b58036/ based on revid:ole.john.aske@stripped

 3294 Alexander Barkov	2011-02-01
      Problem: ucs2 was correctly disallowed in "SET NAMES" only,
      while mysql_real_connect() and mysql_change_user() still allowed
      to use ucs2, which made server crash.
      
      Fix: disallow ucs2 in mysql_real_connect() and mysql_change_user().
      
        @ sql/sql_parse.h
          - introducing a new function, to reuse in all places where we need
            to check client character set.
      
        @ sql/set_var.cc
          Using the new function.
      
        @ sql/sql_connect.h
        @ sql/sql_connect.cc
          - changing return type for thd_init_client_charset() to bool,
            to return errors to the caller
          - in case of unsupported client character set - send error and return true
          - in case of success - return false
      
        @ sql/sql_acl.cc
         - return error if thd_init_client_charset() failes
         - in parse_com_change_user_packet() set user_name to NULL in the very
           beginnig to avoid my_free() on bad memory in case of errors.
      
        @ tests/mysql_client_test.c
          Adding test

    modified:
      sql/set_var.cc
      sql/sql_acl.cc
      sql/sql_connect.cc
      sql/sql_connect.h
      sql/sql_parse.h
      tests/mysql_client_test.c
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2010-12-29 00:26:31 +0000
+++ b/sql/set_var.cc	2011-02-01 15:30:06 +0000
@@ -776,7 +776,7 @@ int set_var_password::update(THD *thd)
 int set_var_collation_client::check(THD *thd)
 {
   /* Currently, UCS-2 cannot be used as a client character set */
-  if (character_set_client->mbminlen > 1)
+  if (!charset_is_good_for_parser(character_set_client))
   {
     my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
              character_set_client->csname);

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2011-01-14 15:48:11 +0000
+++ b/sql/sql_acl.cc	2011-02-01 15:30:06 +0000
@@ -7799,7 +7799,8 @@ public:
   Thd_charset_adapter(THD *thd_arg) : thd (thd_arg) {} 
   bool init_client_charset(uint cs_number)
   {
-    thd_init_client_charset(thd, cs_number);
+    if (thd_init_client_charset(thd, cs_number))
+      return true;
     thd->update_charset();
     return thd->is_error();
   }
@@ -8236,6 +8237,18 @@ static bool parse_com_change_user_packet
   uint dummy_errors;
 
   DBUG_ENTER ("parse_com_change_user_packet");
+
+  /*
+    The caller expects that this function allocates user_name using
+    my_strndup() and calls my_free(user_name) later in some cases.
+
+    Let's set user_name to NULL here, to avoid my_free() on uninitialized
+    memory for those cases when we return from here *before* user_name is
+    actually allocated. This happens on errors: packet error, bad charset.
+  */
+  mpvio->auth_info.user_name= NULL;
+  mpvio->auth_info.user_name_length= 0;
+
   if (passwd >= end)
   {
     my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));

=== modified file 'sql/sql_connect.cc'
--- a/sql/sql_connect.cc	2010-12-15 22:59:21 +0000
+++ b/sql/sql_connect.cc	2011-02-01 15:30:06 +0000
@@ -370,8 +370,23 @@ void reset_mqh(LEX_USER *lu, bool get_th
 }
 
 
-void thd_init_client_charset(THD *thd, uint cs_number)
+/**
+  Set thread character set variables from the given ID
+
+  @param  thd         thread handle
+  @param  cs_number   character set and collation ID
+
+  @retval  0  OK; character_set_client, collation_connection and
+              character_set_results are set to the new value,
+              or to the default global values.
+
+  @retval  1  error, e.g. the given ID is not supported by parser.
+              Corresponding SQL error is sent.
+*/
+
+bool thd_init_client_charset(THD *thd, uint cs_number)
 {
+  CHARSET_INFO *cs;
   /*
    Use server character set and collation if
    - opt_character_set_client_handshake is not set
@@ -380,10 +395,10 @@ void thd_init_client_charset(THD *thd, u
    - client character set doesn't exists in server
   */
   if (!opt_character_set_client_handshake ||
-      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
+      !(cs= get_charset(cs_number, MYF(0))) ||
       !my_strcasecmp(&my_charset_latin1,
                      global_system_variables.character_set_client->name,
-                     thd->variables.character_set_client->name))
+                     cs->name))
   {
     thd->variables.character_set_client=
       global_system_variables.character_set_client;
@@ -394,10 +409,18 @@ void thd_init_client_charset(THD *thd, u
   }
   else
   {
+    if (!charset_is_good_for_parser(cs))
+    {
+      /* Disallow non-supported parser character sets: UCS2, UTF16, UTF32 */
+      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
+               cs->csname);
+      return true;
+    }    
     thd->variables.character_set_results=
       thd->variables.collation_connection= 
-      thd->variables.character_set_client;
+      thd->variables.character_set_client= cs;
   }
+  return false;
 }
 
 

=== modified file 'sql/sql_connect.h'
--- a/sql/sql_connect.h	2010-09-20 14:17:32 +0000
+++ b/sql/sql_connect.h	2011-02-01 15:30:06 +0000
@@ -33,7 +33,7 @@ void reset_mqh(LEX_USER *lu, bool get_th
 bool check_mqh(THD *thd, uint check_command);
 void time_out_user_resource_limits(THD *thd, USER_CONN *uc);
 void decrease_user_connections(USER_CONN *uc);
-void thd_init_client_charset(THD *thd, uint cs_number);
+bool thd_init_client_charset(THD *thd, uint cs_number);
 bool setup_connection_thread_globals(THD *thd);
 
 int check_user(THD *thd, enum enum_server_command command,

=== modified file 'sql/sql_parse.h'
--- a/sql/sql_parse.h	2010-08-31 09:59:51 +0000
+++ b/sql/sql_parse.h	2011-02-01 15:30:06 +0000
@@ -197,4 +197,8 @@ check_table_access(THD *thd, ulong requi
 
 bool check_global_access(THD *thd, ulong want_access);
 
+inline bool charset_is_good_for_parser(CHARSET_INFO *cs)
+{ return test(cs->mbminlen == 1); }
+
+
 #endif /* SQL_PARSE_INCLUDED */

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2010-12-29 00:26:31 +0000
+++ b/tests/mysql_client_test.c	2011-02-01 15:30:06 +0000
@@ -19289,6 +19289,72 @@ static void test_bug47485()
 
 
 /*
+  Bug#58036 client utf32, utf16, ucs2 should be disallowed, they crash server
+*/
+static void test_bug58036()
+{
+  MYSQL *conn;
+  DBUG_ENTER("test_bug47485");
+  myheader("test_bug58036");
+
+  /* Part1: try to connect with ucs2 client character set */
+  conn= mysql_client_init(NULL);
+  mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2");
+  if (mysql_real_connect(conn, opt_host, opt_user,
+                         opt_password,  opt_db ? opt_db : "test",
+                         opt_port, opt_unix_socket, 0))
+  {
+    if (!opt_silent)
+      printf("mysql_real_connect() succeeded (failure expected)\n");
+    mysql_close(conn);
+    DIE();
+  }
+
+  if (!opt_silent)
+    printf("Got mysql_real_connect() error (expected): %s (%d)\n",
+           mysql_error(conn), mysql_errno(conn));  
+  DIE_UNLESS(mysql_errno(conn) == ER_WRONG_VALUE_FOR_VAR);
+  mysql_close(conn);
+
+
+  /*
+    Part2:
+    - connect with latin1
+    - then change client character set to ucs2
+    - then try mysql_change_user()
+  */
+  conn= mysql_client_init(NULL);
+  mysql_options(conn, MYSQL_SET_CHARSET_NAME, "latin1");
+  if (!mysql_real_connect(conn, opt_host, opt_user,
+                         opt_password, opt_db ? opt_db : "test",
+                         opt_port, opt_unix_socket, 0))
+  {
+    if (!opt_silent)
+      printf("mysql_real_connect() failed: %s (%d)\n",
+             mysql_error(conn), mysql_errno(conn));
+    mysql_close(conn);
+    DIE();
+  }
+
+  mysql_options(conn, MYSQL_SET_CHARSET_NAME, "ucs2");
+  if (!mysql_change_user(conn, opt_user, opt_password, NULL))
+  {
+    if (!opt_silent)
+      printf("mysql_change_user() succedded, error expected!");
+    mysql_close(conn);
+    DIE();
+  }
+
+  if (!opt_silent)
+    printf("Got mysql_change_user() error (expected): %s (%d)\n",
+           mysql_error(conn), mysql_errno(conn));
+  mysql_close(conn);
+
+  DBUG_VOID_RETURN;
+}
+
+
+/*
   Bug#49972: Crash in prepared statements.
 
   The following case lead to a server crash:
@@ -19770,6 +19836,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug42373", test_bug42373 },
   { "test_bug54041", test_bug54041 },
   { "test_bug47485", test_bug47485 },
+  { "test_bug58036", test_bug58036 },
   { "test_bug57058", test_bug57058 },
   { 0, 0 }
 };


Attachment: [text/bzr-bundle] bzr/alexander.barkov@oracle.com-20110201153006-4sxsbzs7ru8vya8p.bundle
Thread
bzr commit into mysql-5.5 branch (alexander.barkov:3294) Alexander Barkov1 Feb
  • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Sergey Vojtovich4 Feb
    • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Alexander Barkov4 Feb
      • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Alexander Barkov4 Feb
      • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Sergey Vojtovich4 Feb
        • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Alexander Barkov4 Feb
          • Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Sergey Vojtovich4 Feb
Re: bzr commit into mysql-5.5 branch (alexander.barkov:3294)Alexander Barkov10 Feb