rm(1) bug, possibly serious

Bruce Evans brde at optusnet.com.au
Wed Sep 26 13:42:00 PDT 2007

On Tue, 25 Sep 2007, LI Xin wrote:

> I think this is a bug, here is a fix obtained from NetBSD.

This bug, if any, cannot be fixed in rm.

> The reasoning (from NetBSD's rm.c,v 1.16):

Bugs can easily be added to rm.

> Strip trailing slashes of operands in checkdot().
> POSIX.2 requires that if "." or ".." are specified as the basename
> portion of an operand, a diagnostic message be written to standard
> error, etc.

Note that POSIX only requires this for the rm utility.  (See my previous
mail about why this is bogus.)  Pathname resolution and a similarly
bogus restriction on rmdir(2) requires some operations with dot or
dot-dot to fail, and any utility that uses these operations should
then print a diagnostic, etc.

> We strip the slashes because POSIX.2 defines basename
> as the final portion of a pathname after trailing slashes have been
> removed.

POSIX says "the basename portion of the operand (that is, the final
pathname component".  This doesn't mean the operand mangled by

> This also makes rm "perform actions equivalent to" the POSIX.1
> rmdir() and unlink() functions when removing directories and files,
> even when they do not follow POSIX.1's pathname resolution semantics
> (which require trailing slashes be ignored).

Which POSIX.1?  POSIX.1-2001 actually requires "trailing slashes shall
be resolved as if a single dot character were appended to the pathname".
This is completely different from removing the slash:

   	rm <regular file>/		# ENOTDIR
   	rm <regular file>		# success unless ENOENT etc.
   	rm <directory>/			# success...
   	rm <directory>			# EISDIR
   	rm <symlink to regular file>/	# ENOTDIR
   	rm <symlink to regular file>	# success (removes symlink)
   	rm <symlink to directory>/	# EISDIR
   	rm <symlink to directory>	# success (removes symlink)
   	rmdir ...			# reverse most of above

Anyway, mangling the operands makes the utilities perform actions different
from the functions.

The problem case is "rm -r <symlink to directory>/" which asks for
removing the directory pointed to by the symlink and all its contents,
and is useful -- you type the trailing symlink if you want to ensure
that the removal is as recursive as possible.  With breakage of rmdir(2)
to POSIX spec, this gives removal the contents of the directory pointed
to be the symlink and then fails to remove the directory.  With breakage
as in NetBSD, this gives removal of the symlink only.

> If nobody complains about this I will request for commit approval from re at .



More information about the freebsd-stable mailing list