Features Download
From: Casey Schaufler <casey <at> schaufler-ca.com>
Subject: Re: [PATCH 00/21] Permit multiple active LSM modules
Newsgroups: gmane.linux.kernel.lsm
Date: Monday 7th February 2011 17:00:45 UTC (over 7 years ago)
On 2/7/2011 7:00 AM, David Howells wrote:
> Casey Schaufler  wrote:
>> I have an LSM that I call Glass which is not so much a stacker as
>> a composer of other LSMs. The Glass security blob is an array of
>> pointers, one for each available LSM, including commoncap, which
>> is always in the last slot. The Glass LSM is always registered first.
>> As subsequent LSMs register they are added to the glass LSM vector.
> It sounds you're proposing a very similar thing to what I'm proposing,
but at
> one level of indirection more.

I don't know that I'd characterize it as an addition level of indirection,
but I suppose that it isn't too far off.

>> When a hook is invoked glass goes through its vector and if the
>> LSM provides a hook it gets called, and the return remembered.
>> If any other LSM provided a hook the commoncap hook is skipped,
>> but if no LSM was invoked commoncap is called.
> I found that there wasn't a single good iteration method that would cover
> the operations.  I ended up having to have several different iteration
> and even had to split a couple of operations.  It's very much a
> thing.

I would like to take the going in position that LSMs should be in line
with the iteration method that is appropriate to a given hook. If there
is any hope of maintaining generality hooks need to be able to maintain
state, which means that either the hooks all need to get called every
time or they need to indicate that they can be skipped, which would
require checking. I do not think that we can assume that future LSMs
will use any given hook in the same way it has been used in the past.

My dreaded case is an LSM that bases controls on statistical frequency
of access to files. There is no way you could skip any of its hooks,
and I don't see off hand any file access hook it wouldn't use. I have
heard people (think credit card companies) suggest such things, so
although I don't have use for it I can't discount the potential for it.

> In most cases, if you call commoncap first, you can remove the commoncap
> from all the other LSMs - which simplifies things.

Or you put the commoncap into the infrastructure and pull it from the
LSMs. My approach is to assume that one or more existing LSMs have taken
care of that and only call the commoncap (none of which are state
maintainers) if there is no other hook.

>> My approach is to leave file->security alone, but to wrap its use
>> with a simple function
>>     fsp = file->security;
>> becomes
>>     fsp = glass_get_file(file, GLASS_SMACK);
>> where glass_get_file(file, lsm) is little more than
>>     struct glass_blob *gp = file->security;
>>     return gp->glass_blob[lsm];
> And you said *my* approach was heavy-handed;-)

This is actually very similar to what you did with credentials.
That's where I got the notion that it might be acceptable, at
any rate. The LSM that gets worked over most heavily by this is
Smack, and the Smack maintainer can probably be convinced that
it's not too terrible.

> I presume there would be equivalent functions to set the pointer too.

Yes. The glass_set functions are a little harder to work in because of
the occasional case where functions are passing addresses of blob

>> Blob management can get kind of hairy. I for one would not want to
>> wrap my brain too tightly around an LSM that relied heavily on
>> caches of secids. I don't think that anyone should be trying to
>> outwit the LSM designer on this.
> It's not really any different to your approach.  You provide them with a
> fixed-size blob that happens to be 'void *' in size.  They don't get a
> and they have to allocate any additional bits they want themselves.

Which is exactly what I'm doing and provides the current LSM interface.

> I'm giving them a little more leeway - that's all.

It's leeway that they don't have today. All existing LSMs (upstream or
not) manage their own blobs from pointers.

> One disadvantage of my approach is that I have to look up the offset to
add on,
> whereas for you it's supplied by the caller.  One disadvantage of your
> is that you have to allocate pointers for every LSM - whether they're
going to
> be used or not - as that's a compile-time determination, and you have to
> allocate a pointer for an LSM that won't even use it, even if it is

Yes. I have thought about compressing the vectors at registration time.
It would require some clever to get right, but I doubt that it would be
especially difficult to get working if it didn't have to be perfectly

> I'm not sure why you mention caches of secids - that's nothing
particularly to
> do with it as far as I can see.

Just that I don't understand and don't want to understand the intricacies
blob management as practiced by individual LSMs. A blob that includes a
that grows over time, for example, is one that I believe the infrastructure
wants nothing whatsoever to do with. I believe that providing this leeway
trivial if any value. I also believe that it could result in complexity in
the blob management for everyone that benefits a very few.

>> I would call all of these premature optimizations.
> Not really.  They are something that I was able to claim after doing the
work -
> they weren't the intent of the work.  It was a case of looking to see
what else
> it gained me.  The "optimisations" are a consequence of the approach.

Fair enough. I'll say then that I don't find the approach that appealing.
And how I mean that is that the approach gives higher value to certain
edge cases than it does to the general case.

>>> With your suggestion above, how do you handle just having a single LSM
>>> module active?  Do you still have to go through two pointers?  Or do
>>> have some conditional branches to skip one pointer under some
>>> circumstances?
>> With Glass being itself an LSM I can take advantage of the compile time
>> nature of the interface. If Glass is not configured the implementation
>> of glass_get_file becomes:
>>     return file->security;
>> which is what it was originally, minus the obfuscation.
> What about if it's not a compile-time selection?  Can Glass just get out
of the
> way?

The current implementation would not, because you still have to do
certain things like secid/sectxt management. Recall the discussion
on /proc/self/attr/current, where I would wrap the context with
information about the LSM. Instead of Smack producing "_" Glass would
produce "(smack=_)" where Smack+AppArmor might have
"(smack=_,apparmor=Unconfined)". As you see (and this might make a dandy
argument against the merged "context") this would require that the
reading application handle two different formats, and it couldn't
use the presence or absence of Glass to determine which to expect.
This could be a problem even with a /proc/self/attr/current-
scheme as well, unless the LSMs all get rolled to use the new
path all the time.

>> Think "Personal PIN Number for the Automated ATM Machine".
>> The LSM framework supports Linux Security Modules (LSM).
> I presume you aren't talking about using this on an actual ATM...

Would you have ATMs run WinCE instead?

One use where I see multiple LSMs being heavy deployed is the
financial world, where it does not make sense to try to combine
the various legally required policies into a single entity.

> David

To unsubscribe from this list: send the line "unsubscribe
linux-security-module" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
CD: 3ms