[LWN Logo]

Date:	Thu, 15 Apr 1999 18:34:19 -0400 (EDT)
To:	pavel@atrey.karlin.mff.cuni.cz
Subject: Re: caps in elf headers: use the sticky bit!
From:	tytso@MIT.EDU

   Date: 	Wed, 14 Apr 1999 22:41:44 -0400 (EDT)
   From: "David L. Parsley (lkml account)" <kparse@salem.k12.va.us>

   Well, I think Ted freely exercises his right to ignore us. ;-)

No, it's because I've been travelling --- some of us have real jobs
and can't afford to engage a debate which is taking up a huge amount
of the bandwidth on linux-kernel at the same level of intensity that
you all have been using.  (Which is a polite way of saying, "Wow, you
all have been flaming a lot" :-)

I have been tracking the debate, and let me try to send one huge
message which answers a few arguments, tries to summarize where I
think every one is at in this debate, and to give some recommendations
about how I think we should resolve things.

   Date: Wed, 14 Apr 1999 16:03:25 +0200
   From: Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>

   I do not see why setting inheritable set should be privileged.

   In traditional unix, every utility has inheritable set set to FULL by
   default. I do not think it is good idea to change that.

I have to disagree; making inheritible set to be NULL by default, and
only allowing someone with privileges to set the inheritable set is
extremely important.

Consider that there are many security holes in Unix which are caused by
the fact that by default processes inherit full privleges.  For example,
consider the old security problem where /usr/ucb/Mail used the "more"
pager, and you could cause "more" to cause a shell to be executed by
using the '!' command to more.  Since /usr/ucb/Mail used to be setuid
root, you could get a root shell that way!  Oops.  This has been fixed
in modern Unix systems, but shows that you have to be extremely paranoid
when you write setuid programs, less you fall into similar traps.

The problem here is that /usr/ucb/Mail was a program where the author at
least knew that it was supposed to be installed setuid, and so he could
take care.  However, the author of the "more" program probably never
considered that it was a security sensitive program, and should take
special measures before deciding whether or not to allow the '!' command
to work.  Since "more" wasn't designed to be a high-security program, it
should never inherit setuid privileges or capabilities.  

The problem was solved in /usr/ucb/Mail by changing it do drop
privileges before forking "more", but it only takes one programmer to
forget to do that, and your goose is cooked.  So in a full capabilities
system, by default processes do not inherit capabilities.  In effect,
the drop of privileges is done automatically.  This is a good thing.

Also note that because of this it means that a lot of executables will
have capability sets --- including programs like cp and rm, if you
want a system administrator with a privileged shell to be able to run
cp and rm and have them inhert the capabilities of the privileged
shell process.  As a result, this completely rules out the setuid root
idea, because although cp and rm might not have any "forced"
capabilities, they would have some number of "inherited" capability
sets, and the ***last*** thing you want is for cp and rm to be setuid
root if you boot a non-capability aware kernel.

Face it, using a full capability system is a completely different
security model; it's different from the traditional Unix model.  But
that's OK.  I don't expect everyone to immediately switch to it; it will
take a lot of time.  In fact, I don't think it will ever see widespread
use until some distribution makes it an option and works out all of the
system administration issues.  



Which brings us to the question of what people mean by "capabilities".
There are at least three definitions of "capabilities" floating
around.  The first is the one which Andrej Presern asks for, which is
the academic C.S. definition of "capability".  This is the model where
all accesses are mediated by magic tokens which are called
capabilities, which can be passed around between functions and between
programs/processes.  In order to actually gain access to a file, you
have to present a capability which gives you the right to read it.
This means that the open system call would require a new argument,
which would be the "capability".  Your user id has no meaning, and
there is no "capability set" associated with a process.  This is
actually a very nice model, since it means that there is no implicit
set of privileges associated with your process.  Instead, all accesses
are mediated via explicit use of capabilities for which your process
has access, and the application program has to explicitly select which
capability (out of potentially dozens or hundreds) it might have when
it calls each and every system call.

The only problem with this model is that it is hopeless impractical.
It involves making a completely change to the entire POSIX API, and a
system which used this would not be able to use any of the programs
ever written for Unix or POSIX systems, since it requires a change to
the fundamental OS API.  So, no one besides Andrej has ever agitated
for this kind of "capabilities", and this is indeed something for
which you might as well rewrite Linux from scratch, and it will fail
since none of the existing Unix tools could be trivially ported to it.


The second model of "capabilities" is the one which folks like Pavel
have argued for, and which I will call "capabilities lite".  The
argument here is for something which doesn't require making any
changes to tar, cp, or any filesystem specific changes.  The main goal
is to solve the setuid root executable problem, but taken to its
logical extreme, this model only makes sense if you still have a root
account and you don't support the "inherited" capabilities set.  That
is, by default, all processes still inherit the capabilities of their
parents across exec()'s.  This has some of the advantages of the "full
capabilities" model (described below), but it is a pale, castrated
model of the full POSIX capabilties design.  The main argument for
adopting this seems to be as a short-cut, and possibly because some of
the proponents may not understand all of the advantages of the full
capabilities model.


The final model is the one that I and others who have been involved
from the linux-privs project from the beginning have been argueing
for, and that's the full capabilities model as worked on by the POSIX
subcommittee.  This model at its fundamental core does require making
changes to the filesystem, and to programs like tar.(*) It also does
require making fundamental changes in how a system is configured, and
administered, and how system administrators go about their daily
business.  I expect at least at first, people will only use
capabilities in the "capabilities lite" mode.  That is, they will
simply only give sendmail the few limited privileges it needs, and not
actually try to make root go away.  But I think it's really important
that we not completely rule out the full capabilities model as
originally envisioned by the POSIX subcommittee.  It has a lot of
advantages that the "capabilities lite" model doesn't have, and it's
basically as far as you can take capabilities while still being true
to the fundamental Unix design.  It may not be as far as Andrej would
like, but it's as far as you can practically go.



So, given that, what do we do?  I think we should strive for the full
capabilities model as enviisioned by POSIX.  Yes, it's more work, but
at the end of the day, you end up with a much great set of advantages.
It also allows us to be compatible with other Secure OS's that have
been implemented, and with the POSIX standard if/when it ever gets
revived and completed.

The main thing that had been holding up the full capabilities folks
had been the necessary ext2 changes so that you could store the
capabilties information in the the filesystem, attached to the file.
This is what Secure Solaris and Secure HPUX does, and it's what the
POSIX draft clearly assumed how this would be implemented.  The
problem was that doing this in a clean way is non-trivial and Stephen
and I both haven't had the time to take the initial set of patches
which tried to implement this and clean them up.  This is our fault,
and those folks who came up with the hack of storing them in the ELF
headers was trying to get around the fact that we couldn't get support
into the ext2 filesystem quickly enough.  Fair enough.

What I would suggest is either using a combination of the sticky bit
plus the immutable flag, *or* define a new ext2 flag which means "this
file has capability information".  The second is probably the better
choice, and since it's only a bit in the flags word, it's easy enough
to implement.  Now, people will inevitably complain that this means
you can't use other filesystems.  That's correct.  And I think, that's
OK.  As I mentioned, all of the other Secure OS's that have done this
have assumed filesystem support.  And you wouldn't want to use
capabilities over NFS anyway, since NFS stands for No File Security.
People who use capabilities are generally serious about their
security, and it's easy enough to corrupt an executable going over the
network via NFS to insert an attacker's trojan horse code.  So running
setuid programs over NFS is a *really* bad idea to begin with.

By using a special ext2 flag meaning "there be capabilities here", and
using the ELF header hack, it means that you do allow a program to be
setuid daemon as well as having capabilities; and it allows you to
build a system with the full set of capabilities in the POSIX
capabilities models.  It does mean that we will need to extend some
tools and build a few new ones.  In addition to writing a setuid
scanner, we will need to write a capability scanner.  But in the long
run, I think the extra effort will be worth it.

							- Ted


(*) Secure HPUX has a very clever way of hiding the capabilities
information in a tar file such that non-capability-aware tar programs
can still read tar files with capability information.  Basically, the
capability information is stored in the tar file first, with a flag
marking it as containing capability information, and with the same
name as the file for which the capability information is for.  It is
then followed by the actual data contents of that executable.  A
non-capability aware tar program doing an extract of that tar file
will ignore the flag indicating the contents of the capability
information, write the capability information as a file to disk, and
then when it sees the second file record, it overwrites the first file
with actual data contents of the file, since it has the same name as
the first.


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/