Like many people[#1][#2], I have found out that the Linux capability
handling utilities are non-functional, and cannot be repaired because
the kernel deliberately cripples capabilities (they are reset on every
call to execve()). I have found that various people[#1][#2] have
proposed patches to restore working capabilities. However, the matter
seems rather complicted and I would like to understand the full story.
Hours of Google-grepping through the lkml archives has not helped me
very much, so I hope someone can get the history straight.
I understand that Linux capabilities first appared seven or eight
years ago, and in 2000-06 there was a serious fault discovered which
caused a local root exploit through the use of the sendmail problem.
Rading [#3] and [#4], I understand that the problem was this:
When sendmail is invoked by a non-root user, it attempts to drop its
root privileges (which it has because the binary is installed suid)
by calling setuid(getuid()), which, due to the stupidity of
traditional Unix semantics enshrined in the POSIX/SUS standards,
operates differently according to whether the process has
"appropriate privileges" (in which case it sets all its UIDs to its
real UID) or not (in which case it preserves the saved UID); now
under Linux, "appropriate privileges" is defined[#5] as possessing
the CAP_SETUID capability. So if a non-root user manages to execute
sendmail without the CAP_SETUID capability, the setuid(getuid())
call will fail (or rather, not perform as expected), and the genie
is out of the bottle.
However, what I do not understand is precisely _how_ one gets a
sendmail process without CAP_SETUID: for that is the heart of the
problem, and that is where the bug really was. But [#3] and [#4] are
very obscure (and I found nothing conclusive in lkml archives). I
understand that the problem lies in some combination of the
inheritable capability set and the CAP_SETPCAP capability, but I don't
see what that combination is. Certainly removing capabilities from
the inheritable set should not prevent suid root programs from having
them reinstated (in the language of [#6], the suid root bit should
correspond to a full forced set of capabilities), so I don't see what
that has to do with it, and CAP_SETPCAP indeed allows to remove
capabilities from a given process but I don't see how the user could
gain that capability (and indeed if he can then we can expect him to
gain all capabilities very rapidly).
Can someone describe very accurately what the problem was? And why
was it "fixed"[#7] by completely disabling capability inheritance and
also by disabling the CAP_SETPCAP capability? In other words, suppose
I restore CAP_SETPCAP on my system and/or make capabilities fully
inheritable on execve() (that is, just take the logical AND of the
permitted set with the inheritable set, except if the executed program
is suid root, in which case all three sets - permitted, effective and
inheritable - are set to full): what is the security problem in this?
Assuming I want to make capabilities inheritable, is there a
recommended patch for doing so? Alexander Nyberg's patch in [#1]
looks good to me (at least, it seems to do exactly what I want), but
how well has it been tested? Is this something that might eventually
make its way into the official kernel, or is this a no-goer? Also, if
the author happens to read this, I'd like an explanation on the "Is
this a root task that did seteuid before execve? if so it wanted its
effective permissions dropped" comment in cap_bprm_apply_creds().
Thanks!
--
David A. Madore
(david....@ens.fr,
http://www.madore.org/~david/ )
[#1] <URL: http://groups-beta.google.com/group/fa.linux.kernel/browse_thread/thread/f76dcb9447a77c34 >
[#2] <URL: http://groups-beta.google.com/group/fa.linux.kernel/browse_thread/thread/4366e557a75a933d >
[#3] <URL: http://www.cs.berkeley.edu/~daw/papers/setuid-usenix02.pdf >
[#4] <URL: http://www.sendmail.org/sendmail.8.10.1.LINUX-SECURITY.txt >
[#5] I tend to think that the behavior of setuid() is wrong in the
first place, that is, setuid(getuid()) should also change the saved
UID as soon as the effective UID is zero, even if CAP_SETUID is not
set, to make sure that traditional Unix semantics are observed. (More
recent, capability-aware, programs will use setresuid() anyway.) But
that is rather beside the point.
[#6] <URL: http://ftp.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.4/capfaq-0.2.txt >
[#7] I wanted to find exactly on which kernel version the changes took
place. Unfortunately, <URL: http://lxr.linux.no/ > only has major
versions, the 2.2.15->2.2.16 patch is very hard to read, and I have
neither the patience nor the bandwidth to unpack entire kernel trees
on my PC to unravel the full history...
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
On Mon, Aug 08, 2005 at 09:13:06PM +0000, David Madore wrote:
> However, what I do not understand is precisely _how_ one gets a
> sendmail process without CAP_SETUID: for that is the heart of the
> problem, and that is where the bug really was. But [#3] and [#4] are
> very obscure (and I found nothing conclusive in lkml archives). I
> understand that the problem lies in some combination of the
> inheritable capability set and the CAP_SETPCAP capability, but I don't
> see what that combination is. Certainly removing capabilities from
> the inheritable set should not prevent suid root programs from having
> them reinstated (in the language of [#6], the suid root bit should
> correspond to a full forced set of capabilities), so I don't see what
> that has to do with it, and CAP_SETPCAP indeed allows to remove
> capabilities from a given process but I don't see how the user could
> gain that capability (and indeed if he can then we can expect him to
> gain all capabilities very rapidly).
After some more intensive Googling, I found the answer in the archives
of the linux-privs-discuss mailing-list (whose existence I did not
know of):
<URL:
http://sourceforge.net/mailarchive/forum.php?thread_id=1588083&forum_id=25120
>
The explanation from the sendmail team was incorrect: CAP_SETPCAP is a
red herring, it's only about CAP_SETUID, the implementation of the
inheritable set was broken in that it controlled not only capabilities
automatically passed across execve() but also those _gained_ by suid
root programs (contrary to the claim in the sendmail analysis) and,
worse, instead of failing on execve() when the program could not gain
privileges, it proceeded with the capabilities missing. Hence the
catastrophic failure.
This does not tell me, then, why CAP_SETPCAP was globally disabled by
default, nor why passing of capabilities across execve() was entirely
removed instead of being fixed.
--
David A. Madore
(david....@ens.fr,
http://www.madore.org/~david/ )
I do not know of any good reason. Perhaps the few folks who knew enough
to fix it properly didn't feel like bothering; it beats me.
Messing with capabilities is scary. As far as I can tell, there never was
any coherent "design" to the semantics of POSIX capabilities in Linux.
It's had a little bit of a feeling of a muddle of accumulated gunk,
so unless you understand it really well, it's hard to know what any
changes you make are safe. This may have scared people away from fixing
it "the right way". But if you're volunteering to do the analysis and
figure out how to fix it, I say, sounds good to me.
Then again, I'm an outsider. Perhaps someone more involved in the
development and maintanence of capabilities knows something that I don't.
The POSIX specification for capabilities requires filesystem support,
so that each executables can be marked with three capability sets ---
which indicate which capabilities are asserted when the executable
starts, which capabilities the executable is allowed to request, and
which capabilities the executable is allowed to inherit from its
parent process. This effectively takes a single setuid bit and splits
it into a hundred-odd bits.
This was never implemented for a number of reasons. (1) When the
capabilities support was first merged, extended attributes support
wasn't in any of the filesystems currently integrated, which is a
prerequisite for storing the capability masks on a per-file basis.
(2) There was some debate about whether or not this method was the
course of wisdom, which has probably decreased the enthusiasm for
actually doing the remaining bits of work.
The basic concern with this is that usability experts have shown that
most users have trouble with the 12 bits of the Unix permissions
model. Splitting a single setuid bit into 100-odd bits makes the
manageability problem much, much harder. Note that many some setuid
programs don't necessarily check error returns, and sometimes turning
off permissions can sometimes open up vulnerabilities.
(For example, this wasn't directly related to POSIX capaibilities, but
way back when, one version of Ultrix caused setuid() to return EPERM
if the uid was greater than 32,000 decimal. This was probably caused
by a clueless library implementor implement some specification which
stated that the uid had to be less than 32k. We discovered this
problem at MIT Project Athena when users with uid's above 32,000 would
get root privileges when they logged in, because /bin/login at the
time didn't check the error returns of setuid(), since _obviously_
when root calls setuid(), it never fails, right?)
Another problem with the POSIX capabilities is that most of the
programs that system administrators run to look for setuid programs
will miss programs that have capabilities encoded in extended
attributes. This problem could be fixed by requiring the setuid bit
to be set before paying attention to the capability EA's; but this
could lead to surprising results if the filesystem is mounted on a
system that doesn't use filesystem capabilities at all.
Yet another issue is that the POSIX capabilities model means that a
default executable, such as gcc for example, is not allowed to inherit
_any_ capabilities, even if it is run from a setuid root shell. This
is good from a security point of view, since it means that people
can't get in trouble by doing silly things like typing
"./configure;make" as root and expect any of the build tools to have
override arbitrary file controls. The bad news is that system
administrators aren't particularly happy when their own private tools
have to especially marked to allow them to run with elevated
privileges.
- Ted
Should we be thinking about deprecating and removing capabilities from
Linux?
- James
--
James Morris
<jmo...@namei.org>
You point out various reasons why the POSIX (draft-)specification is
problematic. But nobody says Linux has to abide it, especially as it
is a mere withdrawn draft. Solaris 10 has capabilities (except that
they're called "privileges") which are similar, but not identical, to
the POSIX ones.
And even capabilities with no filesystem support can be useful. In
fact, as far as I see it, the main interest in capabilities lies in
the "process management" part. For example, I might like to run this
or that binary, which claims it needs to be run as root, with a
limited set of capabilities: the current Linux kernels make this quite
impossible. Conversely, I might wish to give a particular capability
to a given user; in association with sudo, this might be quite useful:
instead of telling sudo to let the user run a given command as root,
just let him run a capability-aware wrapper which drops every
capability except the required ones and then calls the actual program
- so even if the latter is not secure, damage is more limited. I can
think of thousands of other uses not requiring any kind of filesystem
support.
> Note that many some setuid
> programs don't necessarily check error returns, and sometimes turning
> off permissions can sometimes open up vulnerabilities.
Yes, the sendmail vulnerability proved this quite clearly. So
certainly a luser should not be permitted to run a suid root program
with anything in between the empty set and the full set of
capabilities.
> Another problem with the POSIX capabilities is that most of the
> programs that system administrators run to look for setuid programs
> will miss programs that have capabilities encoded in extended
> attributes. This problem could be fixed by requiring the setuid bit
> to be set before paying attention to the capability EA's; but this
> could lead to surprising results if the filesystem is mounted on a
> system that doesn't use filesystem capabilities at all.
I might suggest encoding the presence of capabilities by a sgid bit
for a specific group (say, wheel) on top of the extended attributes.
So the careful sysadmin will notice the programs (because sgid wheel
is significant enough to be noted) but it will not cause total
disaster if mounted on a non-capability-capable ;-) filesystem.
> Yet another issue is that the POSIX capabilities model means that a
> default executable, such as gcc for example, is not allowed to inherit
> _any_ capabilities, even if it is run from a setuid root shell. This
> is good from a security point of view, since it means that people
> can't get in trouble by doing silly things like typing
> "./configure;make" as root and expect any of the build tools to have
> override arbitrary file controls. The bad news is that system
> administrators aren't particularly happy when their own private tools
> have to especially marked to allow them to run with elevated
> privileges.
Yes, this seems like a reason to deviate from the POSIX model under
Linux.
--
David A. Madore
(david....@ens.fr,
http://www.madore.org/~david/ )
> the "process management" part. For example, I might like to run this
> or that binary, which claims it needs to be run as root, with a
> limited set of capabilities: the current Linux kernels make this quite
> impossible.
Not impossible with SELinux.
- James
--
James Morris
<jmo...@namei.org>
Ts'o wrote:
>since _obviously_ when root calls setuid(), it never fails, right?
Well this really depends on how privileged a certain root user (think of
SELinux and others) is.
>(2) There was some debate about whether or not this method was the
course of wisdom,
James Morris wrote:
>Should we be thinking about deprecating and removing capabilities from
>Linux?
My one half says no. But it needs reworking. Just look what I had to do
with the linux source code in order to get this
< ftp://ftp.gwdg.de/linux/misc/suser-jengelh/multiadm-1.0.tbz2 > to work as
intended - I had to poke really hard on caps stuff to get this module done.
And my other half says yes, because it's ironically to give a user all caps
and then limit a certain user's permissions using LSM hook functions. So in
effect, if you wanted root accounts of varying powers, all of them would need
some - or even all - caps so that the code flow can reach the security_*()
functions at all, because capable() is done before security_*(). So to get to
security_*(), caps must be enabled, which turns a
if(!capable(CAP_DAC_OVERRIDE)) return;
into, effectively,
if(0) return;
With regard to _this_, I think it would be best to kill the cap checks, and
let a security_* function handle it, in the style of "security/traditional.c".
Jan Engelhardt
--
-- Christopher Warner
On Tue, 2005-08-09 at 00:46 -0400, James Morris wrote:
> Let me play the Devil's advocate here.
>
> Should we be thinking about deprecating and removing capabilities from
> Linux?
>
>
> - James
-
One brief suggestion:
A key/token interface was recently introduced that might be useful to
allow
a simple new inheritance model for "capabilities", "roles",
"rootperms" or
whatever other abstraction you create.
Cheers,
Kyle Moffett
--
There are two ways of constructing a software design. One way is to
make it so
simple that there are obviously no deficiencies. And the other way is
to make
it so complicated that there are no obvious deficiencies. The first
method is
far more difficult.
-- C.A.R. Hoare