List:Commits« Previous MessageNext Message »
From:<damien Date:March 8 2007 11:22pm
Subject:bk commit into 5.1 tree (Damien:1.2466) BUG#26346
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of . When  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-03-08 17:24:36-05:00, Damien@damiendev. +1 -0
  bug#26346 stack + buffer overrun in mysqldump

  client/mysqldump.c@stripped, 2007-03-08 17:22:32-05:00, Damien@damiendev. +117 -47
    a patch in progress

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	Damien
# Host:	damiendev.
# Root:	C:/build/dev

--- 1.268/client/mysqldump.c	2007-02-23 06:23:36 -05:00
+++ 1.269/client/mysqldump.c	2007-03-08 17:22:32 -05:00
@@ -77,13 +77,13 @@
 #define IGNORE_DATA 0x01 /* don't dump data for this table */
 #define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */
 
-static char *add_load_option(char *ptr, const char *object,
+static char *add_load_option(char *ptr, char *ptr_end, const char *object,
                              const char *statement);
 static ulong find_set(TYPELIB *lib, const char *x, uint length,
                       char **err_pos, uint *err_len);
 static char *alloc_query_str(ulong size);
 
-static char *field_escape(char *to,const char *from,uint length);
+static char *field_escape(char *to,char *to_end,const char *from,uint length);
 static my_bool  verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
                 quick= 1, extended_insert= 1,
                 lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
@@ -894,6 +894,41 @@
   DBUG_VOID_RETURN;
 } /* DB_error */
 
+/*
+** CheckBuffer -- prints mysql error message and exits the program.
+*/
+
+static void check_buffer_len(uint length_available, uint length_to_write)
+{
+  DBUG_ENTER("check_buffer_len");
+  if (length_available < length_to_write) {
+    fprintf(stderr, "Error: Input arguments too long\n");
+    fflush(stderr);    
+    ignore_errors= 0; /* Fatal error */
+    safe_exit(EX_USAGE);
+  }
+  DBUG_VOID_RETURN;
+}
+
+static void check_buffer_len2(const char* buffer_in_start, const char* buffer_end, uint
length_to_write)
+{
+  check_buffer_len(buffer_end - buffer_in_start, length_to_write);
+}
+
+/*
+  Copies the in_str string to buffer_out_start, with null terminator.
+  Returns a pointer the null terminator.
+*/
+static char* copy_str_checked(char* buffer_out_start, char* buffer_out_end, const char*
in_str)
+{
+  uint in_len = strlen(in_str);
+
+  check_buffer_len2(buffer_out_start, buffer_out_end, in_len + 1);
+
+  memcpy(buffer_out_start, in_str, in_len + 1); // copy null terminator too
+
+  return buffer_out_start + in_len;
+}
 
 /*
   Sends a query to server, optionally reads result, prints error message if
@@ -2256,20 +2291,27 @@
   DBUG_VOID_RETURN;
 }
 
-static char *add_load_option(char *ptr,const char *object,
+static char *add_load_option(char *ptr, char* ptr_end, const char *object,
                              const char *statement)
 {
   if (object)
   {
     /* Don't escape hex constants */
     if (object[0] == '0' && (object[1] == 'x' || object[1] == 'X'))
-      ptr= strxmov(ptr," ",statement," ",object,NullS);
+    {
+      ptr= copy_str_checked(ptr, ptr_end, " " );
+      ptr= copy_str_checked(ptr, ptr_end, statement );
+      ptr= copy_str_checked(ptr, ptr_end, " " );
+      ptr= copy_str_checked(ptr, ptr_end, object );
+    }
     else
     {
       /* char constant; escape */
-      ptr= strxmov(ptr," ",statement," '",NullS);
-      ptr= field_escape(ptr,object,(uint) strlen(object));
-      *ptr++= '\'';
+      ptr= copy_str_checked(ptr, ptr_end, " " );
+      ptr= copy_str_checked(ptr, ptr_end, statement );
+      ptr= copy_str_checked(ptr, ptr_end, " '" );
+      ptr= field_escape(ptr, ptr_end, object,(uint) strlen(object));
+      ptr= copy_str_checked(ptr, ptr_end, "'" );
     }
   }
   return ptr;
@@ -2283,26 +2325,33 @@
   syntax errors from the SQL parser.
 */
 
-static char *field_escape(char *to,const char *from,uint length)
+static char *field_escape(char *to,char *to_end, const char *from,uint length)
 {
   const char *end;
   uint end_backslashes=0;
 
   for (end= from+length; from != end; from++)
   {
+    check_buffer_len2(to, to_end, 1);
     *to++= *from;
+
     if (*from == '\\')
       end_backslashes^=1;    /* find odd number of backslashes */
     else
     {
-      if (*from == '\'' && !end_backslashes)
-        *to++= *from;      /* We want a duplicate of "'" for MySQL */
+      if (*from == '\'' && !end_backslashes) {
+          check_buffer_len2(to, to_end, 1);
+         *to++= *from;      /* We want a duplicate of "'" for MySQL */
+      }
       end_backslashes=0;
     }
   }
   /* Add missing backslashes if user has specified odd number of backs.*/
-  if (end_backslashes)
+  if (end_backslashes) {
+    check_buffer_len2(to, to_end, 1);
     *to++= '\\';
+  }
+  
   return to;
 } /* field_escape */
 
@@ -2338,7 +2387,7 @@
 static void dump_table(char *table, char *db)
 {
   char ignore_flag;
-  char query_buf[QUERY_LENGTH], *end, buff[256],table_buff[NAME_LEN+3];
+  char query_buf[QUERY_LENGTH], *insert_next, *insert_end, table_buff[NAME_LEN+3];
   char table_type[NAME_LEN];
   char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
   char *query= query_buf;
@@ -2395,44 +2444,59 @@
   opt_quoted_table= quote_name(table, table_buff2, 0);
 
   verbose_msg("-- Sending SELECT query...\n");
+
+#define WHERE_PHRASE  " WHERE "
+#define ORDER_BY_PHRASE  " ORDER BY "
+
   if (path)
   {
     char filename[FN_REFLEN], tmp_path[FN_REFLEN];
+    
+    check_buffer_len(FN_REFLEN, strlen(path) + 1);
+
     convert_dirname(tmp_path,path,NullS);
     my_load_path(tmp_path, tmp_path, NULL);
     fn_format(filename, table, tmp_path, ".txt", 4);
     my_delete(filename, MYF(0)); /* 'INTO OUTFILE' doesn't work, if
                                     filename wasn't deleted */
     to_unix_path(filename);
-    my_snprintf(query, QUERY_LENGTH,
-                "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '%s'",
-                filename);
-    end= strend(query);
-
-    if (fields_terminated || enclosed || opt_enclosed || escaped)
-      end= strmov(end, " FIELDS");
-    end= add_load_option(end, fields_terminated, " TERMINATED BY");
-    end= add_load_option(end, enclosed, " ENCLOSED BY");
-    end= add_load_option(end, opt_enclosed, " OPTIONALLY ENCLOSED BY");
-    end= add_load_option(end, escaped, " ESCAPED BY");
-    end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
-    *end= '\0';
+    
+    insert_next= query;
+    insert_end= query + QUERY_LENGTH;
+
+    insert_next= copy_str_checked(insert_next, insert_end,
+        "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '");
+    insert_next= copy_str_checked(insert_next, insert_end, filename);
+    insert_next= copy_str_checked(insert_next, insert_end, "'");
+
+    if (fields_terminated || enclosed || opt_enclosed || escaped) {
+      insert_next= copy_str_checked(insert_next, insert_end, " FIELDS");
+      insert_next= add_load_option(insert_next, insert_end, fields_terminated, "
TERMINATED BY");
+      insert_next= add_load_option(insert_next, insert_end, enclosed, " ENCLOSED BY");
+      insert_next= add_load_option(insert_next, insert_end, opt_enclosed, " OPTIONALLY
ENCLOSED BY");
+      insert_next= add_load_option(insert_next, insert_end, escaped, " ESCAPED BY");
+      insert_next= add_load_option(insert_next, insert_end, lines_terminated, " LINES
TERMINATED BY");
+    }
+
+    insert_next= copy_str_checked(insert_next, insert_end, " FROM ");
+    insert_next= copy_str_checked(insert_next, insert_end, result_table);
 
-    my_snprintf(buff, sizeof(buff), " FROM %s", result_table);
-    end= strmov(end,buff);
     if (where || order_by)
     {
-      query= alloc_query_str((ulong) ((end - query) + 1 +
-                             (where ? strlen(where) + 7 : 0) +
-                             (order_by ? strlen(order_by) + 10 : 0)));
-      end= strmov(query, query_buf);
+      
+      query = alloc_query_str((ulong) ((insert_next - query) + 1 +
+                             (where ? strlen(where) + sizeof(WHERE_PHRASE) : 0) +
+                             (order_by ? strlen(order_by) + sizeof(ORDER_BY_PHRASE) :
0)));
+
+      insert_next= strmov(query, query_buf);
 
       if (where)
-        end= strxmov(end, " WHERE ", where, NullS);
+        insert_next= strxmov(insert_next, WHERE_PHRASE, where, NullS);
       if (order_by)
-        end= strxmov(end, " ORDER BY ", order_by, NullS);
+        insert_next= strxmov(insert_next, ORDER_BY_PHRASE, order_by, NullS);
     }
-    if (mysql_real_query(mysql, query, (uint) (end - query)))
+
+    if (mysql_real_query(mysql, query, (uint) (insert_next - query)))
     {
       DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
       DBUG_VOID_RETURN;
@@ -2446,15 +2510,21 @@
               result_table);
       check_io(md_result_file);
     }
-    my_snprintf(query, QUERY_LENGTH,
-                "SELECT /*!40001 SQL_NO_CACHE */ * FROM %s",
-                result_table);
+
+    insert_next= query;
+    insert_end= query + QUERY_LENGTH;
+
+    insert_next= copy_str_checked(insert_next, insert_end,
+                "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
+
+    insert_next= copy_str_checked(insert_next, insert_end, result_table);
+
     if (where || order_by)
     {
-      query= alloc_query_str((ulong) (strlen(query) + 1 +
-                             (where ? strlen(where) + 7 : 0) +
-                             (order_by ? strlen(order_by) + 10 : 0)));
-      end= strmov(query, query_buf);
+      query= alloc_query_str((ulong) (insert_next - query + 1 +
+                             (where ? strlen(where) + sizeof(WHERE_PHRASE) : 0) +
+                             (order_by ? strlen(order_by) + sizeof(ORDER_BY_PHRASE) :
0)));
+      insert_next= strmov(query, query_buf);
 
       if (where)
       {
@@ -2463,7 +2533,7 @@
           fprintf(md_result_file, "-- WHERE:  %s\n", where);
           check_io(md_result_file);
         }
-        end= strxmov(end, " WHERE ", where, NullS);
+        insert_next= strxmov(insert_next, WHERE_PHRASE, where, NullS);
       }
       if (order_by)
       {
@@ -2472,7 +2542,7 @@
           fprintf(md_result_file, "-- ORDER BY:  %s\n", order_by);
           check_io(md_result_file);
         }
-        end= strxmov(end, " ORDER BY ", order_by, NullS);
+        insert_next= strxmov(insert_next, ORDER_BY_PHRASE, order_by, NullS);
       }
     }
     if (!opt_xml && !opt_compact)
@@ -2555,10 +2625,10 @@
 
         if (!(field= mysql_fetch_field(res)))
         {
-          my_snprintf(query, QUERY_LENGTH,
+          my_snprintf(query_buf, QUERY_LENGTH,
                       "%s: Not enough fields from table %s! Aborting.\n",
                       my_progname, result_table);
-          fputs(query,stderr);
+          fputs(query_buf,stderr);
           error= EX_CONSCHECK;
           goto err;
         }
@@ -2773,14 +2843,14 @@
     check_io(md_result_file);
     if (mysql_errno(mysql))
     {
-      my_snprintf(query, QUERY_LENGTH,
+      my_snprintf(query_buf, QUERY_LENGTH,
                   "%s: Error %d: %s when dumping table %s at row: %ld\n",
                   my_progname,
                   mysql_errno(mysql),
                   mysql_error(mysql),
                   result_table,
                   rownr);
-      fputs(query,stderr);
+      fputs(query_buf,stderr);
       error= EX_CONSCHECK;
       goto err;
     }

Thread
bk commit into 5.1 tree (Damien:1.2466) BUG#26346damien8 Mar