|Summary:||rm(1) is ignoring more errors than it should in rm_tree(..)|
|Product:||Base System||Reporter:||Enji Cooper <ngie>|
|Component:||bin||Assignee:||freebsd-bugs (Nobody) <bugs>|
|Severity:||Affects Many People||CC:||bdrewery, jilles|
Description Enji Cooper 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 2014-10-04 20:30:44 UTC
So how is this an actual bug?
Comment 2 Warner Losh 2014-10-04 20:31:17 UTC
and don't assign me bugs that I have no interest in fixing,
Comment 3 Jilles Tjoelker 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.