Mercurial > hg > octave-lojdl > gnulib-hg
changeset 10472:a4dc39a18d54
Ensure that a filename ending in a slash cannot be used to access a non-directory.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Wed, 24 Sep 2008 13:50:02 +0200 |
parents | f318366f3bc7 |
children | 541a421c693f |
files | ChangeLog doc/posix-functions/fopen.texi doc/posix-functions/open.texi lib/fopen.c lib/open.c modules/fopen tests/test-fopen.c tests/test-open.c |
diffstat | 8 files changed, 99 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2008-09-24 Bruno Haible <bruno@clisp.org> + + Ensure that a filename ending in a slash cannot be used to access a + non-directory. + * lib/open.c (rpl_open): When the filename ends in a slash, use fstat() + to check whether it's really a directory. + * lib/fopen.c: Include fcntl.h, unistd.h. + (rpl_fopen): When the filename ends in a slash, use open(), fstat(), + and fdopen(). + * modules/fopen (Depends-on): Add unistd. + * tests/test-open.c (main): Try to open "/dev/null/" as a directory. + * tests/test-fopen.c (main): Likewise. + * doc/posix-functions/open.texi: Mention the HP-UX, Solaris bug. + * doc/posix-functions/fopen.texi: Likewise. + Reported by Eric Blake. + 2008-09-23 Eric Blake <ebb9@byu.net> c-stack: avoid compiler optimizations when provoking overflow
--- a/doc/posix-functions/fopen.texi +++ b/doc/posix-functions/fopen.texi @@ -10,7 +10,8 @@ @itemize @item This function does not fail when the file name argument ends in a slash -and (without the slash) names a nonexistent file, on some platforms: +and (without the slash) names a nonexistent file or a file that is not a +directory, on some platforms: HP-UX 11.00, Solaris 9. @item On Windows platforms (excluding Cygwin), this function does usually not
--- a/doc/posix-functions/open.texi +++ b/doc/posix-functions/open.texi @@ -10,7 +10,8 @@ @itemize @item This function does not fail when the file name argument ends in a slash -and (without the slash) names a nonexistent file, on some platforms: +and (without the slash) names a nonexistent file or a file that is not a +directory, on some platforms: HP-UX 11.00, Solaris 9. @item On Windows platforms (excluding Cygwin), this function does usually not
--- a/lib/fopen.c +++ b/lib/fopen.c @@ -22,12 +22,19 @@ #include <stdio.h> #include <errno.h> +#include <fcntl.h> #include <string.h> +#include <unistd.h> FILE * rpl_fopen (const char *filename, const char *mode) #undef fopen { +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + if (strcmp (filename, "/dev/null") == 0) + filename = "NUL"; +#endif + #if FOPEN_TRAILING_SLASH_BUG /* If the filename ends in a slash and a mode that requires write access is specified, then fail. @@ -45,21 +52,41 @@ fails with errno = EISDIR in this case. If the named file does not exist or does not name a directory, then fopen() must fail since the file does not contain a '.' directory. */ - if (mode[0] == 'w' || mode[0] == 'a') - { - size_t len = strlen (filename); - if (len > 0 && filename[len - 1] == '/') - { - errno = EISDIR; + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + int fd; + struct stat statbuf; + FILE *fp; + + if (mode[0] == 'w' || mode[0] == 'a') + { + errno = EISDIR; + return NULL; + } + + fd = open (filename, O_RDONLY); + if (fd < 0) return NULL; - } - } -#endif + + if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) + { + errno = ENOTDIR; + return NULL; + } -#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ - if (strcmp (filename, "/dev/null") == 0) - filename = "NUL"; -#endif + fp = fdopen (fd, mode); + if (fp == NULL) + { + int saved_errno = errno; + close (fd); + errno = saved_errno; + } + return fp; + } + } +# endif return fopen (filename, mode); }
--- a/lib/open.c +++ b/lib/open.c @@ -35,6 +35,7 @@ # undef open { mode_t mode; + int fd; mode = 0; if (flags & O_CREAT) @@ -52,6 +53,11 @@ va_end (arg); } +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + if (strcmp (filename, "/dev/null") == 0) + filename = "NUL"; +# endif + # if OPEN_TRAILING_SLASH_BUG /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR is specified, then fail. @@ -85,11 +91,37 @@ } # endif -# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ - if (strcmp (filename, "/dev/null") == 0) - filename = "NUL"; + fd = open (filename, flags, mode); + +# if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash and fd does not refer to a directory, + then fail. + Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html> + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + If the named file without the slash is not a directory, open() must fail + with ENOTDIR. */ + if (fd >= 0) + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + struct stat statbuf; + + if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } + } # endif - return open (filename, flags, mode); + return fd; } #endif
--- a/modules/fopen +++ b/modules/fopen @@ -7,6 +7,7 @@ Depends-on: stdio +unistd configure.ac: gl_FUNC_FOPEN