Subject: Re: CRITICAL ** Holes in default cron jobs ** CRITICAL
To: Warner Losh <imp@village.org>
From: Ty Sarna <tsarna@endicor.com>
List: current-users
Date: 12/30/1996 12:28:37
Warner Losh wrote:
> 
> In message <199612300123.MAA01238@nemeton.com.au> Giles Lean writes:
> : I wonder if we're talking about the same things?
> : There were two holes in the original advisory:
> 
> There is a third hole that is likely to be present.  If you create a
> directory structure, say /tmp/foo/etc/passwd, then find will see that,
> and you can then race the rm by then switching foo to be a symlink to
> / so that /etc/passwd gets blown away.

This illustrates something that's bugged me about Un*x-oid systems for a
long time: the lack of any way to get a handle on a file (as distinct
from what open() returns, which is more like a handle on the file's
contents). That would solve many of these problems, by allowing the
lookup operation to be separate, and then allowing unlink() et all to be
used on the handle, with a guarantee that all operations on the handle
will be done on the same file. It does introduce a few new problems, but
I think they're solvable.

Imagine a call handle(char *pathname, int flags), and associated hxxx()
replacements for unlink(), chown(), chmod(), open(), etc.  Then one can
do things like (some error checking elided):

	h = handle(file, DONT_FOLLOW_SYMLINKS);
	if (h >= 0) {
		/* maybe hstat() here to verify we got the
		   file we wanted, check permissions, whatever */

		hunlink(h);

		unhand(h);
	}

unhand() releases a handle. The actual delete would happen there, if
that was the last handle on the file. (Similar to
open()/unlink()/close()). Every fh has an implied handle. This is
vaguely NFS-like, if you want to think of it that way.

This guarantees that nobody can switch symlinks on you in the meantime.
It also logically simplifies the stat() variants (stat() and lstat()
become handle()/hstat()/unhand() wrappers that do or don't set
DONT_FOLLOW_SYMLINKS, fstat() becomes a wrapper for
fh2handle()/hstat()/unhand., etc). It also makes access() (in the form
of haccess()) more useful as well.