MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:andrey Date:December 17 2007 4:51pm
Subject:bk commit into 5.1 tree (andrey:1.2647) BUG#29605
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-12-17 17:51:22+01:00, andrey@stripped +6 -0
  Fix for bug#29605 
  (--local-infile=0 checks can be bypassed by sending a FETCH LOCAL FILE response)
  The query sent to the server is checked whether it's a LOAD DATA LOCAL INFILE in case
  the server sends a request to the client to send a local file.

  BitKeeper/etc/ignore@stripped, 2007-12-17 17:51:20+01:00, andrey@stripped +2 -0
    Added tests/mysql_client_test.c.orig libmysqld/lib_sql.cc.orig to the ignore list

  include/mysql.h@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +1 -1
    Add additional parameter to the read_query_result hook.
    It's needed for checking the validity of a LOAD DATA LOCAL INFILE
    response from a server.

  libmysql/libmysql.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +4 -4
    Pass the query to the read_query_result() hook wherever
    appropriate. It's not possible for prepared statements.

  libmysqld/lib_sql.cc@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +15 -7
    emb_read_query_result() was used twice as a hook for
    read_query_result of MYSQL_METHODS. Because of the added second
    parameter to the hook a new function with old's emb_read_query_result()
    signature was added.
    In the embedded server scenario we are sure the server is not fake. Thus
    the response from LOAD DATA LOCAL INFILE is not inspected.

  sql-common/client.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +71 -4
    If the server sends a request to the client
    for sending a file, in case of LOAD DATA LOCAL INFILE,
    the client should check that the query is really that one.
    If not, the server is a fake and tries to steal user-readable
    file from the client.

  tests/mysql_client_test.c@stripped, 2007-12-17 17:51:19+01:00, andrey@stripped +1 -1
    Modify the test to compile with the new definition
    of MYSQL_METHODS

diff -Nrup a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
--- a/BitKeeper/etc/ignore	2007-12-13 12:49:43 +01:00
+++ b/BitKeeper/etc/ignore	2007-12-17 17:51:20 +01:00
@@ -3012,3 +3012,5 @@ win/vs8cache.txt
 ylwrap
 zlib/*.ds?
 zlib/*.vcproj
+tests/mysql_client_test.c.orig
+libmysqld/lib_sql.cc.orig
diff -Nrup a/include/mysql.h b/include/mysql.h
--- a/include/mysql.h	2007-11-26 19:09:34 +01:00
+++ b/include/mysql.h	2007-12-17 17:51:19 +01:00
@@ -752,7 +752,7 @@ enum enum_stmt_attr_type
 
 typedef struct st_mysql_methods
 {
-  my_bool (*read_query_result)(MYSQL *mysql);
+  my_bool (*read_query_result)(MYSQL *mysql, const char *query);
   my_bool (*advanced_command)(MYSQL *mysql,
 			      enum enum_server_command command,
 			      const unsigned char *header,
diff -Nrup a/libmysql/libmysql.c b/libmysql/libmysql.c
--- a/libmysql/libmysql.c	2007-12-12 16:20:53 +01:00
+++ b/libmysql/libmysql.c	2007-12-17 17:51:19 +01:00
@@ -342,7 +342,7 @@ my_bool STDCALL mysql_master_query(MYSQL
   DBUG_ENTER("mysql_master_query");
   if (mysql_master_send_query(mysql, q, length))
     DBUG_RETURN(1);
-  DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
+  DBUG_RETURN((*mysql->methods->read_query_result)(mysql, q));
 }
 
 my_bool STDCALL mysql_master_send_query(MYSQL *mysql, const char *q,
@@ -365,7 +365,7 @@ my_bool STDCALL mysql_slave_query(MYSQL 
   DBUG_ENTER("mysql_slave_query");
   if (mysql_slave_send_query(mysql, q, length))
     DBUG_RETURN(1);
-  DBUG_RETURN((*mysql->methods->read_query_result)(mysql));
+  DBUG_RETURN((*mysql->methods->read_query_result)(mysql, q));
 }
 
 
@@ -2468,7 +2468,7 @@ static my_bool execute(MYSQL_STMT *stmt,
 
   res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
                                  (uchar*) packet, length, 1, NULL) ||
-            (*mysql->methods->read_query_result)(mysql));
+            (*mysql->methods->read_query_result)(mysql, NULL));
   stmt->affected_rows= mysql->affected_rows;
   stmt->server_status= mysql->server_status;
   stmt->insert_id= mysql->insert_id;
@@ -5181,6 +5181,6 @@ MYSQL_RES * STDCALL mysql_use_result(MYS
 
 my_bool STDCALL mysql_read_query_result(MYSQL *mysql)
 {
-  return (*mysql->methods->read_query_result)(mysql);
+  return (*mysql->methods->read_query_result)(mysql, NULL);
 }
 
diff -Nrup a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
--- a/libmysqld/lib_sql.cc	2007-12-14 14:01:09 +01:00
+++ b/libmysqld/lib_sql.cc	2007-12-17 17:51:19 +01:00
@@ -38,7 +38,8 @@ C_MODE_START
 #include <sql_common.h>
 #include "embedded_priv.h"
 
-static my_bool emb_read_query_result(MYSQL *mysql);
+static my_bool emb_read_query_result(MYSQL *mysql, const char *query);
+static my_bool emb_next_result(MYSQL *mysql);
 
 
 /*
@@ -172,7 +173,7 @@ emb_read_rows(MYSQL *mysql, MYSQL_FIELD 
 static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
 {
   MYSQL_DATA *res;
-  if (emb_read_query_result(mysql))
+  if (emb_read_query_result(mysql, NULL))
     return 0;
   res= ((THD*) mysql->thd)->cur_data;
   ((THD*) mysql->thd)->cur_data= 0;
@@ -194,7 +195,7 @@ static my_bool emb_read_prepare_result(M
 
   if (thd->first_data)
   {
-    if (emb_read_query_result(mysql))
+    if (emb_read_query_result(mysql, NULL))
       return 1;
     stmt->field_count= mysql->field_count;
     mysql->status= MYSQL_STATUS_READY;
@@ -227,7 +228,14 @@ static void emb_fetch_lengths(ulong *to,
     *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
 }
 
-static my_bool emb_read_query_result(MYSQL *mysql)
+
+static my_bool emb_next_result(MYSQL *mysql)
+{
+	return emb_read_query_result(mysql, NULL);
+}
+
+
+static my_bool emb_read_query_result(MYSQL *mysql, const char *query)
 {
   THD *thd= (THD*) mysql->thd;
   MYSQL_DATA *res= thd->first_data;
@@ -283,7 +291,7 @@ static int emb_stmt_execute(MYSQL_STMT *
 
   res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
                                  header, sizeof(header), 1, stmt) ||
-            emb_read_query_result(stmt->mysql));
+            emb_read_query_result(stmt->mysql, NULL));
   stmt->affected_rows= stmt->mysql->affected_rows;
   stmt->insert_id= stmt->mysql->insert_id;
   stmt->server_status= stmt->mysql->server_status;
@@ -404,7 +412,7 @@ MYSQL_METHODS embedded_methods= 
   emb_unbuffered_fetch,
   emb_free_embedded_thd,
   emb_read_statistics,
-  emb_read_query_result,
+  emb_next_result,
   emb_read_change_user_result,
   emb_read_rows_from_cursor
 };
@@ -629,7 +637,7 @@ int check_embedded_connection(MYSQL *mys
   sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
   result= check_user(thd, COM_CONNECT, NULL, 0, db, true);
   net_end_statement(thd);
-  emb_read_query_result(mysql);
+  emb_read_query_result(mysql, NULL);
   return result;
 }
 
diff -Nrup a/sql-common/client.c b/sql-common/client.c
--- a/sql-common/client.c	2007-12-12 16:20:56 +01:00
+++ b/sql-common/client.c	2007-12-17 17:51:19 +01:00
@@ -1706,7 +1706,7 @@ static int ssl_verify_server_cert(Vio *v
   before calling mysql_real_connect !
 */
 
-static my_bool cli_read_query_result(MYSQL *mysql);
+static my_bool cli_read_query_result(MYSQL *mysql, const char *query);
 static MYSQL_RES *cli_use_result(MYSQL *mysql);
 
 static MYSQL_METHODS client_methods=
@@ -2688,7 +2688,59 @@ void STDCALL mysql_close(MYSQL *mysql)
 }
 
 
-static my_bool cli_read_query_result(MYSQL *mysql)
+static my_bool is_real_load_data_local(const char *q)
+{
+#define LD_STATE_NORMAL      1
+#define LD_STATE_IN_ML_COM   2
+#define LD_STATE_IN_SL_COM   3
+  int ld_state= LD_STATE_NORMAL;
+  const char *pattern= "LOADDATALOCALINFILE";
+  q--;
+  while (*++q && *pattern) {
+    if (ld_state == LD_STATE_NORMAL)
+    {
+      /*
+        If the current char is not NULL, then the next address
+        will contain either a char or a NULL. Thus, we won't touch
+        memory beyound the string boundaries as the string should be
+        NULL terminated.
+      */
+      if ((*q == '/' && *(q+1) == '*'))
+      {
+        ld_state= LD_STATE_IN_ML_COM;
+        ++q;
+      }
+      else if ((*q == '-' && *(q+1) == '-') || *q == '#')
+      {
+        ld_state = LD_STATE_IN_SL_COM;
+        ++q;
+      }
+      else if (my_charset_latin1.to_upper[(uchar )*q] !=
+               my_charset_latin1.to_lower[(uchar )*q])
+      {
+        if (my_charset_latin1.to_upper[(uchar )*q] != *pattern++)
+          break;
+      }
+    }
+    else
+    {
+      /* \r is not tested as the server doesn't consider it as EOL */
+      if ((ld_state == LD_STATE_IN_ML_COM && *q == '*' && *(q + 1) == '/') ||
+          (ld_state == LD_STATE_IN_SL_COM && *q == '\n'))
+      {
+        ld_state= LD_STATE_NORMAL;
+        ++q;
+      }
+    }
+  }
+  return *pattern == '\0';
+#undef LOAD_DATA_STATE_NORMAL
+#undef LD_STATE_IN_ML_COMMENT
+#undef LD_STATE_IN_SL_COMMENT
+}
+
+
+static my_bool cli_read_query_result(MYSQL *mysql, const char *query)
 {
   uchar *pos;
   ulong field_count;
@@ -2736,7 +2788,22 @@ get_info:
 #ifdef MYSQL_CLIENT
   if (field_count == NULL_LENGTH)		/* LOAD DATA LOCAL INFILE */
   {
-    int error=handle_local_infile(mysql,(char*) pos);
+    int error = 0;
+    if (query && is_real_load_data_local(query) == FALSE)  /* Is the server fake */
+    {
+      /* Send empty packet to mark end of file */
+      if (my_net_write(&mysql->net, (const uchar*) "", 0) || net_flush(&mysql->net))
+      {
+        set_mysql_error(mysql, CR_SERVER_LOST, unknown_sqlstate);
+        DBUG_RETURN(1);
+      }
+      /* Tell the user that something wrong has happened */
+      set_mysql_error(mysql, CR_MALFORMED_PACKET, unknown_sqlstate);
+      error = 1;
+    }
+    else
+      error= handle_local_infile(mysql,(char*) pos);
+
     if ((length= cli_safe_read(mysql)) == packet_error || error)
       DBUG_RETURN(1);
     goto get_info;				/* Get info packet */
@@ -2798,7 +2865,7 @@ mysql_real_query(MYSQL *mysql, const cha
 
   if (mysql_send_query(mysql,query,length))
     DBUG_RETURN(1);
-  DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql));
+  DBUG_RETURN((int) (*mysql->methods->read_query_result)(mysql, query));
 }
 
 
diff -Nrup a/tests/mysql_client_test.c b/tests/mysql_client_test.c
--- a/tests/mysql_client_test.c	2007-12-13 13:43:36 +01:00
+++ b/tests/mysql_client_test.c	2007-12-17 17:51:19 +01:00
@@ -13556,7 +13556,7 @@ static void test_bug9478()
       rc= ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
                                                (uchar*) buff,
                                                sizeof(buff), 0,0,1,NULL) ||
-           (*mysql->methods->read_query_result)(mysql));
+           (*mysql->methods->read_query_result)(mysql, NULL));
       DIE_UNLESS(rc);
       if (!opt_silent && i == 0)
         printf("Got error (as expected): %s\n", mysql_error(mysql));
Thread
bk commit into 5.1 tree (andrey:1.2647) BUG#29605andrey17 Dec