olga / rpms / glibc

Forked from rpms/glibc 5 years ago
Clone

Blame SOURCES/glibc-rh996227.patch

00db10
commit 91ce40854d0b7f865cf5024ef95a8026b76096f3
00db10
Author: Florian Weimer <fweimer@redhat.com>
00db10
Date:   Fri Aug 16 09:38:52 2013 +0200
00db10
00db10
    CVE-2013-4237, BZ #14699: Buffer overflow in readdir_r
00db10
    
00db10
    	* sysdeps/posix/dirstream.h (struct __dirstream): Add errcode
00db10
    	member.
00db10
    	* sysdeps/posix/opendir.c (__alloc_dir): Initialize errcode
00db10
    	member.
00db10
    	* sysdeps/posix/rewinddir.c (rewinddir): Reset errcode member.
00db10
    	* sysdeps/posix/readdir_r.c (__READDIR_R): Enforce NAME_MAX limit.
00db10
    	Return delayed error code.  Remove GETDENTS_64BIT_ALIGNED
00db10
    	conditional.
00db10
    	* sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c: Do not define
00db10
    	GETDENTS_64BIT_ALIGNED.
00db10
    	* sysdeps/unix/sysv/linux/i386/readdir64_r.c: Likewise.
00db10
    	* manual/filesys.texi (Reading/Closing Directory): Document
00db10
    	ENAMETOOLONG return value of readdir_r.  Recommend readdir more
00db10
    	strongly.
00db10
    	* manual/conf.texi (Limits for Files): Add portability note to
00db10
    	NAME_MAX, PATH_MAX.
00db10
    	(Pathconf): Add portability note for _PC_NAME_MAX, _PC_PATH_MAX.
00db10
00db10
diff --git glibc-2.17-c758a686/manual/conf.texi glibc-2.17-c758a686/manual/conf.texi
00db10
index 7eb8b36..c720063 100644
00db10
--- glibc-2.17-c758a686/manual/conf.texi
00db10
+++ glibc-2.17-c758a686/manual/conf.texi
00db10
@@ -1149,6 +1149,9 @@ typed ahead as input.  @xref{I/O Queues}.
00db10
 @deftypevr Macro int NAME_MAX
00db10
 The uniform system limit (if any) for the length of a file name component, not
00db10
 including the terminating null character.
00db10
+
00db10
+@strong{Portability Note:} On some systems, @theglibc{} defines
00db10
+@code{NAME_MAX}, but does not actually enforce this limit.
00db10
 @end deftypevr
00db10
 
00db10
 @comment limits.h
00db10
@@ -1157,6 +1160,9 @@ including the terminating null character.
00db10
 The uniform system limit (if any) for the length of an entire file name (that
00db10
 is, the argument given to system calls such as @code{open}), including the
00db10
 terminating null character.
00db10
+
00db10
+@strong{Portability Note:} @Theglibc{} does not enforce this limit
00db10
+even if @code{PATH_MAX} is defined.
00db10
 @end deftypevr
00db10
 
00db10
 @cindex limits, pipe buffer size
00db10
@@ -1476,6 +1482,9 @@ Inquire about the value of @code{POSIX_REC_MIN_XFER_SIZE}.
00db10
 Inquire about the value of @code{POSIX_REC_XFER_ALIGN}.
00db10
 @end table
00db10
 
00db10
+@strong{Portability Note:} On some systems, @theglibc{} does not
00db10
+enforce @code{_PC_NAME_MAX} or @code{_PC_PATH_MAX} limits.
00db10
+
00db10
 @node Utility Limits
00db10
 @section Utility Program Capacity Limits
00db10
 
00db10
diff --git glibc-2.17-c758a686/manual/filesys.texi glibc-2.17-c758a686/manual/filesys.texi
00db10
index 1df9cf2..814c210 100644
00db10
--- glibc-2.17-c758a686/manual/filesys.texi
00db10
+++ glibc-2.17-c758a686/manual/filesys.texi
00db10
@@ -444,9 +444,9 @@ symbols are declared in the header file @file{dirent.h}.
00db10
 @comment POSIX.1
00db10
 @deftypefun {struct dirent *} readdir (DIR *@var{dirstream})
00db10
 This function reads the next entry from the directory.  It normally
00db10
-returns a pointer to a structure containing information about the file.
00db10
-This structure is statically allocated and can be rewritten by a
00db10
-subsequent call.
00db10
+returns a pointer to a structure containing information about the
00db10
+file.  This structure is associated with the @var{dirstream} handle
00db10
+and can be rewritten by a subsequent call.
00db10
 
00db10
 @strong{Portability Note:} On some systems @code{readdir} may not
00db10
 return entries for @file{.} and @file{..}, even though these are always
00db10
@@ -461,19 +461,61 @@ conditions are defined for this function:
00db10
 The @var{dirstream} argument is not valid.
00db10
 @end table
00db10
 
00db10
-@code{readdir} is not thread safe.  Multiple threads using
00db10
-@code{readdir} on the same @var{dirstream} may overwrite the return
00db10
-value.  Use @code{readdir_r} when this is critical.
00db10
+To distinguish between an end-of-directory condition or an error, you
00db10
+must set @code{errno} to zero before calling @code{readdir}.  To avoid
00db10
+entering an infinite loop, you should stop reading from the directory
00db10
+after the first error.
00db10
+
00db10
+In POSIX.1-2008, @code{readdir} is not thread-safe.  In @theglibc{}
00db10
+implementation, it is safe to call @code{readdir} concurrently on
00db10
+different @var{dirstream}s, but multiple threads accessing the same
00db10
+@var{dirstream} result in undefined behavior.  @code{readdir_r} is a
00db10
+fully thread-safe alternative, but suffers from poor portability (see
00db10
+below).  It is recommended that you use @code{readdir}, with external
00db10
+locking if multiple threads access the same @var{dirstream}.
00db10
 @end deftypefun
00db10
 
00db10
 @comment dirent.h
00db10
 @comment GNU
00db10
 @deftypefun int readdir_r (DIR *@var{dirstream}, struct dirent *@var{entry}, struct dirent **@var{result})
00db10
-This function is the reentrant version of @code{readdir}.  Like
00db10
-@code{readdir} it returns the next entry from the directory.  But to
00db10
-prevent conflicts between simultaneously running threads the result is
00db10
-not stored in statically allocated memory.  Instead the argument
00db10
-@var{entry} points to a place to store the result.
00db10
+This function is a version of @code{readdir} which performs internal
00db10
+locking.  Like @code{readdir} it returns the next entry from the
00db10
+directory.  To prevent conflicts between simultaneously running
00db10
+threads the result is stored inside the @var{entry} object.
00db10
+
00db10
+@strong{Portability Note:} It is recommended to use @code{readdir}
00db10
+instead of @code{readdir_r} for the following reasons:
00db10
+
00db10
+@itemize @bullet
00db10
+@item
00db10
+On systems which do not define @code{NAME_MAX}, it may not be possible
00db10
+to use @code{readdir_r} safely because the caller does not specify the
00db10
+length of the buffer for the directory entry.
00db10
+
00db10
+@item
00db10
+On some systems, @code{readdir_r} cannot read directory entries with
00db10
+very long names.  If such a name is encountered, @theglibc{}
00db10
+implementation of @code{readdir_r} returns with an error code of
00db10
+@code{ENAMETOOLONG} after the final directory entry has been read.  On
00db10
+other systems, @code{readdir_r} may return successfully, but the
00db10
+@code{d_name} member may not be NUL-terminated or may be truncated.
00db10
+
00db10
+@item
00db10
+POSIX-1.2008 does not guarantee that @code{readdir} is thread-safe,
00db10
+even when access to the same @var{dirstream} is serialized.  But in
00db10
+current implementations (including @theglibc{}), it is safe to call
00db10
+@code{readdir} concurrently on different @var{dirstream}s, so there is
00db10
+no need to use @code{readdir_r} in most multi-threaded programs.  In
00db10
+the rare case that multiple threads need to read from the same
00db10
+@var{dirstream}, it is still better to use @code{readdir} and external
00db10
+synchronization.
00db10
+
00db10
+@item
00db10
+It is expected that future versions of POSIX will obsolete
00db10
+@code{readdir_r} and mandate the level of thread safety for
00db10
+@code{readdir} which is provided by @theglibc{} and other
00db10
+implementations today.
00db10
+@end itemize
00db10
 
00db10
 Normally @code{readdir_r} returns zero and sets @code{*@var{result}}
00db10
 to @var{entry}.  If there are no more entries in the directory or an
00db10
@@ -481,15 +523,6 @@ error is detected, @code{readdir_r} sets @code{*@var{result}} to a
00db10
 null pointer and returns a nonzero error code, also stored in
00db10
 @code{errno}, as described for @code{readdir}.
00db10
 
00db10
-@strong{Portability Note:} On some systems @code{readdir_r} may not
00db10
-return a NUL terminated string for the file name, even when there is no
00db10
-@code{d_reclen} field in @code{struct dirent} and the file
00db10
-name is the maximum allowed size.  Modern systems all have the
00db10
-@code{d_reclen} field, and on old systems multi-threading is not
00db10
-critical.  In any case there is no such problem with the @code{readdir}
00db10
-function, so that even on systems without the @code{d_reclen} member one
00db10
-could use multiple threads by using external locking.
00db10
-
00db10
 It is also important to look at the definition of the @code{struct
00db10
 dirent} type.  Simply passing a pointer to an object of this type for
00db10
 the second parameter of @code{readdir_r} might not be enough.  Some
00db10
diff --git glibc-2.17-c758a686/sysdeps/posix/dirstream.h glibc-2.17-c758a686/sysdeps/posix/dirstream.h
00db10
index a7a074d..8e8570d 100644
00db10
--- glibc-2.17-c758a686/sysdeps/posix/dirstream.h
00db10
+++ glibc-2.17-c758a686/sysdeps/posix/dirstream.h
00db10
@@ -39,6 +39,8 @@ struct __dirstream
00db10
 
00db10
     off_t filepos;		/* Position of next entry to read.  */
00db10
 
00db10
+    int errcode;		/* Delayed error code.  */
00db10
+
00db10
     /* Directory block.  */
00db10
     char data[0] __attribute__ ((aligned (__alignof__ (void*))));
00db10
   };
00db10
diff --git glibc-2.17-c758a686/sysdeps/posix/opendir.c glibc-2.17-c758a686/sysdeps/posix/opendir.c
00db10
index ddfc3a7..fc05b0f 100644
00db10
--- glibc-2.17-c758a686/sysdeps/posix/opendir.c
00db10
+++ glibc-2.17-c758a686/sysdeps/posix/opendir.c
00db10
@@ -231,6 +231,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp)
00db10
   dirp->size = 0;
00db10
   dirp->offset = 0;
00db10
   dirp->filepos = 0;
00db10
+  dirp->errcode = 0;
00db10
 
00db10
   return dirp;
00db10
 }
00db10
diff --git glibc-2.17-c758a686/sysdeps/posix/readdir_r.c glibc-2.17-c758a686/sysdeps/posix/readdir_r.c
00db10
index b5a8e2e..8ed5c3f 100644
00db10
--- glibc-2.17-c758a686/sysdeps/posix/readdir_r.c
00db10
+++ glibc-2.17-c758a686/sysdeps/posix/readdir_r.c
00db10
@@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
00db10
   DIRENT_TYPE *dp;
00db10
   size_t reclen;
00db10
   const int saved_errno = errno;
00db10
+  int ret;
00db10
 
00db10
   __libc_lock_lock (dirp->lock);
00db10
 
00db10
@@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
00db10
 		  bytes = 0;
00db10
 		  __set_errno (saved_errno);
00db10
 		}
00db10
+	      if (bytes < 0)
00db10
+		dirp->errcode = errno;
00db10
 
00db10
 	      dp = NULL;
00db10
-	      /* Reclen != 0 signals that an error occurred.  */
00db10
-	      reclen = bytes != 0;
00db10
 	      break;
00db10
 	    }
00db10
 	  dirp->size = (size_t) bytes;
00db10
@@ -106,29 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
00db10
       dirp->filepos += reclen;
00db10
 #endif
00db10
 
00db10
-      /* Skip deleted files.  */
00db10
+#ifdef NAME_MAX
00db10
+      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
00db10
+	{
00db10
+	  /* The record is very long.  It could still fit into the
00db10
+	     caller-supplied buffer if we can skip padding at the
00db10
+	     end.  */
00db10
+	  size_t namelen = _D_EXACT_NAMLEN (dp);
00db10
+	  if (namelen <= NAME_MAX)
00db10
+	    reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
00db10
+	  else
00db10
+	    {
00db10
+	      /* The name is too long.  Ignore this file.  */
00db10
+	      dirp->errcode = ENAMETOOLONG;
00db10
+	      dp->d_ino = 0;
00db10
+	      continue;
00db10
+	    }
00db10
+	}
00db10
+#endif
00db10
+
00db10
+      /* Skip deleted and ignored files.  */
00db10
     }
00db10
   while (dp->d_ino == 0);
00db10
 
00db10
   if (dp != NULL)
00db10
     {
00db10
-#ifdef GETDENTS_64BIT_ALIGNED
00db10
-      /* The d_reclen value might include padding which is not part of
00db10
-	 the DIRENT_TYPE data structure.  */
00db10
-      reclen = MIN (reclen,
00db10
-		    offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name));
00db10
-#endif
00db10
       *result = memcpy (entry, dp, reclen);
00db10
-#ifdef GETDENTS_64BIT_ALIGNED
00db10
+#ifdef _DIRENT_HAVE_D_RECLEN
00db10
       entry->d_reclen = reclen;
00db10
 #endif
00db10
+      ret = 0;
00db10
     }
00db10
   else
00db10
-    *result = NULL;
00db10
+    {
00db10
+      *result = NULL;
00db10
+      ret = dirp->errcode;
00db10
+    }
00db10
 
00db10
   __libc_lock_unlock (dirp->lock);
00db10
 
00db10
-  return dp != NULL ? 0 : reclen ? errno : 0;
00db10
+  return ret;
00db10
 }
00db10
 
00db10
 #ifdef __READDIR_R_ALIAS
00db10
diff --git glibc-2.17-c758a686/sysdeps/posix/rewinddir.c glibc-2.17-c758a686/sysdeps/posix/rewinddir.c
00db10
index 2935a8e..d4991ad 100644
00db10
--- glibc-2.17-c758a686/sysdeps/posix/rewinddir.c
00db10
+++ glibc-2.17-c758a686/sysdeps/posix/rewinddir.c
00db10
@@ -33,6 +33,7 @@ rewinddir (dirp)
00db10
   dirp->filepos = 0;
00db10
   dirp->offset = 0;
00db10
   dirp->size = 0;
00db10
+  dirp->errcode = 0;
00db10
 #ifndef NOT_IN_libc
00db10
   __libc_lock_unlock (dirp->lock);
00db10
 #endif
00db10
diff --git glibc-2.17-c758a686/sysdeps/unix/sysv/linux/i386/readdir64_r.c glibc-2.17-c758a686/sysdeps/unix/sysv/linux/i386/readdir64_r.c
00db10
index 8ebbcfd..a7d114e 100644
00db10
--- glibc-2.17-c758a686/sysdeps/unix/sysv/linux/i386/readdir64_r.c
00db10
+++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/i386/readdir64_r.c
00db10
@@ -18,7 +18,6 @@
00db10
 #define __READDIR_R __readdir64_r
00db10
 #define __GETDENTS __getdents64
00db10
 #define DIRENT_TYPE struct dirent64
00db10
-#define GETDENTS_64BIT_ALIGNED 1
00db10
 
00db10
 #include <sysdeps/posix/readdir_r.c>
00db10
 
00db10
diff --git glibc-2.17-c758a686/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c glibc-2.17-c758a686/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
00db10
index 5ed8e95..290f2c8 100644
00db10
--- glibc-2.17-c758a686/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
00db10
+++ glibc-2.17-c758a686/sysdeps/unix/sysv/linux/wordsize-64/readdir_r.c
00db10
@@ -1,5 +1,4 @@
00db10
 #define readdir64_r __no_readdir64_r_decl
00db10
-#define GETDENTS_64BIT_ALIGNED 1
00db10
 #include <sysdeps/posix/readdir_r.c>
00db10
 #undef readdir64_r
00db10
 weak_alias (__readdir_r, readdir64_r)