Subject: Re: funlink() for fun!
To: NetBSD Kernel Technical Discussion List <tech-kern@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-kern
Date: 07/11/2003 16:48:54
>>> If all one is trying to do is flesh out the set of f*() system
>>> calls which have file descriptor parameters to make it orthogonal
>>> to the set which have pathname parameters then
>> ...you shouldn't do funlink() in this form in the first place, as
>> unlink() is not an operation on a file but an operation on a link to
>> a file.
> But that's the whole point of funlink() (and perhaps even some of the
> other f*() calls, such as fchdir()) -- turn an operation on a file
> into an operation on a filename (i.e. a link to a file).

Not quite.  chdir() operates on a process and a directory; the pathname
is necessary only to identify the directory.  It could equally well
identify the directory by a file descriptor open on it, and that's
exactly what fchdir() does.  truncate() operates on a file; the
pathname is used merely to find the desired file.  It too could equally
well identify the file by a file descriptor open on it, and that's
exactly what ftruncate() does.

However, unlink() does not operate on a file, except as a side effect;
it operates on a link to a file.  The file is affected, sometimes very
mildly, sometimes severely, but the critical point is that the pathname
is not serving just to locate the file, but rather to locate a
particular link to the file.  Since file descriptors are on files, not
on links to files, funlink() doesn't really make sense.

>> Now, an funlink() that takes an fd on a directory and a (slashless)
>> component name, that would be a sensible way to add an fd-based
>> variant of unlink().
> If the process has an FD open on the parent directory then it should
> be able to much more easily just fchdir() there first, obtaining and
> keeping an open FD for its PWD for those cases where it has to go
> right back to where it started.

Yes, it should be able to.  But since you can't open "." if your
current directory is execute-only, it can't.  (It'd also be nice to be
able to do one syscall (funlink of this flavor) instead of three
(fchdir, unlink, fchdir).)

> For other uses (such as unlinking stdin) such a form would be
> unusable, and after all the goal is to define a system call that
> accepts a file descriptor and acts upon the file that was opened in
> the same way as the s/^f// system call would act when passed a
> filename referring to the same file that was opened.

Which is why you can't do funlink(), because unlink doesn't operate on
files; it operates on links to files.  The file is operated on only in
that it's garbage-collected once it's no longer referenceable.  (Which
may be when its refcount goes to zero, or it may be an indeterminate
time later.)

> I've always though the only extremely serious omission in the f*()
> function call set has been faccess()

It doesn't really make sense, unless you also add fopen() (which name
has unfortunately already been preempted by stdio), to re-open a file
with potentially different access rights.  Otherwise, faccess() doesn't
tell you anything of use.

> (and of course there should not have ever been an access() call since
> it is inherently insecure);

How so?  Provided you realize what it does, and more importantly what
it doesn't do, there's nothing wrong with it.  (In particular, access()
with F_OK is useful to non-setid programs.)

> It could also be very useful for secure programming if we had an
> O_MKDIR flag for open() that would [combine mkdir() and open()].
> O_MKDIR may even eliminate enough of the cases where you'd use your
> O_NOACCESS to make O_NOACCESS strictly unnecessary.

No, it wouldn't.  You still couldn't save and restore your current
directory by opening "." and fchdir()ing back there if your current
directory is execute-only, even with O_MKDIR, without O_NOACCESS.

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B