Re: updated proposal for cap in elf

Albert D. Cahalan (acahalan@cs.uml.edu)
Mon, 19 Apr 1999 21:38:30 -0400 (EDT)


Y2K writes:
> On Mon, 19 Apr 1999, Albert D. Cahalan wrote:
>> Y2K writes:
>>> On Sat, 17 Apr 1999, Albert D. Cahalan wrote:

>> Nope, this is for a highly secure system.
>
> yes I've read your "Sick Security Ideas" at
> http://www.cs.uml.edu/~acahalan/linux/obstacles.html .
> It sounds like some of them are very draconian indeed.

That is my list of wild ideas. You might notice that the more sane and
standard security features are _not_ on that list. Capability bits,
ACLs, and Mandatory Access Control are not on that list.

>>>> pE == 0000000000000000
>>>
>>> pE should maybe be a little higher so that some of the shell builtins work
>>> like echo 'foo' >> /etc/passwd still work ;->
>>
>> Nope, shell builtins are not supposed to have such power.
>> Admins are expected to use a tool with proper logging and locking
>> when they modify the password file.
>
> I think that the content of the files /etc/passwd etc are beyond the scope
> of the kernel. To the kernel /etc/passwd is just another file. Now to libc
> and several root running programs that may or may not be the story.

Yes, /etc/passwd is just another file. It can be protected by normal access
control, even when an admin tries "echo r::0:0:r:/:/bin/sh >> /etc/passwd".

> You are going to hate what I say next-->
> If you need some program to give special controled and logged access to
> /etc/passwd and friends then you need to mark those binaries as special
> cap-enhanced and then you need to excercise your policy there.

Yes. For an admin, the fI bits are that marking.

> Maybe as part of that policy you augment it with CAP_LINUX_USR0 ...
> CAP_LINUX_USR9 which the kernel could give a sh*t less about. Then you
> could define them as you like. Then you running program could do a few
> checks like is your uid on a list of good people and CAP_LINUX_USR3 is in

This is wonderful.

>>>> The admin is only allowed to do his work via tools that leave an
>>>> audit trail, so his shell only has the above. The shell can't do
>>>> anything at all.
>
> Then don't give them quasi-bits. I'd think that your auditing would record
> the who and what; it should also probably make some decisions based on
> that-- like do nothing he smells funny. caps should specify what a given
> program can do with the kernel not what a given user can do with specific
> contents of specific files.

I think you object to the presence of multiple bits on the file granting
the same power to different users. The system is somewhat ugly.

If bloat were no concern, one could have a different set of bits
for each user on the system. Trying to cut the bloat a bit, one could
have a different set of bits for each group (assuming fewer groups
than users) or role. The draft cuts the bloat greatly, since it
calculates a per-user set of bits from pI, fI, and fP.

>> [...] I think the draft was poorly done, but I think that we
>> should be able to turn off Linux extensions. I'd like to see
>
> Maybe the draft was done badly-- it died did it not;->
> Well obviously both of us seem to not take it super-religiously.

Some people here seem very concerned that a "standard" is being "broken".
Never mind the fact that we are dealing with a withdrawn draft proposal!
Well, I'd like to keep those people happy anyway. I think that there must
be a set of config values that provides the draft behavior.

(this is most likely critical for general acceptance)

>> 1. traditional UNIX
>
> OK don't kill the ability for euid root to do anything.
> caps we don't need no stinking caps-- we got root.
>
>> 2. pure draft standard
>> 3. something that isn't so extreme
>
> I think you read too many extremes into it. CAP_LINUX_ADDUSER_2_ETC_PASSWD
> was never intended. I think the side-effect we are fighting over was never
> intended-- I do concede that I could be wrong about that.
>
>> This works:
>> /* pP_control_config is a global kernel setting */
>> new_pP = fP | (fI & old_pI) | (old_pP & pP_control_config);
>
> Then processes can't control its inheritence on a per process basis.
> expanding our formulas and the drafts you get
> pP'= (fP & x) | (fI & pI) | (pP & pI & fI & pP_control_conf)
> then we get to the rediculas situation where a process is allowing
> inheritence, file is aggreeing, and the parent already has the power so
> why should it not pass the power.

Huh? You added pI and fI where they do not belong.

>> This works:
>> /* old_pm is full for a backwards-compatible root user */
>> new_pP = fP | (fI & old_pI) | old_pm;
>
> again that old_pm term should be constrained by its pP and the inheritence
> flags. Go through the above absurdity reductions and see if you don't
> again get very familiar formulas.

No, it must _not_ be constrained in that way. That would be absurd.

>> The problem: on high-security systems, an admin's shell has an empty pP.
>
> good he isn't permitted to do anything, he has to get his power through
> well controlled binaries, let the power reside with the binaries -- not
> the luser then. Those special binaries are going to have to be carefuly
> written anyway.

In case a buffer overflow is found, only an admin can fully exploit it.
Hopefully the threat of job loss will help the admin resist temptation.

>>> For backwards compatibility fE would have to be non-zero.
>>> Since mv doesn't do many network stuff or change uid, etc it should set
>>> its fI much lower hypothetically 0e4a .
>>> fP should be zero.
>>
>> Sure, fI should be something less and fE would need to match if the
>> /bin/mv command does not support the new security system.
>>
>> The important point is that fI should contain some bits.
>
> Yes it should. The important contrast is that under my new formulas they
> can all be safely set. Under your system you propose that they can grant
> powers under various situations.

In other words, your system makes them useless. They don't work.
You might as well just get rid of fI in that case.

>> Well, this is just broken. It means the admin's shell can do anything.
>> I'd like to support that behavior as an option, not as the only way.
>
> If you don't want the admins shell to have the power, then don't empower
> them plain and simple. Empower the binaries and then be super careful what
> you do in them. capibilities grant raw powers, your binaries should
> enforce policies.

In that case, let's just assume everything is setuid (for real). That is
essentially what you propose. All executables have full power, and they
enforce policies by themselves. I do not think this is safe.

You have to assume that apps are somewhat buggy. Admins are at least
partially trusted, but not 100% trusted. Buffer overflows that normal
users can exploit are worse than ones that only admins can exploit.
If admins were 100% trusted, you could forget about all this screwing
around and just give them all the root password on a normal system.

>>> What about the situation where a user calls a legacy program that was suid
>>> root but now gains stuff from fP but it does some of its work by calling
>>> other programs that still need those privledges?
>>
>> There are several options.
>> 1. The pP_control_config hack above could fix this.
>> 2. Most programs like that are security holes already.
>> 3. Perhaps fE should influence the new pI... (must be an option)
>
> Do not like 1. .. they'd have less power so number 2. would be less of a
> hole and with a little smarting up could be greatly improved.
> Smart programs can influence pI quite effectively as they need to.
> Dumb ones should be rewritten over time. In the mean while they may leak
> but at least they'd be leaking consideribly less.
>
>> Considering option 3, one could have this:
>> new_pI = old_pI | (fE & fE_control_config);
>
> Smart programs can already influence pI in quite a fine-grained manner.
> If dumb ones are leaking(should be less then all caps) then you at least
> happen to have the oppurtunity to correct that.
> Plus you do not really mean that you should use your formula number 3.
> As it seems to only increase pI, exactly opposite of what I think you
> intended.

Nope, that is what I intended. If pI does not increase, the programs
that are run from a privileged app may crash.

You want to go with a weak system, then enhance it as needed.
I want to go full-strength POSIX draft, then weaken it as needed.
When fE_control_config is 0000000... you get full-strength draft.

>>> I don't think anybody should gain power from fI only from pP(heavily
>>> masked by inheritance flags) or fP. It sounds like your pI is a
>>> quazi-permitted bit. I can't do it but this indicates that maybe one of my
>>> children will say I can whereas if not then I could not use it.
>>
>> It is strange indeed. For compatibility, you may wish to assume that
>> unmarked executables have a full fI set.
>
> then your shell has no power, but every joe schmoe binary gets the
> privledges you clearly wanted to protect so dearly.

"you may wish to" --> "the security admin may optionally"

This is full compatibility mode. You can have a powerful shell by
just running a shell. The bits that an unmarked executable gets
are part of what determines whether you get traditional UNIX or
a highly secure system. With 20% of the bits set, you get mid-level
security.

> Blech ugly thats why I
> want to add in the pP term so that children can't willy nilly inherite
> weird stuff that the parents didn't have.

What is pI for then? Normally, pI is used for that purpose.

> I want fI to be purely
> restrictive, you want it to be some mix of restrictive/enabling. We
> already have an enabler in fP and I think it is sufficient.
> The mixed quasi capibilities make me quesy.

fP is not sufficient

I may want to give the "skill" (super kill) program CAP_SYS_RESOURCE
for use by everyone and CAP_KILL for use by admins only. By having
two separate enablers, I reduce the risk that I have to accept.

>>>> No, we need a set of bits (I'll call it "pm") that are always
>>>> added to pP. The set would be 0 for maximum security or normal
>>>> users, and ~0 for an admin on a more normal system. This might
>>>> be help kill off the ugly hack in exec.c that pretends an
>>>> executable has fI and fE full if UID 0 runs it.
>
> I think that should be pP

No, pP generally contains nothing at all. Power comes from pI.

> and I think that you should be able to easily
> lose them when you call children through inheritence masking. I really
> dislike the words "always added". I like those defaults and think can make
> them safe by adding in a extra term so that children gain privledges only
> through a well understand single mechanism.

I see "always added" as an adjustable compatibility feature.

>> Untrusted binaries (marked or not) get a full fI at boot,
>> but this may be reduced system-wide by writing to a file in /proc.
>
> unmarked ones I think should get fI=pP, fP=0, fE=pP'

That really isn't very different from my less-variable choice.

>>>> new_pP = fP | (fI & old_pI) | old_pm;
>>>> if(new_pP & ~old_pM) return -EPERM; /* getting prohibited caps? */
>>>
>>> Why are you getting prohibited caps thats why there is fI?
>>
>> They come from old_pm, the substitute for the UID 0 hack in exec.c.
>> It may be better to reduce old_pm before calculating new_pP instead.
>
> Kludge upon Kludge for dubious benefite. Doesn't the varible explosion
> give some hints?

I don't see much of a varible explosion, but...

Yes, this type of system is complex. Capability lists, ACLs, MAC,
and other related features are all junk. True capabilities are the
only complete solution... but then the whole world breaks.

(that idea was: kill the whole filesystem concept and just pass
around persistent object handles)

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