Re: [PATCH 00/21] Permit multiple active LSM modules
[Posted February 9, 2011 by jake]
| From: |
| Casey Schaufler <casey-AT-schaufler-ca.com> |
| To: |
| David Howells <dhowells-AT-redhat.com> |
| Subject: |
| Re: [PATCH 00/21] Permit multiple active LSM modules |
| Date: |
| Thu, 03 Feb 2011 10:06:22 -0800 |
| Message-ID: |
| <4D4AEE9E.3090400@schaufler-ca.com> |
| Cc: |
| penguin-kernel-AT-i-love.sakura.ne.jp,
linux-security-module-AT-vger.kernel.org,
Casey Schaufler <casey-AT-schaufler-ca.com> |
On 2/3/2011 3:05 AM, David Howells wrote:
> Casey Schaufler <casey@schaufler-ca.com> wrote:
>
>> One could create an LSM that composes other LSMs. I have been working on
>> such an implementation, but it isn't going to be done soon and it has too
>> deal with the same set of issues you outline here. It has the advantage of
>> leaving the existing LSMs closer to their current state. It would no doubt
>> have performance issues beyond what a "native" implementation would.
Sigh. I'm about to make references to an alternative approach that
no one else has seen. I will have to post it in the next day or two
or have everyone clawing at my eyes. Sorry about not having it ready,
but if it had been I would have put it out before this.
Just enough information so that my descriptions make some sense:
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.
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.
> You still have to change all the references the LSMs make to the security
> pointers in the objects (such file->f_security) as they all access those
> directly. A bunch of the patches I have here are simply wrapping those
> accesses.
Yes, it looks somewhat similar to what I have tried. I think that
your wrappers are somewhat heavy handed, but that is an artifact of
your single blob strategy, I think. It also looks burdensome for
the single LSM case.
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];
> Also you still would need to sort out the fact that the LSMs chain to commoncap
> routines. You generally want to call each commoncap routine once only.
> Sometimes its just a matter of wasted time, but sometimes it'll have other
> effects too.
Yes. My approach is to call the commoncap hook if no other LSM
provides the hook. This is pretty much required as there is no
LSM specification regarding potential side effects. I think that
going forward it is going to help a lot if we have something
about what an LSM should or shouldn't do in that regard.
>> Is this strictly necessary? I have been working on the notion that there
>> is a master blob that has a pointer for each LSM and that the individual
>> LSMs manage their own blobs. It is pretty easy to image an LSM with variable
>> size blobs. I doubt that allocating the maximum possible blob every time is
>> going to make anyone happy.
> I think it's the best way. If an LSM just requires a fixed-size blob, then the
> security framework can allocate that directly. Otherwise, if it wants a
> variable size blob, it can just ask the framework for space for a pointer -
> which then just falls back to your suggestion above (it can always split its
> blob too).
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.
> By aggregating like this you get a number of wins:
>
> (1) If possible, the aggregation can be tacked on to the end of the object,
> thus eliminating the first pointer indirection and also possibly sharing
> some CPU cacheline with the object itself.
>
> (2) If not possible, only one pointer's worth of space need to be set aside to
> reach them. For fixed size blobs no further pointer space need be
> consumed.
>
> (3) All the blobs can share cachelines. It's likely that all the blobs
> will be referenced, so if the first blob is looked at, it is likely to
> automatically draw the second into the CPU cache.
>
> (4) Fewer calls to the memory allocator.
I would call all of these premature optimizations.
> 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 you 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.
>>> The security framework aggregates the security data for each object into
>>> one allocation which _it_ makes rather than the LSM. Where possible, this
>>> allocation is appended to the allocation of the object itself. The offset
>>> of the security data for each class of objects for an LSM is stored in that
>>> LSM's pointer table, and wrappers are then provided.
>> Hmm. Sounds convoluted.
> Not really, I suspect I haven't explained it very well (it was 2am when I wrote
> this:-).
I just think that memory usage optimization is something that we could
come back to after we address the other, more pressing issues.
> Also is the whole thing the LSM or the LSM framework, and are modules LSMs or
> LSM modules?
Think "Personal PIN Number for the Automated ATM Machine".
The LSM framework supports Linux Security Modules (LSM).
>>> These patches theoretically permit multiple LSMs to be selected, but I
>>> haven't tested that as my test machine is only set up for SELinux at this
>>> time. They do, however, with SELinux alone.
>> How about you give that a try? My experience has been that any one
>> LSM is easy, and that certain pairs are relatively easy to have run
>> together, but they don't actually work right. More on secids below.
> I plan to try stacking TOMOYO on SELinux, but I've got to set that up first
> (plus I need to give some attention to other stuff).
I have composed (in my world Glass is a composer, not a stacker)
Smack, TOMOYO and AppArmor on a single system and it runs. The Smack
policy seems to work, but I have not done anything with configuring
the others beyond what comes with Ubuntu-10.10 and have not tested
their behavior. There are things like the /proc/.../current interface
that I know are wrong.
I have not gotten SELinux to share with anything, but that is probably
just that the blob wrapping isn't done correctly.
>>> (*) Which module should get to handle secid/secctx requests? Currently
>>> when it comes to retrieving or converting these, then the first module
>>> that offers the service gets it, and subsequent modules are ignored.
>> There's the elephant in the pudding. If you want audit to work correctly
>> you have to make the secid_to_secctx() call produce a string that reflects
>> all of the LSMs that are involved. As for the labeled networking, I fear
>> that we may be forced to rethink the interfaces to distance the LSM from
>> the over-the-wire representation so that it is possible for a composer or
>> the infrastructure to provide unification. Plus, there are those pesky
>> inode_get_secid() interfaces that I screamed so loudly against.
>>
>> No, just picking the first (or last) provider/consumer of secids
>> is a NAKable offense. Sorry. I would have posted something in 2010
>> were it not for that.
> I know. Hence why I stated it as an issue. The interface just doesn't support
> it.
>
> I think the obvious thing is to reject any chosen module that implements any of
> these interfaces if we've already selected a module that implements them. That
> would mean you can choose either Smack or SELinux, but not both.
That kind of takes the wind out of the sails, doesn't it?
I think that mapping can be done for the cases like audit, where
the secid is only used to turn around and get a secctx, which it then
treats as a text string for inclusion in an audit record. The networking
code that uses secids just passes them about, it never does anything
with them without calling an LSM hook. I think.
The interfaces that use secids on inodes have to have gotten them from
an LSM hook and had better only be using them through LSM hooks, so
they should be OK too. If they are not, those interfaces are inappropriate
and their callers are broken.
It does mean that there needs to be a standard for a secctx that allows
for the presence of multiple concurrent LSMs. There will have to be an
interface whereby either the composer/stacker can break a secctx into its
constituent parts or with which an LSM can pull the bit it cares about
out. In either case the LSMs may need to be undated to accept a secctx
in a standardized format.
>>> (*) Should there be a way of marking certain module mixes as not permitted
>>> (say SELinux and Smack or TOMOYO and AppArmor)?
>> Oddly, I found that TOMOYO and AppArmor seem to coexist without problem.
>> That's because TOMOYO doesn't do anything that conflicts actively with
>> AppArmor. Any LSM that reports and/or sets its process attribute via
>> /proc/self/attr/current (SELinux, Smack, AppArmor) is going to expect
>> to own that interface and teaching them to share is not going to be pretty.
> At a glance, I think that the only two non-compatible modules are SELinux and
> Smack because they both implement the secctx/secid interface functions.
I think that we can address secctx/secid. I am more concerned with labeled
networking, but since Smack is strongly in the CIPSO camp and SELinux only
uses it for MLS it could turn out to be less of a real problem than it
appears.
> I was thinking that you probably wouldn't want to mix SELinux and Smack because
> they're both object-based security modules or TOMOYO and AppArmor because
> they're both path-based security modules.
Yes, that is a reasonable first view.
If we have real LSM composition I could readily see ...
(At this point Casey takes a deep breath)
... breaking up SELinux into its various components to make them
more accessible. The MLS module might do better as a standalone
LSM, and I know that there would be interest in MCS. Remember that
one of the issues with SELinux is that you can't get the bit you
want without taking the whole thing.
> David
So now to be fair I need to post Glass. I need to check a thing or two
before I do (the disadvantage of not being the free agent I once was)
but I hope that doesn't take too long.
I think that we can do this thing, but that we do have to address the
serious issues up front and keep it simple, at least initially.
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html