diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2012-03-27 10:02:59 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2012-03-28 11:05:25 -0700 |
commit | 5911eff83efedce91b856b54ae11d94692c7d71e (patch) | |
tree | b296c29af40e172589b6f56d68ec14c676ef2ded | |
parent | 1a1c46afe29902a521ee4171304084dbc8cfcf5e (diff) | |
download | coreutils-5911eff83efedce91b856b54ae11d94692c7d71e.tar.xz |
chmod: fix symlink race condition
* NEWS: Document this.
* src/chmod.c (process_file): Don't follow symlink if we
think the file is not a symlink.
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | src/chmod.c | 10 |
2 files changed, 15 insertions, 1 deletions
@@ -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] diff --git a/src/chmod.c b/src/chmod.c index aa4ac771c..2e1f1c70b 100644 --- a/src/chmod.c +++ b/src/chmod.c @@ -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 { |