From: Eric Blake Date: Wed, 2 Sep 2009 12:07:54 +0000 (-0600) Subject: openat-safer: new module X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02fd4eb4561842dee666b709fbbb1632c4357d2d;p=pspp openat-safer: new module * modules/openat-safer: New file. * lib/openat-safer.c: Likewise. * m4/fcntl-safer.m4 (gl_OPENAT_SAFER): New macro. * lib/fcntl-safer.h (openat_safer): Declare. * lib/fcntl--.h (openat): Override. * MODULES.html.sh (File descriptor based I/O): Mention it. * lib/openat.h: Add double-inclusion guards. * lib/openat.c (includes): Only include "fcntl-safer.h", not "fcntl--.h", so we can implement openat. * modules/openat-safer-tests: New test. * tests/test-openat-safer.c: New file. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index c30ac8e2c0..6c991eab21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,18 @@ 2009-09-02 Eric Blake + openat-safer: new module + * modules/openat-safer: New file. + * lib/openat-safer.c: Likewise. + * m4/fcntl-safer.m4 (gl_OPENAT_SAFER): New macro. + * lib/fcntl-safer.h (openat_safer): Declare. + * lib/fcntl--.h (openat): Override. + * MODULES.html.sh (File descriptor based I/O): Mention it. + * lib/openat.h: Add double-inclusion guards. + * lib/openat.c (includes): Only include "fcntl-safer.h", not + "fcntl--.h", so we can implement openat. + * modules/openat-safer-tests: New test. + * tests/test-openat-safer.c: New file. + dirent-safer: new module * modules/dirent-safer: New file. * lib/dirent--.h: Likewise. diff --git a/MODULES.html.sh b/MODULES.html.sh index bb99642690..bcecc5546e 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2509,6 +2509,7 @@ func_all_modules () func_begin_table func_module fcntl-safer + func_module openat-safer func_module safe-read func_module safe-write func_module full-read diff --git a/lib/fcntl--.h b/lib/fcntl--.h index 5a6a8792d0..9e311ce7ec 100644 --- a/lib/fcntl--.h +++ b/lib/fcntl--.h @@ -1,6 +1,6 @@ /* Like fcntl.h, but redefine some names to avoid glitches. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2009 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,3 +25,9 @@ #undef creat #define creat creat_safer + +#if GNULIB_OPENAT_SAFER +# include "openat.h" /* FIXME - should be sufficient. */ +# undef openat +# define openat openat_safer +#endif diff --git a/lib/fcntl-safer.h b/lib/fcntl-safer.h index 99f38656d0..2b10ba68f4 100644 --- a/lib/fcntl-safer.h +++ b/lib/fcntl-safer.h @@ -1,6 +1,6 @@ /* Invoke fcntl-like functions, but avoid some glitches. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2009 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,3 +21,7 @@ int open_safer (char const *, int, ...); int creat_safer (char const *, mode_t); + +#if GNULIB_OPENAT_SAFER +int openat_safer (int, char const *, int, ...); +#endif diff --git a/lib/openat-safer.c b/lib/openat-safer.c new file mode 100644 index 0000000000..f6977fd2b5 --- /dev/null +++ b/lib/openat-safer.c @@ -0,0 +1,47 @@ +/* Invoke openat, but avoid some glitches. + + Copyright (C) 2005, 2006, 2008-2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert for open, ported by Eric Blake for openat. */ + +#include + +#include "fcntl-safer.h" + +#include +#include "openat.h" /* FIXME - should be sufficient. */ +#include +#include "unistd-safer.h" + +int +openat_safer (int fd, char const *file, int flags, ...) +{ + mode_t mode = 0; + + if (flags & O_CREAT) + { + va_list ap; + va_start (ap, flags); + + /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4 + creates crashing code when 'mode_t' is smaller than 'int'. */ + mode = va_arg (ap, PROMOTED_MODE_T); + + va_end (ap); + } + + return fd_safer (openat (fd, file, flags, mode)); +} diff --git a/lib/openat.c b/lib/openat.c index 7a68cba60d..0e2c27b7b7 100644 --- a/lib/openat.c +++ b/lib/openat.c @@ -25,10 +25,16 @@ #include #include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */ -#include "fcntl--.h" #include "openat-priv.h" #include "save-cwd.h" +/* We can't use "fcntl--.h", so that openat_safer does not interfere. */ +#if GNULIB_FCNTL_SAFER +# include "fcntl-safer.h" +# undef open +# define open open_safer +#endif + /* Replacement for Solaris' openat function. First, try to simulate it via open ("/proc/self/fd/FD/FILE"). diff --git a/lib/openat.h b/lib/openat.h index 4072c94ed0..df52691ff9 100644 --- a/lib/openat.h +++ b/lib/openat.h @@ -16,6 +16,9 @@ /* written by Jim Meyering */ +#ifndef _GL_HEADER_OPENAT +#define _GL_HEADER_OPENAT + #include #include @@ -120,3 +123,5 @@ lchmodat (int fd, char const *file, mode_t mode) { return fchmodat (fd, file, mode, AT_SYMLINK_NOFOLLOW); } + +#endif /* _GL_HEADER_OPENAT */ diff --git a/m4/fcntl-safer.m4 b/m4/fcntl-safer.m4 index e2080dfa5d..365e221656 100644 --- a/m4/fcntl-safer.m4 +++ b/m4/fcntl-safer.m4 @@ -1,4 +1,4 @@ -#serial 6 +#serial 7 dnl Copyright (C) 2005-2007, 2009 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -11,3 +11,9 @@ AC_DEFUN([gl_FCNTL_SAFER], # Prerequisites of lib/open-safer.c. AC_REQUIRE([gl_PROMOTED_TYPE_MODE_T]) ]) + +AC_DEFUN([gl_OPENAT_SAFER], +[ + AC_REQUIRE([gl_FCNTL_SAFER]) + AC_LIBOBJ([openat-safer]) +]) diff --git a/modules/openat-safer b/modules/openat-safer new file mode 100644 index 0000000000..d59588396b --- /dev/null +++ b/modules/openat-safer @@ -0,0 +1,28 @@ +Description: +openat function that avoids clobbering std{in,out,err}. + +Files: +lib/fcntl--.h +lib/fcntl-safer.h +lib/openat-safer.c +m4/fcntl-safer.m4 + +Depends-on: +fcntl-safer +openat +unistd-safer + +configure.ac: +gl_OPENAT_SAFER +gl_MODULE_INDICATOR([openat-safer]) + +Makefile.am: + +Include: +"fcntl-safer.h" + +License: +GPL + +Maintainer: +Eric Blake diff --git a/modules/openat-safer-tests b/modules/openat-safer-tests new file mode 100644 index 0000000000..20bf3822d2 --- /dev/null +++ b/modules/openat-safer-tests @@ -0,0 +1,11 @@ +Files: +tests/test-openat-safer.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-openat-safer +check_PROGRAMS += test-openat-safer +test_openat_safer_LDADD = $(LDADD) @LIBINTL@ diff --git a/tests/test-openat-safer.c b/tests/test-openat-safer.c new file mode 100644 index 0000000000..a62477bfd3 --- /dev/null +++ b/tests/test-openat-safer.c @@ -0,0 +1,122 @@ +/* Test that openat_safer leave standard fds alone. + Copyright (C) 2009 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Eric Blake , 2009. */ + +#include + +#include "fcntl--.h" + +#include +#include +#include +#include +#include + +/* This test intentionally closes stderr. So, we arrange to have fd 10 + (outside the range of interesting fd's during the test) set up to + duplicate the original stderr. */ + +#define BACKUP_STDERR_FILENO 10 +static FILE *myerr; + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (myerr); \ + abort (); \ + } \ + } \ + while (0) + +int +main () +{ + int i; + int j; + int dfd; + int fd; + char buf[2]; + const char *witness = "test-openat-safer.txt"; + + /* We close fd 2 later, so save it in fd 10. */ + if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO + || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL) + return 2; + + /* Create handle for future use. */ + dfd = openat (AT_FDCWD, ".", O_RDONLY); + ASSERT (STDERR_FILENO < dfd); + + /* Create file for later checks. */ + remove (witness); + fd = openat (dfd, witness, O_WRONLY | O_CREAT | O_EXCL, 0600); + ASSERT (STDERR_FILENO < fd); + ASSERT (write (fd, "hi", 2) == 2); + ASSERT (close (fd) == 0); + + /* Four iterations, with progressively more standard descriptors + closed. */ + for (i = -1; i <= STDERR_FILENO; i++) + { + ASSERT (fchdir (dfd) == 0); + if (0 <= i) + ASSERT (close (i) == 0); + + /* Execute once in ".", once in "..". */ + for (j = 0; j <= 1; j++) + { + if (j) + ASSERT (chdir ("..") == 0); + + /* Check for error detection. */ + errno = 0; + ASSERT (openat (AT_FDCWD, "", O_RDONLY) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (openat (dfd, "", O_RDONLY) == -1); + ASSERT (errno == ENOENT); + + /* Check for trailing slash and /dev/null handling; the + particular errno might be ambiguous. */ + errno = 0; + ASSERT (openat (dfd, "nonexist.ent/", O_CREAT | O_RDONLY, + S_IRUSR | S_IWUSR) == -1); + /* ASSERT (errno == ENOTDIR); */ + errno = 0; + ASSERT (openat (dfd, "/dev/null/", O_RDONLY) == -1); + /* ASSERT (errno == ENOTDIR); */ + fd = openat (dfd, "/dev/null", O_RDONLY); + ASSERT (STDERR_FILENO < fd); + ASSERT (close (fd) == 0); + + /* Check for our witness file. */ + fd = openat (dfd, witness, O_RDONLY | O_NOFOLLOW); + ASSERT (STDERR_FILENO < fd); + ASSERT (read (fd, buf, 2) == 2); + ASSERT (buf[0] == 'h' && buf[1] == 'i'); + ASSERT (close (fd) == 0); + } + } + ASSERT (fchdir (dfd) == 0); + ASSERT (unlink (witness) == 0); + ASSERT (close (dfd) == 0); + + return 0; +}