Sophie

Sophie

distrib > Mandriva > current > i586 > media > contrib-release-src > by-pkgid > 720f0ad389e4d8a64778a620389844c1 > files > 8

mysql-cluster-7.1.3-1mdv2010.1.src.rpm

diff -Naurp mysql-cluster-gpl-7.1.3/mysql-test/r/grant.result mysql-cluster-gpl-7.1.3.oden/mysql-test/r/grant.result
--- mysql-cluster-gpl-7.1.3/mysql-test/r/grant.result	2010-03-29 17:16:04.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/mysql-test/r/grant.result	2010-05-26 13:59:02.080363027 +0200
@@ -1413,3 +1413,19 @@ DROP USER 'user1';
 DROP USER 'user1'@'localhost';
 DROP USER 'user2';
 DROP DATABASE db1;
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+GRANT SELECT ON db1.* to 'testbug'@localhost;
+USE db2;
+CREATE TABLE t1 (a INT);
+USE test;
+SELECT * FROM `../db2/tb2`;
+ERROR 42S02: Table 'db1.../db2/tb2' doesn't exist
+SELECT * FROM `../db2`.tb2;
+ERROR 42000: SELECT command denied to user 'testbug'@'localhost' for table 'tb2'
+SELECT * FROM `#mysql50#/../db2/tb2`;
+ERROR 42S02: Table 'db1.#mysql50#/../db2/tb2' doesn't exist
+DROP USER 'testbug'@localhost;
+DROP TABLE db2.t1;
+DROP DATABASE db1;
+DROP DATABASE db2;
diff -Naurp mysql-cluster-gpl-7.1.3/mysql-test/t/grant.test mysql-cluster-gpl-7.1.3.oden/mysql-test/t/grant.test
--- mysql-cluster-gpl-7.1.3/mysql-test/t/grant.test	2010-03-29 17:15:35.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/mysql-test/t/grant.test	2010-05-26 13:59:02.080363027 +0200
@@ -1525,5 +1525,30 @@ DROP USER 'user1'@'localhost';
 DROP USER 'user2';
 DROP DATABASE db1;
 
+
+#
+# Bug #53371: COM_FIELD_LIST can be abused to bypass table level grants.
+#
+
+CREATE DATABASE db1;
+CREATE DATABASE db2;
+GRANT SELECT ON db1.* to 'testbug'@localhost;
+USE db2;
+CREATE TABLE t1 (a INT);
+USE test;
+connect (con1,localhost,testbug,,db1);
+--error ER_NO_SUCH_TABLE
+SELECT * FROM `../db2/tb2`;
+--error ER_TABLEACCESS_DENIED_ERROR
+SELECT * FROM `../db2`.tb2;
+--error ER_NO_SUCH_TABLE
+SELECT * FROM `#mysql50#/../db2/tb2`;
+connection default;
+disconnect con1;
+DROP USER 'testbug'@localhost;
+DROP TABLE db2.t1;
+DROP DATABASE db1;
+DROP DATABASE db2;
+
 # Wait till we reached the initial number of concurrent sessions
 --source include/wait_until_count_sessions.inc
diff -Naurp mysql-cluster-gpl-7.1.3/sql/mysql_priv.h mysql-cluster-gpl-7.1.3.oden/sql/mysql_priv.h
--- mysql-cluster-gpl-7.1.3/sql/mysql_priv.h	2010-03-29 16:51:25.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/mysql_priv.h	2010-05-26 13:59:02.081362954 +0200
@@ -2302,7 +2302,7 @@ void update_create_info_from_table(HA_CR
 int rename_file_ext(const char * from,const char * to,const char * ext);
 bool check_db_name(LEX_STRING *db);
 bool check_column_name(const char *name);
-bool check_table_name(const char *name, uint length);
+bool check_table_name(const char *name, uint length, bool check_for_path_chars);
 char *get_field(MEM_ROOT *mem, Field *field);
 bool get_field(MEM_ROOT *mem, Field *field, class String *res);
 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
diff -Naurp mysql-cluster-gpl-7.1.3/sql/partition_info.cc mysql-cluster-gpl-7.1.3.oden/sql/partition_info.cc
--- mysql-cluster-gpl-7.1.3/sql/partition_info.cc	2010-03-29 16:51:26.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/partition_info.cc	2010-05-26 13:59:02.081362954 +0200
@@ -975,7 +975,7 @@ bool partition_info::check_partition_inf
           part_elem->engine_type= default_engine_type;
         }
         if (check_table_name(part_elem->partition_name,
-                             strlen(part_elem->partition_name)))
+                             strlen(part_elem->partition_name), FALSE))
         {
           my_error(ER_WRONG_PARTITION_NAME, MYF(0));
           goto end;
@@ -993,7 +993,7 @@ bool partition_info::check_partition_inf
         {
           sub_elem= sub_it++;
           if (check_table_name(sub_elem->partition_name,
-                               strlen(sub_elem->partition_name)))
+                               strlen(sub_elem->partition_name), FALSE))
           {
             my_error(ER_WRONG_PARTITION_NAME, MYF(0));
             goto end;
diff -Naurp mysql-cluster-gpl-7.1.3/sql/sql_parse.cc mysql-cluster-gpl-7.1.3.oden/sql/sql_parse.cc
--- mysql-cluster-gpl-7.1.3/sql/sql_parse.cc	2010-05-26 13:58:41.925237887 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/sql_parse.cc	2010-05-26 13:59:02.083362658 +0200
@@ -1313,6 +1313,13 @@ bool dispatch_command(enum enum_server_c
     }
     thd->convert_string(&conv_name, system_charset_info,
 			packet, arg_length, thd->charset());
+    if (check_table_name(conv_name.str, conv_name.length, FALSE))
+    {
+      /* this is OK due to convert_string() null-terminating the string */
+      my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str);
+      break;
+    }
+
     table_list.alias= table_list.table_name= conv_name.str;
     packet= arg_end + 1;
 
@@ -6242,7 +6249,7 @@ TABLE_LIST *st_select_lex::add_table_to_
     DBUG_RETURN(0);				// End of memory
   alias_str= alias ? alias->str : table->table.str;
   if (!test(table_options & TL_OPTION_ALIAS) && 
-      check_table_name(table->table.str, table->table.length))
+      check_table_name(table->table.str, table->table.length, FALSE))
   {
     my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
     DBUG_RETURN(0);
diff -Naurp mysql-cluster-gpl-7.1.3/sql/sql_table.cc mysql-cluster-gpl-7.1.3.oden/sql/sql_table.cc
--- mysql-cluster-gpl-7.1.3/sql/sql_table.cc	2010-05-26 13:58:41.920237806 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/sql_table.cc	2010-05-26 13:59:02.084362632 +0200
@@ -437,7 +437,21 @@ uint tablename_to_filename(const char *f
   DBUG_PRINT("enter", ("from '%s'", from));
 
   if ((length= check_n_cut_mysql50_prefix(from, to, to_length)))
+  {
+    /*
+      Check if the name supplied is a valid mysql 5.0 name and 
+      make the name a zero length string if it's not.
+      Note that just returning zero length is not enough : 
+      a lot of places don't check the return value and expect 
+      a zero terminated string.
+    */  
+    if (check_table_name(to, length, TRUE))
+    {
+      to[0]= 0;
+      length= 0;
+    }
     DBUG_RETURN(length);
+  }
   length= strconvert(system_charset_info, from,
                      &my_charset_filename, to, to_length, &errors);
   if (check_if_legal_tablename(to) &&
diff -Naurp mysql-cluster-gpl-7.1.3/sql/sql_yacc.yy mysql-cluster-gpl-7.1.3.oden/sql/sql_yacc.yy
--- mysql-cluster-gpl-7.1.3/sql/sql_yacc.yy	2010-03-29 16:51:29.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/sql_yacc.yy	2010-05-26 13:59:02.086425672 +0200
@@ -6278,7 +6278,7 @@ alter_list_item:
             {
               MYSQL_YYABORT;
             }
-            if (check_table_name($3->table.str,$3->table.length) ||
+            if (check_table_name($3->table.str,$3->table.length, FALSE) ||
                 ($3->db.str && check_db_name(&$3->db)))
             {
               my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
diff -Naurp mysql-cluster-gpl-7.1.3/sql/table.cc mysql-cluster-gpl-7.1.3.oden/sql/table.cc
--- mysql-cluster-gpl-7.1.3/sql/table.cc	2010-03-29 16:51:29.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/sql/table.cc	2010-05-26 13:59:02.087425625 +0200
@@ -499,6 +499,26 @@ inline bool is_system_table_name(const c
 }
 
 
+/**
+  Check if a string contains path elements
+*/  
+
+static inline bool has_disabled_path_chars(const char *str)
+{
+  for (; *str; str++)
+    switch (*str)
+    {
+      case FN_EXTCHAR:
+      case '/':
+      case '\\':
+      case '~':
+      case '@':
+        return TRUE;
+    }
+  return FALSE;
+}
+
+
 /*
   Read table definition from a binary / text based .frm file
   
@@ -554,7 +574,8 @@ int open_table_def(THD *thd, TABLE_SHARE
         This kind of tables must have been opened only by the
         my_open() above.
     */
-    if (strchr(share->table_name.str, '@') ||
+    if (has_disabled_path_chars(share->table_name.str) ||
+        has_disabled_path_chars(share->db.str) ||
         !strncmp(share->db.str, MYSQL50_TABLE_NAME_PREFIX,
                  MYSQL50_TABLE_NAME_PREFIX_LENGTH) ||
         !strncmp(share->table_name.str, MYSQL50_TABLE_NAME_PREFIX,
@@ -2771,7 +2792,6 @@ bool check_db_name(LEX_STRING *org_name)
             (name_length > NAME_CHAR_LEN)); /* purecov: inspected */
 }
 
-
 /*
   Allow anything as a table name, as long as it doesn't contain an
   ' ' at the end
@@ -2779,7 +2799,7 @@ bool check_db_name(LEX_STRING *org_name)
 */
 
 
-bool check_table_name(const char *name, uint length)
+bool check_table_name(const char *name, uint length, bool check_for_path_chars)
 {
   uint name_length= 0;  // name length in symbols
   const char *end= name+length;
@@ -2806,6 +2826,9 @@ bool check_table_name(const char *name,
         continue;
       }
     }
+    if (check_for_path_chars &&
+        (*name == '/' || *name == '\\' || *name == '~' || *name == FN_EXTCHAR))
+      return 1;
 #endif
     name++;
     name_length++;
diff -Naurp mysql-cluster-gpl-7.1.3/tests/mysql_client_test.c mysql-cluster-gpl-7.1.3.oden/tests/mysql_client_test.c
--- mysql-cluster-gpl-7.1.3/tests/mysql_client_test.c	2010-03-29 16:52:14.000000000 +0200
+++ mysql-cluster-gpl-7.1.3.oden/tests/mysql_client_test.c	2010-05-26 13:59:02.089425553 +0200
@@ -18052,6 +18052,50 @@ static void test_bug44495()
   DBUG_VOID_RETURN;
 }
 
+static void test_bug53371()
+{
+  int rc;
+  MYSQL_RES *result;
+
+  myheader("test_bug53371");
+
+  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP DATABASE IF EXISTS bug53371");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP USER 'testbug'@localhost");
+
+  rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)");
+  myquery(rc);
+  rc= mysql_query(mysql, "CREATE DATABASE bug53371");
+  myquery(rc);
+  rc= mysql_query(mysql, "GRANT SELECT ON bug53371.* to 'testbug'@localhost");
+  myquery(rc);
+
+  rc= mysql_change_user(mysql, "testbug", NULL, "bug53371");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "SHOW COLUMNS FROM client_test_db.t1");
+  DIE_UNLESS(rc);
+  DIE_UNLESS(mysql_errno(mysql) == 1142);
+
+  result= mysql_list_fields(mysql, "../client_test_db/t1", NULL);
+  DIE_IF(result);
+
+  result= mysql_list_fields(mysql, "#mysql50#/../client_test_db/t1", NULL);
+  DIE_IF(result);
+
+  rc= mysql_change_user(mysql, opt_user, opt_password, current_db);
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP TABLE t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP DATABASE bug53371");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP USER 'testbug'@localhost");
+  myquery(rc);
+}
+
+
 /*
   Read and parse arguments and MySQL options from my.cnf
 */
@@ -18361,6 +18405,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug30472", test_bug30472 },
   { "test_bug20023", test_bug20023 },
   { "test_bug45010", test_bug45010 },
+  { "test_bug53371", test_bug53371 },
   { "test_bug31418", test_bug31418 },
   { "test_bug31669", test_bug31669 },
   { "test_bug28386", test_bug28386 },