fts: use O_NOFOLLOW to avoid race condition when opening a directory
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Sep 2010 19:38:41 +0000 (12:38 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Sep 2010 19:39:10 +0000 (12:39 -0700)
* lib/fts.c (opendirat): New arg extra_flags.
(__opendir2): Use it to avoid following symlinks when opening
a directory, if symlinks are not supposed to be followed.  See
<http://lists.gnu.org/archive/html/bug-gnulib/2010-09/msg00213.html>.

ChangeLog
lib/fts.c

index 3d6d4c4..f2c8301 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2010-09-13  Paul Eggert  <eggert@cs.ucla.edu>
 
+       fts: use O_NOFOLLOW to avoid race condition when opening a directory
+       * lib/fts.c (opendirat): New arg extra_flags.
+       (__opendir2): Use it to avoid following symlinks when opening
+       a directory, if symlinks are not supposed to be followed.  See
+       <http://lists.gnu.org/archive/html/bug-gnulib/2010-09/msg00213.html>.
+
        fdopendir: preserve argument fd before returning
        * lib/fdopendir.c: Adjust comments to say POSIX, not Solaris.
        (fdopendir_with_dup, fd_clone_opendir): New static functions.
index 4b89ee7..1daf69c 100644 (file)
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -290,10 +290,11 @@ fts_set_stat_required (FTSENT *p, bool required)
 /* FIXME: if others need this function, move it into lib/openat.c */
 static inline DIR *
 internal_function
-opendirat (int fd, char const *dir)
+opendirat (int fd, char const *dir, int extra_flags)
 {
   int new_fd = openat (fd, dir,
-                       O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
+                       (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
+                        | extra_flags));
   DIR *dirp;
 
   if (new_fd < 0)
@@ -1237,7 +1238,11 @@ fts_build (register FTS *sp, int type)
 #else
 # define __opendir2(file, flag) \
         ( ! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD) \
-          ? opendirat(sp->fts_cwd_fd, file)        \
+          ? opendirat(sp->fts_cwd_fd, file,        \
+                      ((ISSET(FTS_PHYSICAL)                   \
+                        && ! (cur->fts_level == FTS_ROOTLEVEL \
+                              && ISSET(FTS_COMFOLLOW)))       \
+                       ? O_NOFOLLOW : 0))                     \
           : opendir(file))
 #endif
        if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {