Bug 194132 - rm(1) is ignoring more errors than it should in rm_tree(..)
Summary: rm(1) is ignoring more errors than it should in rm_tree(..)
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: bin (show other bugs)
Version: CURRENT
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-04 05:44 UTC by Enji Cooper
Modified: 2014-10-16 19:41 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Enji Cooper freebsd_committer freebsd_triage 2014-10-04 05:44:00 UTC
This code in bin/rm/rm.c catches more errors than it should:

338         if (!fflag && errno)
339                 err(1, "fts_read");
340         fts_close(fts);
341 }

In particular, the code will mask errors if fts_read fails with anything other than EACCES, ENOENT, or EPERM according to the intent of -f in rm(1):

     -f      Attempt to remove the files without prompting for confirmation,
             regardless of the file's permissions.  If the file does not
             exist, do not display a diagnostic message or modify the exit
             status to reflect an error.  The -f option overrides any previous
             -i options.

Please see the related bug for more details.
Comment 1 Warner Losh freebsd_committer freebsd_triage 2014-10-04 20:30:44 UTC
So how is this an actual bug?
Comment 2 Warner Losh freebsd_committer freebsd_triage 2014-10-04 20:31:17 UTC
and don't assign me bugs that I have no interest in fixing,
Comment 3 Jilles Tjoelker freebsd_committer freebsd_triage 2014-10-05 15:13:03 UTC
The problem here is in fts(3), not in rm(1). If fts_read() aborts the traversal because of a concurrent modification, that is a bug. If a concurrent rm -rf X/Y causes an rm -rf X to abort, this may cause X/Z to escape removal erroneously.

A possible fix is to use the pathnames to go back to grandparent directories if opening ".." fails (as with "..", st_dev and st_ino must be checked). A consequence is that the current directory and fts_accpath in the FTS_DP result will be different (fts_accpath will contain a slash, which it normally doesn't if fts is changing directory). Also, this will not work in deep directory trees with pathnames longer than PATH_MAX.