This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Ada] Partial fix for overflow bugs in run-time library
- To: gcc-patches at gcc dot gnu dot org
- Subject: [Ada] Partial fix for overflow bugs in run-time library
- From: Florian Weimer <fw at deneb dot enyo dot de>
- Date: Wed, 07 Nov 2001 13:13:00 +0100
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
}