Subject: Re: Addition to force open to open only regular files
To: None <tech-kern@netbsd.org>
From: Greg A. Woods <woods@weird.com>
List: tech-kern
Date: 11/20/2000 15:06:00
[ On Monday, November 20, 2000 at 15:37:48 (+0100), Wolfgang Solfrank wrote: ]
> Subject: Re: Addition to force open to open only regular files
>
> > In the case of $HOSTALIASES and rewind tape devices it would in effect
> > prevent the library routines using $HOSTALIASES from accidentally
> > opening a tape device when called from a set-ID process where the
> > current effective-ID was permitted to open that device.  I.e. the
> > library would do something like:
> > 
> >   fd = open_as(getenv("HOSTALIASES"), O_RDONLY, (mode_t) 0, getuid());
> > 
> > and since the tape device wouldn't normally be accessible by the real
> > user-ID, the call would fail with EPERM.
> 
> But since you need to know the user-ID to give to open_as as argument,
> I ask again, what is different to a seteuid(getuid()); open(...); setback();
> sequence?  Especially, the argument, that you could have swapped the
> uids with another call to seteuid() doesn't count, does it?

The difference is in whether or not code in the process can ever run as
the privileged user again.  With open_as() the ID-swapping feature would
be permanently disabled in the kernel.  The remaining use of the
seteuid() call would be just to make the process run as the real-UID but
not to affect the saved-set-UID [as setuid() would], and thus the
process would then only be able to open files as if it were still
running as the effective user.  I.e. after calling seteuid(getuid())
you'd only be able to call open_as() with the old effective-IDs, which
would be the same as the saved-set-IDs [or with the real-IDs, but that
would be a no-OP over a plain open()].

The main appeal of open_as() over other solutions is that it elegantly
solves both the above problem of accessing files as the effective-ID
without allowing ID-swapping and without running great gobs of code as
the effective-ID, while at the same time also allowing longer-running
set-ID processes to avoid the race conditions inherent in access(2).

Note I snuck a potentially controversial requirement in here --
i.e. that implementing open_as() implies removing ID-swapping.  The
reason I say this is a requirement is for the very reason you ask what
difference open_as() would make over seteuid() since it would indeed
make no difference without completely removing ID-swapping.

Open_as() would still fix the race conditions of access(), even without
affecting ID-swapping, of course, so it seems to be a good idea no
matter where you sit on the fence.

> Again, I don't see what this would buy us.  Can anyone explain what
> separate credentials for filesystem calls would be of use for?

I agree that FS-ID credentials wouldn't be terribly beneficial.  They
might be a bit safer than UID-swapping (i.e. again implying either one
or the other is allowed to exist) because then you could be sure that
the process could never regain its full privileges [eg. it could never
exec(/bin/sh) after suffering a buffer overflow].  It's just a single
brick though -- it doesn't build a real wall.  The cracker need only
find a path to higher privilege through modifying files that FS-IDs
would give him or her access to.

> Hmm, what about doing all accesses to the file in question via the child
> process?  I.e., why does the parent itself have to have an FD for the file
> at all?

In smail-3 it would be a fairly major re-design to make it work that
way.  Even better would be to require a separate set-ID-root program to
open the file and hand the data back (or re-exec() smail after opening a
protected file or socket).

> BTW, people keep arguing that a problem with using these library
> functions is that they cannot rely on the caller to not have switched
> the user (or group) ID before calling the library function.  Huh?
> Just document it that the caller mustn't call the function with switched
> IDs and be done with it.  It sure isn't possible for the average user
> to switch IDs and cause library functions to be called arbitrarily in
> an executable he doesn't own, or is it?  And if it is, you are lost
> anyway, are you not?

I can't disagree with that.  The only problem is that this kind of
change is to an existing API, and since it could have serious
implications this suggests that either all existing uses must be audited
before the change is made, or that a new interface be provided under a
new name and that the existing interface be deprecated in favour of it.
Either way is "hard" even if you only consider code that might be in
set-ID programs because the person making the change does not, almost by
definition, have control over all the code that uses the API being
changed.

-- 
							Greg A. Woods

+1 416 218-0098      VE3TCP      <gwoods@acm.org>      <robohack!woods>
Planix, Inc. <woods@planix.com>; Secrets of the Weird <woods@weird.com>