Bug 196724 - fts(3) returns invalid fts_info for edge case
Summary: fts(3) returns invalid fts_info for edge case
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Only Me
Assignee: Jilles Tjoelker
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-01-14 13:55 UTC by Peter Holm
Modified: 2015-04-19 13:31 UTC (History)
1 user (show)

See Also:
jilles: mfc-stable10+
jilles: mfc-stable9-
jilles: mfc-stable8-


Attachments
don't return FTS_SLNONE if it's not a symlink (if race) (693 bytes, patch)
2015-04-03 19:29 UTC, Jilles Tjoelker
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Holm freebsd_committer freebsd_triage 2015-01-14 13:55:59 UTC
During parallel file system tests fts(3) may return a wrong value in fts_info.

# FAULT
# -rw-------  1 root  wheel  - 4 13 jan 09:25 ./lockf.0.3676
# fts_path: ./lockf.0.3676
# fts_info: 13 FTS_SLNONE
# fts_errno: 0 No error: 0

Test scenario @ http://people.freebsd.org/~pho/fts2.sh
Comment 1 Jilles Tjoelker freebsd_committer freebsd_triage 2015-04-01 21:59:25 UTC
When following symlinks, fts returns FTS_SLNONE when stat() fails, but a subsequent lstat() succeeds (in recent versions fstatat() without and with AT_SYMLINK_NOFOLLOW). This incorrectly triggers if a filename exists to be read from the directory, is deleted before the stat and created again after the stat.

Clearly, the code should only return FTS_SLNONE if S_ISLNK(sbp->st_mode). What it should do otherwise is less clear. We could go back to stat() and try some number of times for stat() and lstat() to become consistent, or we could return FTS_NS immediately.
Comment 2 Jilles Tjoelker freebsd_committer freebsd_triage 2015-04-03 19:29:12 UTC
Created attachment 155166 [details]
don't return FTS_SLNONE if it's not a symlink (if race)
Comment 3 Peter Holm freebsd_committer freebsd_triage 2015-04-04 09:54:13 UTC
The patch looks good. Tested on r281013. Thank you for looking at this!
Comment 4 commit-hook freebsd_committer freebsd_triage 2015-04-04 20:22:39 UTC
A commit references this bug:

Author: jilles
Date: Sat Apr  4 20:22:13 UTC 2015
New revision: 281082
URL: https://svnweb.freebsd.org/changeset/base/281082

Log:
  fts: Don't return FTS_SLNONE if it's not a symlink (if race).

  When following symlinks, fts returned FTS_SLNONE when fstatat(flag=0)
  failed, but a subsequent fstatat(flag=AT_SYMLINK_NOFOLLOW) succeeded. This
  incorrectly triggered if a filename existed to be read from the directory,
  was deleted before the fstatat(flag=0) and created again after the
  fstatat(flag=0).

  Fix this by only returning FTS_SLNONE if the result from
  fstatat(flag=AT_SYMLINK_NOFOLLOW) is actually a symlink. If it is not a
  symlink, treat it as if fstatat(flag=0) succeeded.

  PR:		196724
  Reported and tested by:	pho
  MFC after:	1 week

Changes:
  head/lib/libc/gen/fts.c
Comment 5 commit-hook freebsd_committer freebsd_triage 2015-04-19 13:29:30 UTC
A commit references this bug:

Author: jilles
Date: Sun Apr 19 13:28:32 UTC 2015
New revision: 281741
URL: https://svnweb.freebsd.org/changeset/base/281741

Log:
  MFC r281082: fts: Don't return FTS_SLNONE if it's not a symlink (if race).

  When following symlinks, fts returned FTS_SLNONE when fstatat(flag=0)
  failed, but a subsequent fstatat(flag=AT_SYMLINK_NOFOLLOW) succeeded. This
  incorrectly triggered if a filename existed to be read from the directory,
  was deleted before the fstatat(flag=0) and created again after the
  fstatat(flag=0).

  Fix this by only returning FTS_SLNONE if the result from
  fstatat(flag=AT_SYMLINK_NOFOLLOW) is actually a symlink. If it is not a
  symlink, treat it as if fstatat(flag=0) succeeded.

  PR:		196724

Changes:
_U  stable/10/
  stable/10/lib/libc/gen/fts.c