Re: updated proposal for cap in elf

Y2K (y2k@y2ker.com)
Mon, 19 Apr 1999 08:49:07 -0700 (PDT)


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.
> >> 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.
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.
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
the current pP. I think ID is more important to such a system anyway.
You could set it up so that like group leaders can add and delete users
from their groups but only people in their groups. uid would be the main
control feature. Anyway this is beyond the scope of the kernel it should
exist purely in user-land.
> >> 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.
> > Yes in the old formula it would be 00fffffeff using old formula and your
> > numbers -- I consider that a bug you a feature. Under my system normals
> > don't get special rights, but enhanced users would be able to use caps
> > even in his shell builtins or legacy programs.
> Well, this is bad. 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.
> 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.
so killing the extra term we get:
pP'= (fP & x) | (fI & pI) | (pP & pI & fI )
which again is absurd and should be reduced to one of two ways
pP'= (fP & x) | (pP & pI & fI )
pP'= (fP & x) | (fI & pI)
x is allowed to be implementation defined.
Don't these formulas look familiar?
>
> 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.
> This works:
> /* You can have it all! */
> new_pP = fP | (fI & old_pI) | (old_pP & pP_control_config) | old_pm;
Pluralities above necessities.
> 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.
> > 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.
> 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.
> > 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.
> > 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. 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. 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.
> >> 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 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.
> > What you call pm I call pI & pP which then gets further masked by fI.
> > What would you have for defaults on trusted marked binaries? untrusted
> > marked ones?
> Trusted marked binaries get exactly what they specify.
That sounds good;-> stupid question on my part.
> 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'
marked but untrusted ones should be whatever they care to be however the x
in the draft stand should be set to zero effectively ignoring fP;->
> >> 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?
> >> if((new_pP & fm) != fm) return -EPERM; /* not enough? */
> > That I can see as being potentialy useful.
>
> It helps avoid crashing privileged processes. At the very least,
> users and tech support will prefer "permission denied" over crashes.
> It will most likely stop some DoS attacks and maybe worse.
Yes used sparingly it is good. I think that EPERMing `foo --version` is a
little harse though.

Anyway I am really enjoying all this discussion.

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