Package: mysql
Version: 3.23.49-8.9
Severity: critical
Tags: security patch woody

Hello

[in copy to [EMAIL PROTECTED]

After the packages in unstable and testing were fixed by uploading
4.0.24-1 and 4.1.10a-1 I took a look at the Woody packages and found
them vulnerable, too.

Sergei Golubchik <[EMAIL PROTECTED]> provided a reference to the 4.0 patch
http://mysql.bkbits.net:8080/mysql-4.0/[EMAIL PROTECTED]
which, with some minor modifications, was applicable to the 3.23 source
tree.

I afterwards verified the three prove of concept examples given by
Stefano and they did at least not work any longer as they did with the
unpatched version.
http://archives.neohapsis.com/archives/vulnwatch/2005-q1/0082.html
http://archives.neohapsis.com/archives/vulnwatch/2005-q1/0083.html
http://archives.neohapsis.com/archives/vulnwatch/2005-q1/0084.html

You can find a proposed upload for stable-security on
http://www.lathspell.de/linux/debian/mysql/woody/

To verify the patches the directory single-patches/ contains the
original patch splitted up to 11 individual files all on their 
original version and after I adjusted the patch.

The concatenation of the p*_new.diff snippets toghether with some
comments and a diff to generate the new changelog entry is in
the directory what-i-applied/. The complete and adjusted patch
was copied to debian/patches/SECURITY__CAN-2005-0709....diff
as reference after I applied it.

For the patches itself I did some minor checks i.e. looked if there are
occurances of O_TRUNC flags or my_create() functions that were not replaced.
But I would sleep better if somebody else would look over it again as I'm
getting tired :)

hope that helps,

-christian-


P.S.: Security Team, Woody's mysql has also another, although very
      minor security problem for which Sean Finney recently backported
      a patch, you might want to take a look at bug #296674 [CAN-2004-0957]

-- System Information:
Debian Release: 3.1
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.10-9-amd64-k8
Locale: LANG=de_DE, LC_CTYPE=de_DE (charmap=ISO-8859-1) (ignored: LC_ALL set to 
de_DE)
#
#  * Stefano Di Paola found the following vulnerabilities:
#    - Remote authenticated users with INSERT and DELETE privileges could
#      execute arbitrary code by using CREATE FUNCTION to access libc calls,
#      as demonstrated byusing strcat, on_exit, and exit. [CAN-2005-0709]
#    - Remote authenticated users with INSERT and DELETE privileges could
#      bypass library path restrictions and execute arbitrary libraries by
#      using INSERT INTO to modify the mysql.func table, which is processed
#      by the udf_init function. [CAN-2005-0710]
#    - Predictable file names were used when creating temporary tables, which
#      allowed local users with CREATE TEMPORARY TABLE privileges to overwrite
#      arbitrary files via a symlink attack. [CAN-2005-0711]
#
# The patch is a backported version of MySQLs original patch for 4.0 which
# was available at: 
# http://mysql.bkbits.net:8080/mysql-4.0/[EMAIL PROTECTED]
#
# The following is a quotation of the upstream patch comments:
#
# >  This is a BitKeeper generated diff -Nru style patch.
# > 
# >  ChangeSet
# >    2005/03/03 19:51:29+01:00 [EMAIL PROTECTED] 
# >    Fixes for bugs reported by Stefano Di Paola ([EMAIL PROTECTED])
# >  
# >  include/my_global.h
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +3 -0
# >    O_NOFOLLOW
# >  
# >  isam/create.c
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +3 -2
# >    create table files with O_EXCL|O_NOFOLLOW
# >  
# >  merge/mrg_create.c
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +1 -1
# >    create table files with O_EXCL|O_NOFOLLOW
# >  
# >  myisam/mi_create.c
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +8 -8
# >    create files of temporary tables with O_EXCL|O_NOFOLLOW
# >  
# >  myisammrg/myrg_create.c
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +1 -1
# >    create table files with O_EXCL|O_NOFOLLOW
# >  
# >  mysys/mf_tempfile.c
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +4 -4
# >    create temporary files with O_EXCL|O_NOFOLLOW
# >  
# >  sql/ha_myisam.cc
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +11 -7
# >    let mi_create know if the table is TEMPORARY
# >  
# >  sql/mysql_priv.h
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +1 -1
# >    --allow_suspicious_udfs
# >  
# >  sql/mysqld.cc
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +9 -2
# >    --allow_suspicious_udfs
# >  
# >  sql/share/english/errmsg.txt
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +1 -1
# >    typo
# >  
# >  sql/sql_udf.cc
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +67 -31
# >    --allow_suspicious_udfs
# >    don't allow xxx() udf without any of xxx_init/deinit/add/reset
# >    check paths when loading from mysql.func
# >  
# >  sql/table.cc
# >    2005/03/03 19:51:26+01:00 [EMAIL PROTECTED] +5 -1
# >    create frm of temporary table with O_EXCL|O_NOFOLLOW
# 
--- a/include/my_global.h       2005-03-17 23:49:22.272318000 +0100
+++ b/include/my_global.h       2005-03-17 23:49:49.135092659 +0100
@@ -395,6 +395,9 @@
 #ifndef O_SHORT_LIVED
 #define O_SHORT_LIVED  0
 #endif
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW      0
+#endif
 
 /* #define USE_RECORD_LOCK     */
 
--- a/isam/create.c     2002-02-14 18:30:15.000000000 +0100
+++ b/isam/create.c     2005-03-17 23:49:51.912655694 +0100
@@ -58,13 +58,14 @@
   base_pos=512;                                        /* Enough for 
N_STATE_INFO */
   bzero((byte*) &share,sizeof(share));
   if ((file = my_create(fn_format(buff,name,"",N_NAME_IEXT,4),0,
-       O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+       O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
     goto err;
   errpos=1;
   VOID(fn_format(buff,name,"",N_NAME_DEXT,2+4));
   if (!(flags & HA_DONT_TOUCH_DATA))
   {
-    if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+    if ((dfile = my_create(buff,0,O_RDWR | O_EXCL | O_NOFOLLOW,
+                           MYF(MY_WME))) < 0)
       goto err;
     errpos=2;
   }
--- a/merge/create.c    2002-02-14 18:30:15.000000000 +0100
+++ b/merge/create.c    2005-03-17 23:49:54.377267964 +0100
@@ -33,7 +33,7 @@
 
   errpos=0;
   if ((file = my_create(fn_format(buff,name,"",MRG_NAME_EXT,4),0,
-       O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+       O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
     goto err;
   errpos=1;
   if (table_names)
--- a/myisam/mi_create.c        2002-02-14 18:30:17.000000000 +0100
+++ b/myisam/mi_create.c        2005-03-18 00:01:52.892241358 +0100
@@ -37,7 +37,7 @@
 {
   register uint i,j;
   File dfile,file;
-  int errpos,save_errno;
+  int errpos,save_errno, create_mode= O_RDWR | O_TRUNC;
   uint fields,length,max_key_length,packed,pointer,
        key_length,info_length,key_segs,options,min_key_length_skipp,
        base_pos,varchar_count,long_varchar_count,varchar_length,
@@ -170,7 +170,10 @@
     min_pack_length+=varchar_length+2*varchar_count;
   }
   if (flags & HA_CREATE_TMP_TABLE)
+  {
     options|= HA_OPTION_TMP_TABLE;
+    create_mode|= O_EXCL | O_NOFOLLOW;
+  }
   if (flags & HA_CREATE_CHECKSUM || (options & HA_OPTION_CHECKSUM))
   {
     options|= HA_OPTION_CHECKSUM;
@@ -468,8 +471,8 @@
   if (! (flags & HA_DONT_TOUCH_DATA))
     share.state.create_time= (long) time((time_t*) 0);
 
-  if ((file = my_create(fn_format(buff,name,"",MI_NAME_IEXT,4),0,
-                       O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+  if ((file = my_create(fn_format(buff,name,"",MI_NAME_IEXT,4),0, create_mode,
+                       MYF(MY_WME))) < 0)
     goto err;
   errpos=1;
   VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4));
@@ -478,7 +481,7 @@
 #ifdef USE_RAID
     if (share.base.raid_type)
     {
-      if ((dfile=my_raid_create(buff,0,O_RDWR | O_TRUNC,
+      if ((dfile=my_raid_create(buff, 0, create_mode,
                                share.base.raid_type,
                                share.base.raid_chunks,
                                share.base.raid_chunksize,
@@ -487,7 +490,7 @@
     }
     else
 #endif
-    if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+    if ((dfile = my_create(buff, 0, create_mode, MYF(MY_WME))) < 0)
       goto err;
 
     errpos=3;
--- a/myisammrg/myrg_create.c   2002-02-14 18:30:18.000000000 +0100
+++ b/myisammrg/myrg_create.c   2005-03-18 00:03:27.279412105 +0100
@@ -33,7 +33,7 @@
 
   errpos=0;
   if ((file = my_create(fn_format(buff,name,"",MYRG_NAME_EXT,4),0,
-       O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+       O_RDWR | O_EXCL | O_NOFOLLOW,MYF(MY_WME))) < 0)
     goto err;
   errpos=1;
   if (table_names)
--- a/mysys/mf_tempfile.c       2002-02-14 18:30:17.000000000 +0100
+++ b/mysys/mf_tempfile.c       2005-03-18 00:03:48.154143325 +0100
@@ -71,7 +71,7 @@
     {
       strmake(to,res,FN_REFLEN-1);
       (*free)(res);
-      file=my_create(to,0, mode, MyFlags);
+      file=my_create(to,0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
     }
     environ=old_env;
   }
@@ -82,7 +82,7 @@
   {
     strmake(to,res,FN_REFLEN-1);
     (*free)(res);
-    file=my_create(to, 0, mode, MyFlags);
+    file=my_create(to, 0, mode | O_EXCL | O_NOFOLLOW, MyFlags);
   }
 #elif defined(HAVE_MKSTEMP)
   {
@@ -143,7 +143,7 @@
       strmake(to,res,FN_REFLEN-1);
       (*free)(res);
       file=my_create(to,0,
-                    (int) (O_RDWR | O_BINARY | O_TRUNC |
+                    (int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
                            O_TEMPORARY | O_SHORT_LIVED),
                     MYF(MY_WME));
 
@@ -186,7 +186,7 @@
       }
       (void) strmov(end_pos,TMP_EXT);
       file=my_create(to,0,
-                    (int) (O_RDWR | O_BINARY | O_TRUNC |
+                    (int) (O_RDWR | O_BINARY | O_TRUNC | O_EXCL | O_NOFOLLOW |
                            O_TEMPORARY | O_SHORT_LIVED),
                     MYF(MY_WME));
     }
--- a/sql/ha_myisam.cc  2002-02-14 18:30:24.000000000 +0100
+++ b/sql/ha_myisam.cc  2005-03-18 00:10:03.435368039 +0100
@@ -931,7 +931,7 @@
                      HA_CREATE_INFO *info)
 {
   int error;
-  uint i,j,recpos,minpos,fieldpos,temp_length,length;
+  uint i,j,recpos,minpos,fieldpos,temp_length,length, create_flags;
   bool found_auto_increment=0;
   enum ha_base_keytype type;
   char buff[FN_REFLEN];
@@ -1096,16 +1096,20 @@
   create_info.raid_chunks=info->raid_chunks ? info->raid_chunks : 
RAID_DEFAULT_CHUNKS;
   create_info.raid_chunksize=info->raid_chunksize ? info->raid_chunksize : 
RAID_DEFAULT_CHUNKSIZE;
 
+  if (info->options & HA_LEX_CREATE_TMP_TABLE)
+    create_flags|= HA_CREATE_TMP_TABLE;
+  if (options & HA_OPTION_PACK_RECORD)
+    create_flags|= HA_PACK_RECORD;
+  if (options & HA_OPTION_CHECKSUM)
+    create_flags|= HA_CREATE_CHECKSUM;
+  if (options & HA_OPTION_DELAY_KEY_WRITE)
+    create_flags|= HA_CREATE_DELAY_KEY_WRITE;
+
   error=mi_create(fn_format(buff,name,"","",2+4+16),
                  form->keys,keydef,
                  (uint) (recinfo_pos-recinfo), recinfo,
                  0, (MI_UNIQUEDEF*) 0,
-                 &create_info,
-                 (((options & HA_OPTION_PACK_RECORD) ? HA_PACK_RECORD : 0) |
-                  ((options & HA_OPTION_CHECKSUM) ? HA_CREATE_CHECKSUM : 0) |
-                  ((options & HA_OPTION_DELAY_KEY_WRITE) ?
-                   HA_CREATE_DELAY_KEY_WRITE : 0)));
-
+                 &create_info, create_flags);
 
   my_free((gptr) recinfo,MYF(0));
   DBUG_RETURN(error);
--- a/sql/mysql_priv.h  2002-02-14 18:30:26.000000000 +0100
+++ b/sql/mysql_priv.h  2005-03-18 00:15:03.379379115 +0100
@@ -525,7 +525,8 @@
                       COND_slave_stopped, COND_slave_start;
 extern pthread_attr_t connection_attrib;
 extern bool opt_endinfo, using_udf_functions, locked_in_memory,
-            opt_using_transactions, use_temp_pool, opt_local_infile;
+            opt_using_transactions, use_temp_pool, opt_local_infile,
+            opt_allow_suspicious_udfs;
 extern char f_fyllchar;
 extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
             ha_read_key_count, ha_read_next_count, ha_read_prev_count,
--- a/sql/mysqld.cc     2002-02-14 18:30:15.000000000 +0100
+++ b/sql/mysqld.cc     2005-03-18 00:25:13.190686788 +0100
@@ -221,7 +221,7 @@
            opt_myisam_log=0,
             opt_large_files=sizeof(my_off_t) > 4;
 bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0,
-     opt_safe_user_create=0;
+     opt_safe_user_create=0, opt_allow_suspicious_udfs;
 FILE *bootstrap_file=0;
 int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice
 extern MASTER_INFO glob_mi;
@@ -2614,11 +2614,13 @@
               OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
               OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
               OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
-              OPT_SLAVE_SKIP_ERRORS, OPT_LOCAL_INFILE
+              OPT_SLAVE_SKIP_ERRORS, OPT_LOCAL_INFILE,
+              OPT_ALLOW_SUSPICIOUS_UDFS
 };
 
 static struct option long_options[] = {
   {"ansi",                  no_argument,       0, 'a'},
+  {"allow-suspicious-udfs", no_argument,       0, (int) 
OPT_ALLOW_SUSPICIOUS_UDFS},
   {"basedir",               required_argument, 0, 'b'},
 #ifdef HAVE_BERKELEY_DB
   {"bdb-home",              required_argument, 0, (int) OPT_BDB_HOME},
@@ -3195,6 +3197,11 @@
   printf("Usage: %s [OPTIONS]\n", my_progname);
   puts("\n\
   --ansi               Use ANSI SQL syntax instead of MySQL syntax\n\
+  --allow-suspicious-udfs\n\
+                        Allows to use UDF's consisting of only one symbol\n\
+                        xxx() without corresponing xxx_init() or 
xxx_deinit().\n\
+                        That also means that one can load any function from\n\
+                        any library, for example exit() from libc.so\n\
   -b, --basedir=path   Path to installation directory. All paths are\n\
                        usually resolved relative to this\n\
   --big-tables         Allow big result sets by saving all temporary sets\n\
--- a/sql/share/english/errmsg.txt      2002-02-14 18:51:40.000000000 +0100
+++ b/sql/share/english/errmsg.txt      2005-03-18 00:26:13.891147821 +0100
@@ -128,7 +128,7 @@
 "No paths allowed for shared library",
 "Function '%-.64s' already exist",
 "Can't open shared library '%-.64s' (errno: %d %-.64s)",
-"Can't find function '%-.64s' in library'",
+"Can't find function '%-.64s' in library",
 "Function '%-.64s' is not defined",
 "Host '%-.64s' is blocked because of many connection errors.  Unblock with 
'mysqladmin flush-hosts'",
 "Host '%-.64s' is not allowed to connect to this MySQL server",
--- a/sql/sql_udf.cc    2002-02-14 18:30:22.000000000 +0100
+++ b/sql/sql_udf.cc    2005-03-18 00:30:05.890689505 +0100
@@ -75,29 +75,49 @@
 static pthread_mutex_t THR_LOCK_udf;
 
 
-static udf_func *add_udf(char *name, Item_result ret, char *dl,
-                        Item_udftype typ);
+static udf_func *add_udf(char *name, Item_result ret,
+                         char *dl, Item_udftype typ);
 static void del_udf(udf_func *udf);
 static void *find_udf_dl(const char *dl);
 
-
-static void init_syms(udf_func *tmp)
+static char *init_syms(udf_func *tmp, char *nm)
 {
-  char nm[MAX_FIELD_NAME+16],*end;
+  char *end;
+
+  if (!((tmp->func= dlsym(tmp->dlhandle, tmp->name))))
+    return tmp->name;
 
-  tmp->func = dlsym(tmp->dlhandle, tmp->name);
   end=strmov(nm,tmp->name);
-  (void) strmov(end,"_init");
-  tmp->func_init = dlsym(tmp->dlhandle, nm);
-  (void) strmov(end,"_deinit");
-  tmp->func_deinit = dlsym(tmp->dlhandle, nm);
+
   if (tmp->type == UDFTYPE_AGGREGATE)
   {
-    (void)strmov( end, "_reset" );
-    tmp->func_reset = dlsym( tmp->dlhandle, nm );
-    (void)strmov( end, "_add" );
-    tmp->func_add = dlsym( tmp->dlhandle, nm );
+    (void)strmov(end, "_reset");
+    if (!((tmp->func_reset= dlsym(tmp->dlhandle, nm))))
+      return nm;
+    (void)strmov(end, "_add");
+    if (!((tmp->func_add= dlsym(tmp->dlhandle, nm))))
+      return nm;
+  }
+
+  (void) strmov(end,"_deinit");
+  tmp->func_deinit= dlsym(tmp->dlhandle, nm);
+
+  (void) strmov(end,"_init");
+  tmp->func_init= dlsym(tmp->dlhandle, nm);
+
+  /*
+    to prefent loading "udf" from, e.g. libc.so
+    let's ensure that at least one auxiliary symbol is defined
+  */
+  if (!tmp->func_init && !tmp->func_deinit && tmp->type != UDFTYPE_AGGREGATE)
+  {
+    if (opt_allow_suspicious_udfs)
+      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), nm);
+    else
+      return nm;
   }
+
+  return 0;
 }
 
 static byte* get_hash_key(const byte *buff,uint *length,
@@ -109,7 +129,7 @@
 }
 
 /*
-** Read all predeclared functions from [EMAIL PROTECTED] and accept all that
+** Read all predeclared functions from mysql.func and accept all that
 ** can be used.
 */
 
@@ -151,7 +171,7 @@
   if (open_tables(new_thd, &tables))
   {
     DBUG_PRINT("error",("Can't open udf table"));
-    sql_print_error("Can't open mysql/func table");
+    sql_print_error("Can't open mysql.func table. Please run the 
mysql_install_db script to create it.");
     close_thread_tables(new_thd);
     delete new_thd;
     DBUG_VOID_RETURN;
@@ -169,10 +189,22 @@
     if (table->fields >= 4)                    // New func table
       udftype=(Item_udftype) table->field[3]->val_int();
 
+    /*
+      Ensure that the .dll doesn't have a path
+      This is done to ensure that only approved dll from the system
+      directories are used (to make this even remotely secure).
+    */
+    if (strchr(dl_name, '/') || strlen(name) > NAME_LEN)
+    {
+      sql_print_error("Invalid row in mysql.func table for function '%.64s'",
+                      name);
+      continue;
+    }
+
     if (!(tmp = add_udf(name,(Item_result) table->field[1]->val_int(),
                        dl_name, udftype)))
     {
-      sql_print_error("Can't alloc memory for udf function: name");
+      sql_print_error("Can't alloc memory for udf function: '%.64s'", name);
       continue;
     }
 
@@ -189,13 +221,15 @@
       new_dl=1;
     }
     tmp->dlhandle = dl;
-    init_syms(tmp);
-    if (!tmp->func)
     {
-      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name);
-      del_udf(tmp);
-      if (new_dl)
-       dlclose(dl);
+      char buf[MAX_FIELD_NAME+16], *missing;
+      if ((missing= init_syms(tmp, buf)))
+      {
+        sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), missing);
+        del_udf(tmp);
+        if (new_dl)
+          dlclose(dl);
+      }
     }
   }
   if (error > 0)
@@ -380,13 +414,15 @@
     new_dl=1;
   }
   udf->dlhandle=dl;
-  init_syms(udf);
-
-  if (udf->func == NULL)
   {
-    net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, udf->name);
-    goto err;
+    char buf[MAX_FIELD_NAME+16], *missing;
+    if ((missing= init_syms(udf, buf)))
+    {
+      net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, missing);
+      goto err;
+    }
   }
+
   udf->name=strdup_root(&mem,udf->name);
   udf->dl=strdup_root(&mem,udf->dl);
   if (!udf->name || !udf->dl ||
@@ -402,7 +438,7 @@
   u_d->func_reset=udf->func_reset;
   u_d->func_add=udf->func_add;
 
-  /* create entry in mysql/func table */
+  /* create entry in mysql.func table */
 
   bzero((char*) &tables,sizeof(tables));
   tables.db= (char*) "mysql";
@@ -422,7 +458,7 @@
   close_thread_tables(thd);
   if (error)
   {
-    net_printf(&thd->net, ER_ERROR_ON_WRITE, "[EMAIL PROTECTED]",error);
+    net_printf(&thd->net, ER_ERROR_ON_WRITE, "mysql.func",error);
     del_udf(u_d);
     goto err;
   }
--- a/sql/table.cc      2002-02-14 18:30:24.000000000 +0100
+++ b/sql/table.cc      2005-03-18 00:38:47.911609320 +0100
@@ -945,6 +945,10 @@
   uint key_length;
   ulong length;
   char fill[IO_SIZE];
+  int create_flags= O_RDWR | O_TRUNC;
+
+  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+    create_flags|= O_EXCL | O_NOFOLLOW;
 
 #if SIZEOF_OFF_T > 4
   /* Fix this in MySQL 4.0;  The current limit is 4G rows (QQ) */
@@ -954,7 +958,7 @@
     create_info->min_rows= ~(ulong) 0;
 #endif
 
-  if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+  if ((file= my_create(name, CREATE_MODE, create_flags, MYF(MY_WME))) >= 0)
   {
     bzero((char*) fileinfo,64);
     fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header

Reply via email to