chmod: fix symlink race condition
authorPaul Eggert <eggert@cs.ucla.edu>
Tue, 27 Mar 2012 17:02:59 +0000 (10:02 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Wed, 28 Mar 2012 18:05:25 +0000 (11:05 -0700)
* NEWS: Document this.
* src/chmod.c (process_file): Don't follow symlink if we
think the file is not a symlink.

NEWS
src/chmod.c

diff --git a/NEWS b/NEWS
index c8d2bbc..40dadc2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  When recursing, chmod -R no longer gets confused into following a symlink
+  if some other process simultaneously replaces a non-symlink with a symlink.
+  The fix is effective on modern hosts with the fchmodat or lchmod syscalls.
+  [bug introduced in the beginning]
 
 * Noteworthy changes in release 8.16 (2012-03-26) [stable]
 
index aa4ac77..2e1f1c7 100644 (file)
@@ -268,7 +268,15 @@ process_file (FTS *fts, FTSENT *ent)
 
       if (! S_ISLNK (old_mode))
         {
-          if (chmodat (fts->fts_cwd_fd, file, new_mode) == 0)
+          /* Use any native support for AT_SYMLINK_NOFOLLOW, to avoid
+             following a symlink if there is a race.  */
+          #if HAVE_FCHMODAT || HAVE_LCHMOD
+          int follow_flag = AT_SYMLINK_NOFOLLOW;
+          #else
+          int follow_flag = 0;
+          #endif
+
+          if (fchmodat (fts->fts_cwd_fd, file, new_mode, follow_flag) == 0)
             chmod_succeeded = true;
           else
             {