Re: Linux libc5.4.33 dumbness w/ mk[s]temp()

From: Zack Weinberg (zackat_private)
Date: Mon Apr 13 1998 - 04:29:40 PDT

  • Next message: Theo de Raadt: "Re: MGE UPS Systems"

    On Sat, 11 Apr 1998 16:46:56 -0500, Greg Alexander wrote:
    >        Linux libc5.4.33's mk[s]temp() functions require 6 X's at the end of
    >a filename (the BSD versions I've seen are a bit more flexible).  This alone
    >is enough to break any claims to real BSD compatability,
    
    Six X's at the end of the string are required by the Unix98 standard.
    
    > but wait, there's
    >more:
    >        Only 1 of those 6 X's are really unique.  The rest are simply pid.
    >So you can create exactly 62 temp files using mk[s]temp() in one pid.  When
    >using mkstemp(), a EEXIST error is returned, and you get no fd, so you're
    >unlikely to do anything dumb, so it's just a really annoying DoS.
    
    This bug exists also in glibc 2.0.  It has been fixed in the 2.1
    development sources, but the fix is somewhat experimental so it will
    not be backported to 2.0.  However, I've appended the change in case
    anyone wants to test it.  It can probably be applied to 2.0 with
    minimal effort and to libc5 with some work.  It almost certainly won't
    work with either as is.
    
    I monitor this list pretty closely for libc-related bugs, but if you
    want to be sure they get addressed, please use the 'glibcbug' script
    that came with the library to send a formal report.
    
    zw
    
    Index: sysdeps/posix/mkstemp.c
    ===================================================================
    RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mkstemp.c,v
    retrieving revision 1.5
    retrieving revision 1.7
    diff -u -r1.5 -r1.7
    --- sysdeps/posix/mkstemp.c     1998/03/10 10:44:45     1.5
    +++ sysdeps/posix/mkstemp.c     1998/04/07 12:52:50     1.7
    @@ -19,9 +19,11 @@
     #include <stdlib.h>
     #include <string.h>
     #include <errno.h>
    +#include <stdint.h>
     #include <stdio.h>
     #include <fcntl.h>
     #include <unistd.h>
    +#include <sys/time.h>
    
     /* Generate a unique temporary file name from TEMPLATE.
        The last six characters of TEMPLATE must be "XXXXXX";
    @@ -33,8 +35,11 @@
     {
       static const char letters[]
         = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    +  static uint32_t value;
    +  struct timeval tv;
    +  char *XXXXXX;
       size_t len;
    -  size_t i;
    +  int count;
    
       len = strlen (template);
       if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
    @@ -43,20 +48,40 @@
           return -1;
         }
    
    -  if (sprintf (&template[len - 5], "%.5u",
    -              (unsigned int) getpid () % 100000) != 5)
    -    /* Inconceivable lossage.  */
    -    return -1;
    +  /* This is where the Xs start.  */
    +  XXXXXX = &template[len - 6];
    
    -  for (i = 0; i < sizeof (letters); ++i)
    +  /* Get some more or less random data.  */
    +  __gettimeofday (&tv, NULL);
    +  value += tv.tv_usec | getpid ();
    +
    +  for (count = 0; count < TMP_MAX; ++count)
         {
    +      uint32_t v = value;
           int fd;
    
    -      template[len - 6] = letters[i];
    +      /* Fill in the random bits.  */
    +      XXXXXX[0] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[1] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[2] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[3] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[4] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[5] = letters[v % 62];
    
           fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600);
           if (fd >= 0)
    +       /* The file does not exist.  */
            return fd;
    +
    +      /* This is a random value.  It is only necessary that the next
    +        TMP_MAX values generated by adding 7777 to VALUE are different
    +        with (module 2^32).  */
    +      value += 7777;
         }
    
       /* We return the null string if we can't find a unique file name.  */
    Index: sysdeps/posix/mktemp.c
    ===================================================================
    RCS file: /egcs/carton/cvsfiles/libc/sysdeps/posix/mktemp.c,v
    retrieving revision 1.8
    retrieving revision 1.9
    diff -u -r1.8 -r1.9
    --- sysdeps/posix/mktemp.c      1996/11/06 04:24:39     1.8
    +++ sysdeps/posix/mktemp.c      1998/04/07 09:08:11     1.9
    @@ -1,4 +1,4 @@
    -/* Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
    +/* Copyright (C) 1991, 1992, 1993, 1996, 1998 Free Software Foundation, Inc.
        This file is part of the GNU C Library.
    
        The GNU C Library is free software; you can redistribute it and/or
    @@ -16,13 +16,15 @@
        write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
        Boston, MA 02111-1307, USA.  */
    
    +#include <errno.h>
    +#include <stdint.h>
    +#include <stdio.h>
     #include <stdlib.h>
     #include <string.h>
    -#include <errno.h>
     #include <unistd.h>
    -#include <stdio.h>
    -#include <sys/types.h>
     #include <sys/stat.h>
    +#include <sys/time.h>
    +#include <sys/types.h>
    
     /* Generate a unique temporary file name from TEMPLATE.
        The last six characters of TEMPLATE must be "XXXXXX";
    @@ -33,8 +35,11 @@
     {
       static const char letters[]
         = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    +  static uint32_t value;
    +  struct timeval tv;
    +  char *XXXXXX;
       size_t len;
    -  size_t i;
    +  int count;
    
       len = strlen (template);
       if (len < 6 || strcmp (&template[len - 6], "XXXXXX"))
    @@ -43,20 +48,39 @@
           return NULL;
         }
    
    -  if (sprintf (&template[len - 5], "%.5u",
    -              (unsigned int) getpid () % 100000) != 5)
    -    /* Inconceivable lossage.  */
    -    return NULL;
    +  /* This is where the Xs start.  */
    +  XXXXXX = &template[len - 6];
    
    -  for (i = 0; i < sizeof (letters); ++i)
    +  /* Get some more or less random data.  */
    +  __gettimeofday (&tv, NULL);
    +  value += tv.tv_usec | getpid ();
    +
    +  for (count = 0; count < TMP_MAX; ++count)
         {
           struct stat ignored;
    +      uint32_t v = value;
    
    -      template[len - 6] = letters[i];
    +      /* Fill in the random bits.  */
    +      XXXXXX[0] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[1] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[2] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[3] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[4] = letters[v % 62];
    +      v /= 62;
    +      XXXXXX[5] = letters[v % 62];
    
           if (stat (template, &ignored) < 0 && errno == ENOENT)
            /* The file does not exist.  So return this name.  */
            return template;
    +
    +      /* This is a random value.  It is only necessary that the next
    +        TMP_MAX values generated by adding 7777 to VALUE are different
    +        with (module 2^32).  */
    +      value += 7777;
         }
    
       /* We return the null string if we can't find a unique file name.  */
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 13:49:10 PDT