Re: Bug in how capability inheritance is handled in "fs/exec.c", 2.3.99

From: David L. Parsley (parsley@roanoke.edu)
Date: Tue May 30 2000 - 10:02:42 EST


After following this thread for a bit, I've got one burning question:
What are the formulas for computing the capability sets of a new process
in Trusted IRIX? I've also got a copy of Draft 17 (thanks, Casey!), and
I'm quite pleased with:

pI' = pI (& fM (*)) ; pP' = fP | (fI & pI) ; pE' = pP' & fE

I'm confident that a good distro can be built on the principle of least
priviledge using this model, and with the addition of fM (which I'll
explain) it can be done without modifying code for every binary, and
without having to run every program through a wrapper.

* fM is be an additional set stored in the filesystem to improve
behavior for non-capability aware binaries (which we know will be the
rule, not the exception, for a LONG time). It's just a mask to
constrain the passage of the inheritable set from parent to child, where
a cap-aware program would just drop the bits it doesn't need.

The essentials of this model are these: 1) A given process should only
have the pP/E bits it needs to function for the syscalls it will make.
2) A given process should only have pI bits to enable the proper pP/E
bits in it's children such that 1 applies.

This model maps to the current model essentially like this:

(current) a root-owned shell exec's a normal binary, binary 'inherits'
root's capabilities (all)
--> (future) a shell with PIE=(0,some,0) exec's a normal binary, binary
inherits some of I
(*Note: I couldn't think of an example where the shell itself would need
any P/E bits set)

(current) a user shell exec's a setuid-root binary, binary runs with
root capabilities (all)
--> (future) a user shell with PIE=(0,0,0) exec's a binary with P=(some
bits), binary is able to do it's job

Now a couple of abstract examples...

For these examples, I'm only going to deal with a few abstract
capabilities.
capA, capB, capC, capD expressed as a set (ABCD), e.g. (0010).
pPIE=(XXXX,YYYY,ZZZZ) gives the Permitted, Inheritable and Effective
capability sets for the current process.
fPIEM=(WWWW,XXXX,YYYY,ZZZZ) gives the same for the file, plus the
inheritable Mask as described above.

Ex. 1) The kernel starts 'init', 'init' starts 'imapd', 'imapd' uses
'imapauth' authenticate users. 'imapd' needs P=1000 to do it's job,
'imapauth' needs P=0100.

init pPIE=(0000,1111,0000) exec's /sbin/imapd
fPIEM=(0000,1000,1000,0100):
pI' = pI & fM = 1111 & 0100 = 0100
pP' = fP | ( fI & pI ) = 0000 | ( 1000 & 1111) = 1000
pE' = pP' & fE = 1000 & 1000 = 1000

==> pPIE(imapd)=(1000,0100,1000) satisfying 1 & 2 above; it only has the
P/E bit it needs to operate, and the only 'I' bit is the one needed in
'imapauth':

imapd pPIE(1000,0100,1000) exec's /sbin/imapauth
fPIEM=(0000,0100,0100,0000) ==> pPIE(imapauth)=(0100,0000,0100);
imapauth only has the bit it needs to do auth, and won't by default pass
any 'I' bits to it's children. (though with syscalls it could raise 'I'
bits to a ceiling imposed by P).

NOTE: this scenario takes advantage of the fact that 'I' need not be a
subset of 'P', as specified in the draft.

Ex. 2) A user is using the 'chown' binary to modify file owners/groups.
With capC (P=0010) 'chown' can change the owner. The user shell process
is bash pPIE=(0000,0011,0000); this user carries two capabilities in her
inheritable set, only one of which is needed for this example.

bash pPIE=(0000,0011,0000) exec's /bin/chown fPIEM=(0000,0010,0010,0000)
==> pPIE(chown)=(0010,0000,0010).

So the user logs in with certain capabilities, and the programs used
only inherit those they need.

Now, I REALLY LIKE this model. As a system administrator, I can see a
straight path to using this model to vastly improve system security in a
clear, understandable manner (at least by me, and I hope you too, now
;-). The only improvement I can imagine is to further carry fM into a
pM, such that pI is bounded by pP & pM. Why? Because in a buffer
overflow situation, you don't want the cracker to be able to trivially
raise pI up to pP and then exec /bin/bash with a greater pI' that what
is needed by 'legitimate' children of p.

I'll assert that the above described model is the closest we could come
to a 'principle of least priviledge' model without modifying the code of
every setuid and root-run binary on the system. This also has the side
effect of putting more power into the hands of the system administrator
at the expense of the programmer, which I also like.

Comments?

        David

-- 
David L. Parsley
Network Administrator
Roanoke College

- 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/



This archive was generated by hypermail 2b29 : Wed May 31 2000 - 21:00:24 EST