This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[Ada] Partial fix for overflow bugs in run-time library


Maybe I've submitted this earlier, I'm not sure.

The Ada run-time library contains several buffer overflow bugs.  The
one that is most easily exploited (for setuid binaries) was introduced
when the /tmp race condition in the Ada temporary files code was
removed (on GNU/Linux systems).

The VMS code either has plenty of buffer overflow problems, or VMS
limits the file name length quite drastically.  SGI's realpath() might
be problematic, too.

I've got no documentation on the readdir_r() function, so I can't tell
if the code is safe or not.  The Win32 code is definitely unsafe and
needs fixing, but I haven't got a Win32 machine.

Bootstrapped on GNU/Linux on x86.

2001-11-07  Florian Weimer  <fw@deneb.enyo.de>

	* adaint.c (__gnat_try_lock): Fix buffer overflow bugs.
	(max_path_len): Moved from cstreams.c.
	(__gnat_tmp_name, __gnat_readdir): Fix buffer overflow bug,
	readdir_r() call has still to be verified.
	(win32_no_block_spawn): We have a buffer overflow bug in this
	function.

	* adaint.h (max_path_len): Declare variable, since we still need
	it in cstreams.c.

	* cstreams.c (max_path_len): Moved to adaint.c
	(__gnat_full_name): Fix buffer overflow bugs.


Index: adaint.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ada/adaint.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 adaint.c
*** adaint.c	2001/10/04 17:50:42	1.2
--- adaint.c	2001/11/07 11:22:03
*************** __gnat_try_lock (dir, file)
*** 244,253 ****
       char *dir;
       char *file;
  {
!   char full_path [256];
    int fd;
  
!   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
    fd = open (full_path, O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
      return 0;
--- 244,253 ----
       char *dir;
       char *file;
  {
!   char full_path [1024];
    int fd;
  
!   sprintf (full_path, "%.500s%c%.500s", dir, DIR_SEPARATOR, file);
    fd = open (full_path, O_CREAT | O_EXCL, 0600);
    if (fd < 0) {
      return 0;
*************** __gnat_try_lock (dir, file)
*** 266,275 ****
       char *dir;
       char *file;
  {
!   char full_path [256];
    int fd;
  
!   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
    fd = open (full_path, O_CREAT | O_EXCL, 0600);
    if (fd < 0)
      return 0;
--- 266,275 ----
       char *dir;
       char *file;
  {
!   char full_path [1024];
    int fd;
  
!   sprintf (full_path, "%.500s%c%.500s", dir, DIR_SEPARATOR, file);
    fd = open (full_path, O_CREAT | O_EXCL, 0600);
    if (fd < 0)
      return 0;
*************** __gnat_try_lock (dir, file)
*** 286,298 ****
       char *dir;
       char *file;
  {
!   char full_path [256];
!   char temp_file [256];
    struct stat stat_result;
    int fd;
  
!   sprintf (full_path, "%s%c%s", dir, DIR_SEPARATOR, file);
!   sprintf (temp_file, "%s-%d-%d", dir, getpid(), getppid ());
  
    /* Create the temporary file and write the process number */
    fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
--- 286,298 ----
       char *dir;
       char *file;
  {
!   char full_path [1024];
!   char temp_file [1024];
    struct stat stat_result;
    int fd;
  
!   sprintf (full_path, "%.500s%c%.500s", dir, DIR_SEPARATOR, file);
!   sprintf (temp_file, "%.500s-%d-%d", dir, getpid(), getppid ());
  
    /* Create the temporary file and write the process number */
    fd = open (temp_file, O_CREAT | O_WRONLY, 0600);
*************** __gnat_file_length (fd)
*** 626,633 ****
    return (statbuf.st_size);
  }
  
  /* Create a temporary filename and put it in string pointed to by
!    tmp_filename */
  
  void
  __gnat_tmp_name (tmp_filename)
--- 626,652 ----
    return (statbuf.st_size);
  }
  
+ #ifdef __EMX__
+ int max_path_len = _MAX_PATH;
+ 
+ #else
+ #ifdef VMS
+ int max_path_len = 255; /* PATH_MAX */
+ 
+ #else
+ #if defined (__vxworks) || defined (__OPENNT)
+ int max_path_len = PATH_MAX;
+ 
+ #else
+ #include <sys/param.h>
+ int max_path_len = MAXPATHLEN;
+ #endif
+ #endif
+ #endif
+ 
  /* Create a temporary filename and put it in string pointed to by
!    tmp_filename.  tmp_filename must point to at least max_path_len 
!    characters.  */
  
  void
  __gnat_tmp_name (tmp_filename)
*************** __gnat_tmp_name (tmp_filename)
*** 660,666 ****
  #elif defined (linux)
    char *tmpdir = getenv ("TMPDIR");
  
!   if (tmpdir == NULL)
      strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
    else
      sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
--- 679,685 ----
  #elif defined (linux)
    char *tmpdir = getenv ("TMPDIR");
  
!   if (tmpdir == NULL || (strlen(tmpdir) + 20) > (size_t) max_path_len)
      strcpy (tmp_filename, "/tmp/gnat-XXXXXX");
    else
      sprintf (tmp_filename, "%s/gnat-XXXXXX", tmpdir);
*************** __gnat_readdir (dirp, buffer)
*** 681,686 ****
--- 700,706 ----
  {
    /* If possible, try to use the thread-safe version.  */
  #ifdef HAVE_READDIR_R
+   /* ??? readdir_r() might overflow buffer. */
    if (readdir_r (dirp, buffer) != NULL)
      return ((struct dirent*) buffer)->d_name;
    else
*************** __gnat_readdir (dirp, buffer)
*** 689,695 ****
  #else
    struct dirent *dirent = readdir (dirp);
  
!   if (dirent != NULL)
      {
        strcpy (buffer, dirent->d_name);
        return buffer;
--- 709,715 ----
  #else
    struct dirent *dirent = readdir (dirp);
  
!   if (dirent != NULL && strlen(dirent->d_name) <= 1024)
      {
        strcpy (buffer, dirent->d_name);
        return buffer;
*************** win32_no_block_spawn (command, args)
*** 1293,1299 ****
    PROCESS_INFORMATION PI;
    SECURITY_ATTRIBUTES SA;
  
!   char full_command [2000];
    int k;
  
    /* Startup info. */
--- 1313,1319 ----
    PROCESS_INFORMATION PI;
    SECURITY_ATTRIBUTES SA;
  
!   char full_command [2000];	/* ??? buffer overflow bug */
    int k;
  
    /* Startup info. */
Index: adaint.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ada/adaint.h,v
retrieving revision 1.3
diff -c -3 -p -r1.3 adaint.h
*** adaint.h	2001/10/05 21:07:05	1.3
--- adaint.h	2001/11/07 11:22:03
*************** extern char  *__gnat_to_host_file_spec  
*** 96,101 ****
--- 96,102 ----
  extern char  *__gnat_to_canonical_path_spec	   PARAMS ((char *));
  extern void   __gnat_adjust_os_resource_limits	   PARAMS ((void));
  
+ extern int     max_path_len;
  extern int     __gnat_feof		  	   PARAMS ((FILE *));
  extern int     __gnat_ferror		  	   PARAMS ((FILE *));
  extern int     __gnat_fileno		  	   PARAMS ((FILE *));
Index: cstreams.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ada/cstreams.c,v
retrieving revision 1.2
diff -c -3 -p -r1.2 cstreams.c
*** cstreams.c	2001/10/04 17:50:42	1.2
--- cstreams.c	2001/11/07 11:22:03
***************
*** 49,66 ****
  
  #include "adaint.h"
  
! #ifdef __EMX__
! int max_path_len = _MAX_PATH;
! #elif defined (VMS)
  #include <unixlib.h>
! int max_path_len = 255; /* PATH_MAX */
! 
! #elif defined (__vxworks) || defined (__OPENNT)
  
- int max_path_len = PATH_MAX;
  
- #else
- 
  #ifdef linux
  
  /* Don't use macros on GNU/Linux since they cause incompatible changes between
--- 49,59 ----
  
  #include "adaint.h"
  
! #ifdef VMS
  #include <unixlib.h>
! #endif
  
  
  #ifdef linux
  
  /* Don't use macros on GNU/Linux since they cause incompatible changes between
*************** int max_path_len = PATH_MAX;
*** 78,88 ****
  
  #endif
  
- #include <sys/param.h>
- 
- int max_path_len = MAXPATHLEN;
- #endif
- 
  /* The _IONBF value in CYGNUS or MINGW32 stdio.h is wrong.  */
  #if defined (WINNT) || defined (_WINNT)
  #undef _IONBF
--- 71,76 ----
*************** __gnat_full_name (nam, buffer)
*** 225,231 ****
  #else
    if (nam[0] != '/')
      {
!       p = getcwd (buffer, max_path_len);
        if (p == 0)
  	{
  	  buffer[0] = '\0';
--- 213,219 ----
  #else
    if (nam[0] != '/')
      {
!       p = getcwd (buffer, max_path_len - (strlen(nam) + 1));
        if (p == 0)
  	{
  	  buffer[0] = '\0';
*************** __gnat_full_name (nam, buffer)
*** 239,247 ****
  
        strcat (buffer, nam);
      }
!   else
!     strcpy (buffer, nam);
! 
    return buffer;
  #endif
  }
--- 227,242 ----
  
        strcat (buffer, nam);
      }
!   else 
!     {
!       if (strlen(nam) < max_path_len)
! 	  strcpy (buffer, nam);
!       else 
! 	{
! 	  buffer[0] = '\0';
! 	  return 0;
! 	}
!     }
    return buffer;
  #endif
  }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]