diff mbox series

[16/18] LSM: Allow arbitrary LSM ordering

Message ID 20180916003059.1046-17-keescook@chromium.org (mailing list archive)
State New, archived
Headers show
Series LSM: Prepare for explict LSM ordering | expand

Commit Message

Kees Cook Sept. 16, 2018, 12:30 a.m. UTC
To prepare for having a third type of LSM ("shared blob"), this implements
dynamic handling of LSM ordering. The visible change here is that the
"security=" boot commandline is now a comma-separated ordered list of
all LSMs, not just the single "exclusive" LSM. This means that the
"minor" LSMs can now be disabled at boot time by omitting them from the
commandline. Additionally LSM ordering becomes entirely mutable for LSMs
with LSM_ORDER_MUTABLE ("capability" is not mutable and is always enabled
first).

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 .../admin-guide/kernel-parameters.txt         |  13 +-
 security/security.c                           | 145 ++++++++++++++----
 2 files changed, 126 insertions(+), 32 deletions(-)

Comments

Casey Schaufler Sept. 16, 2018, 6:49 p.m. UTC | #1
On 9/15/2018 5:30 PM, Kees Cook wrote:
> To prepare for having a third type of LSM ("shared blob"), this implements
> dynamic handling of LSM ordering. The visible change here is that the
> "security=" boot commandline is now a comma-separated ordered list of
> all LSMs, not just the single "exclusive" LSM. This means that the
> "minor" LSMs can now be disabled at boot time by omitting them from the
> commandline. Additionally LSM ordering becomes entirely mutable for LSMs
> with LSM_ORDER_MUTABLE ("capability" is not mutable and is always enabled
> first).

Today if I have Yama enabled and use security=apparmor I get a
module list of capability,yama,apparmor. With this change I would
get a different result, capability,apparmor. I am personally OK with
this, but I think others may see it as a violation of compatibility.

One solution is to leave security= as is, not affecting "minor"
modules and only allowing specification of one major module, and adding
another boot option security.stack= that overrides a security= option
and that takes the list as you've implemented here.

An icky alternative would be to say that any security= specification
with no commas in it retains the old behavior. So
	security=apparmor
	security=apparmor,
would get you
	capability,yama,apparmor
	capability,apparmor
respectively.

Another option would be to require negation on the minor modules,
such as
	security=apparmor,-loadpin

I can't honestly say which I like least or best.
Kees Cook Sept. 16, 2018, 11 p.m. UTC | #2
On Sun, Sep 16, 2018 at 11:49 AM, Casey Schaufler
<casey@schaufler-ca.com> wrote:
> On 9/15/2018 5:30 PM, Kees Cook wrote:
>> To prepare for having a third type of LSM ("shared blob"), this implements
>> dynamic handling of LSM ordering. The visible change here is that the
>> "security=" boot commandline is now a comma-separated ordered list of
>> all LSMs, not just the single "exclusive" LSM. This means that the
>> "minor" LSMs can now be disabled at boot time by omitting them from the
>> commandline. Additionally LSM ordering becomes entirely mutable for LSMs
>> with LSM_ORDER_MUTABLE ("capability" is not mutable and is always enabled
>> first).
>
> Today if I have Yama enabled and use security=apparmor I get a
> module list of capability,yama,apparmor. With this change I would
> get a different result, capability,apparmor. I am personally OK with
> this, but I think others may see it as a violation of compatibility.

Correct. That is the problem I had asked about earlier: it means
people with existing security= for specifying the active major LSM
will _disable_ all the minor LSMs after this change. It makes me
uncomfortable.

> One solution is to leave security= as is, not affecting "minor"
> modules and only allowing specification of one major module, and adding

I would much prefer this, yes.

A question remains: how do we map the existing "security=" selection
of a "major" LSM against what will be next "exclusive" plus tomoyo,
and in the extreme case, nothing?

Perhaps as part of deprecating "security=", we could just declare that
it is selecting between SELinux, AppArmor, Smack, and Tomoyo only?

> another boot option security.stack= that overrides a security= option
> and that takes the list as you've implemented here.

or "lsm.stack=" that overrides "security=" entirely?

> An icky alternative would be to say that any security= specification
> with no commas in it retains the old behavior. So
>         security=apparmor
>         security=apparmor,
> would get you
>         capability,yama,apparmor
>         capability,apparmor
> respectively.
>
> Another option would be to require negation on the minor modules,
> such as
>         security=apparmor,-loadpin
>
> I can't honestly say which I like least or best.

The trailing comma thing gets us some compatibility, but we still have
to decide which things should be exclusive-via-"security=" since with
blob-sharing it already becomes possible to do selinux + tomoyo.

The -$lsm style may make it hard to sensibly order any unspecified
LSMs. I guess it could just fall back to "follow builtin ordering of
unspecified LSMs" (unless someone had, maybe, "-all").

so, if builtin ordering after blob-sharing is
capability,integrity,yama,loadpin,{selinux,apparmor,smack},tomoyo

security=apparmor  is  capability,apparmor,integrity,yama,loadpin,tomoyo

security=yama,smack,-all  is  capability,yama,smack

security=loadpin,selinux,yama,-integrity  is
capability,loadpin,selinux,yama,tomoyo


Whatever we design, it needs to handle both the blob-sharing
near-future, and have an eye towards "extreme stacking" in the
some-day future. In both cases, the idea of a "major" LSM starts to
get very very hazy.

As for how we classify things, based on hooks...

now:
    always: capability
    major: selinux,apparmor,smack,tomoyo
    minor: yama,loadpin
    init-only: integrity

blob-sharing:
    always: capability
    exclusive: selinux,apparmor,smack
    sharing: tomoyo,integrity,yama,loadpin

extreme:
    always: capability
    sharing: selinux,apparmor,smack,tomoyo,integrity,yama,loadpin

The most special are capability (unconditional, run first) and
integrity (init-only, no security_add_hooks() call).

Can we classify things as MAC and non-MAC for "major" vs "minor"? SARA
and Landlock aren't MAC (and neither is integrity), or should we do
the "-$lsm" thing instead?

-Kees
Tetsuo Handa Sept. 17, 2018, 12:46 a.m. UTC | #3
On 2018/09/17 8:00, Kees Cook wrote:
> On Sun, Sep 16, 2018 at 11:49 AM, Casey Schaufler
> <casey@schaufler-ca.com> wrote:
>> One solution is to leave security= as is, not affecting "minor"
>> modules and only allowing specification of one major module, and adding
> 
> I would much prefer this, yes.
> 
> A question remains: how do we map the existing "security=" selection
> of a "major" LSM against what will be next "exclusive" plus tomoyo,
> and in the extreme case, nothing?
> 
> Perhaps as part of deprecating "security=", we could just declare that
> it is selecting between SELinux, AppArmor, Smack, and Tomoyo only?
> 
>> another boot option security.stack= that overrides a security= option
>> and that takes the list as you've implemented here.
> 
> or "lsm.stack=" that overrides "security=" entirely?


Yes, I think we can add new option.

For example, introducing lsm= and obsoleting security= (because total length for
kernel command line is limited while enumeration makes the parameter value longer).

  security= works like current behavior.

  lsm= requires explicit enumeration of all modules (except capability which has to
  be always enabled) which should be enabled at boot.

  security= is ignored if lsm= is specified.
Casey Schaufler Sept. 17, 2018, 3:06 p.m. UTC | #4
On 9/16/2018 4:00 PM, Kees Cook wrote:
> On Sun, Sep 16, 2018 at 11:49 AM, Casey Schaufler
> <casey@schaufler-ca.com> wrote:
>> On 9/15/2018 5:30 PM, Kees Cook wrote:
>>> To prepare for having a third type of LSM ("shared blob"), this implements
>>> dynamic handling of LSM ordering. The visible change here is that the
>>> "security=" boot commandline is now a comma-separated ordered list of
>>> all LSMs, not just the single "exclusive" LSM. This means that the
>>> "minor" LSMs can now be disabled at boot time by omitting them from the
>>> commandline. Additionally LSM ordering becomes entirely mutable for LSMs
>>> with LSM_ORDER_MUTABLE ("capability" is not mutable and is always enabled
>>> first).
>> Today if I have Yama enabled and use security=apparmor I get a
>> module list of capability,yama,apparmor. With this change I would
>> get a different result, capability,apparmor. I am personally OK with
>> this, but I think others may see it as a violation of compatibility.
> Correct. That is the problem I had asked about earlier: it means
> people with existing security= for specifying the active major LSM
> will _disable_ all the minor LSMs after this change. It makes me
> uncomfortable.
>
>> One solution is to leave security= as is, not affecting "minor"
>> modules and only allowing specification of one major module, and adding
> I would much prefer this, yes.
>
> A question remains: how do we map the existing "security=" selection
> of a "major" LSM against what will be next "exclusive" plus tomoyo,
> and in the extreme case, nothing?
>
> Perhaps as part of deprecating "security=", we could just declare that
> it is selecting between SELinux, AppArmor, Smack, and Tomoyo only?

I'd be happier keeping yama and loadpin as the special cases. Someone
might want to say security=landlock and expect the existing "minor"
module behavior.

>> another boot option security.stack= that overrides a security= option
>> and that takes the list as you've implemented here.
> or "lsm.stack=" that overrides "security=" entirely?

I thought about that. In some ways that would be most sane.

>> An icky alternative would be to say that any security= specification
>> with no commas in it retains the old behavior. So
>>         security=apparmor
>>         security=apparmor,
>> would get you
>>         capability,yama,apparmor
>>         capability,apparmor
>> respectively.
>>
>> Another option would be to require negation on the minor modules,
>> such as
>>         security=apparmor,-loadpin
>>
>> I can't honestly say which I like least or best.
> The trailing comma thing gets us some compatibility, but we still have
> to decide which things should be exclusive-via-"security=" since with
> blob-sharing it already becomes possible to do selinux + tomoyo.
>
> The -$lsm style may make it hard to sensibly order any unspecified
> LSMs. I guess it could just fall back to "follow builtin ordering of
> unspecified LSMs" (unless someone had, maybe, "-all").

That's why I'm not especially happy with either one.

> so, if builtin ordering after blob-sharing is
> capability,integrity,yama,loadpin,{selinux,apparmor,smack},tomoyo
>
> security=apparmor  is  capability,apparmor,integrity,yama,loadpin,tomoyo

I would expect capability,integrity,yama,loadpin,apparmor to reflect
today's behavior.

> security=yama,smack,-all  is  capability,yama,smack

Yes

> security=loadpin,selinux,yama,-integrity  is
> capability,loadpin,selinux,yama,tomoyo

I think that the negation should only apply to
integrity, yama and loadpin. All blob-using modules
must be explicitly stated if you want to use them.

> Whatever we design, it needs to handle both the blob-sharing
> near-future, and have an eye towards "extreme stacking" in the
> some-day future. In both cases, the idea of a "major" LSM starts to
> get very very hazy.

Long term the only distinction is "minor" and blob using. So long as
there's a way to enforce incompatibility (i.e. not Smack and SELinux)
in the sorter term we can adopt that mindset already.

> As for how we classify things, based on hooks...
>
> now:
>     always: capability
>     major: selinux,apparmor,smack,tomoyo
>     minor: yama,loadpin
>     init-only: integrity
>
> blob-sharing:
>     always: capability
>     exclusive: selinux,apparmor,smack
>     sharing: tomoyo,integrity,yama,loadpin
>
> extreme:
>     always: capability
>     sharing: selinux,apparmor,smack,tomoyo,integrity,yama,loadpin
>
> The most special are capability (unconditional, run first) and
> integrity (init-only, no security_add_hooks() call).
>
> Can we classify things as MAC and non-MAC for "major" vs "minor"? SARA
> and Landlock aren't MAC (and neither is integrity), or should we do
> the "-$lsm" thing instead?

I don't like using MAC because the use of the module isn't the issue,
it's the interfaces used. As ugly as it is, I like the -$lsm better.

>
> -Kees
>
Kees Cook Sept. 17, 2018, 4:24 p.m. UTC | #5
On Mon, Sep 17, 2018 at 8:06 AM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>> The trailing comma thing gets us some compatibility, but we still have
>> to decide which things should be exclusive-via-"security=" since with
>> blob-sharing it already becomes possible to do selinux + tomoyo.
>>
>> The -$lsm style may make it hard to sensibly order any unspecified
>> LSMs. I guess it could just fall back to "follow builtin ordering of
>> unspecified LSMs" (unless someone had, maybe, "-all").
>
> That's why I'm not especially happy with either one.
>
>> so, if builtin ordering after blob-sharing is
>> capability,integrity,yama,loadpin,{selinux,apparmor,smack},tomoyo
>>
>> security=apparmor  is  capability,apparmor,integrity,yama,loadpin,tomoyo
>
> I would expect capability,integrity,yama,loadpin,apparmor to reflect
> today's behavior.

If that's desired then we have to declare tomoyo as "exclusive" even
though it doesn't use blobs. But then what happens in the extreme
stacking case? Do we add "lsm.extreme=1" to change how security= is
parsed?

>> security=yama,smack,-all  is  capability,yama,smack
>
> Yes
>
>> security=loadpin,selinux,yama,-integrity  is
>> capability,loadpin,selinux,yama,tomoyo
>
> I think that the negation should only apply to
> integrity, yama and loadpin. All blob-using modules
> must be explicitly stated if you want to use them.

What about tomoyo, though? It's presently considered a major LSM (i.e.
security=tomoyo disables the other majors), but it doesn't use blobs.

>> Whatever we design, it needs to handle both the blob-sharing
>> near-future, and have an eye towards "extreme stacking" in the
>> some-day future. In both cases, the idea of a "major" LSM starts to
>> get very very hazy.
>
> Long term the only distinction is "minor" and blob using. So long as
> there's a way to enforce incompatibility (i.e. not Smack and SELinux)
> in the sorter term we can adopt that mindset already.

Given that tomoyo doesn't share blobs and integrity doesn't register
hooks, how would they be considered in that world? Or rather, what
distinguishes a "minor" LSM? It seems there are three cases: uses
blobs with sharing, uses blobs without sharing, uses no blobs. What
happens if an LSM grows a feature that needs blob sharing? If "uses no
blobs" should be considered "shares blobs", then there is no
distinction between "minor" and "blob sharing".

>> As for how we classify things, based on hooks...
>>
>> now:
>>     always: capability
>>     major: selinux,apparmor,smack,tomoyo
>>     minor: yama,loadpin
>>     init-only: integrity
>>
>> blob-sharing:
>>     always: capability
>>     exclusive: selinux,apparmor,smack
>>     sharing: tomoyo,integrity,yama,loadpin
>>
>> extreme:
>>     always: capability
>>     sharing: selinux,apparmor,smack,tomoyo,integrity,yama,loadpin
>>
>> The most special are capability (unconditional, run first) and
>> integrity (init-only, no security_add_hooks() call).
>>
>> Can we classify things as MAC and non-MAC for "major" vs "minor"? SARA
>> and Landlock aren't MAC (and neither is integrity), or should we do
>> the "-$lsm" thing instead?
>
> I don't like using MAC because the use of the module isn't the issue,
> it's the interfaces used. As ugly as it is, I like the -$lsm better.

Agreed on MAC. And yes, I think -$lsm is best here. Should we overload
"security=" or add "lsm.stacking="?

-Kees
Casey Schaufler Sept. 17, 2018, 5:13 p.m. UTC | #6
On 9/17/2018 9:24 AM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 8:06 AM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>>> The trailing comma thing gets us some compatibility, but we still have
>>> to decide which things should be exclusive-via-"security=" since with
>>> blob-sharing it already becomes possible to do selinux + tomoyo.
>>>
>>> The -$lsm style may make it hard to sensibly order any unspecified
>>> LSMs. I guess it could just fall back to "follow builtin ordering of
>>> unspecified LSMs" (unless someone had, maybe, "-all").
>> That's why I'm not especially happy with either one.
>>
>>> so, if builtin ordering after blob-sharing is
>>> capability,integrity,yama,loadpin,{selinux,apparmor,smack},tomoyo
>>>
>>> security=apparmor  is  capability,apparmor,integrity,yama,loadpin,tomoyo
>> I would expect capability,integrity,yama,loadpin,apparmor to reflect
>> today's behavior.
> If that's desired then we have to declare tomoyo as "exclusive" even
> though it doesn't use blobs. But then what happens in the extreme
> stacking case? Do we add "lsm.extreme=1" to change how security= is
> parsed?

TOMOYO uses the cred blob pointer. When the blob is shared TOMOYO
has to be allocated a pointer size chunk to store the pointer in.
Smack has the same behavior on file blobs.


>>> security=yama,smack,-all  is  capability,yama,smack
>> Yes
>>
>>> security=loadpin,selinux,yama,-integrity  is
>>> capability,loadpin,selinux,yama,tomoyo
>> I think that the negation should only apply to
>> integrity, yama and loadpin. All blob-using modules
>> must be explicitly stated if you want to use them.
> What about tomoyo, though? It's presently considered a major LSM (i.e.
> security=tomoyo disables the other majors), but it doesn't use blobs.
>
>>> Whatever we design, it needs to handle both the blob-sharing
>>> near-future, and have an eye towards "extreme stacking" in the
>>> some-day future. In both cases, the idea of a "major" LSM starts to
>>> get very very hazy.
>> Long term the only distinction is "minor" and blob using. So long as
>> there's a way to enforce incompatibility (i.e. not Smack and SELinux)
>> in the sorter term we can adopt that mindset already.
> Given that tomoyo doesn't share blobs and integrity doesn't register
> hooks, how would they be considered in that world? Or rather, what
> distinguishes a "minor" LSM? It seems there are three cases: uses
> blobs with sharing, uses blobs without sharing, uses no blobs. What
> happens if an LSM grows a feature that needs blob sharing? If "uses no
> blobs" should be considered "shares blobs", then there is no
> distinction between "minor" and "blob sharing".

Today the distinction is based on how the module registers hooks.
Modules that use blobs (including TOMOYO) use security_module_enable()
and those that don't just use security_add_hooks(). The "pick one"
policy is enforced in security_module_enable(), which is why you can
have as many non-blob users as you like. You could easily have a
non-blob using module that was exclusive simply by using
security_module_enable().

In the stacking case you could have integrity_init() call
security_module_enable() but not security_add_hooks(). You wouldn't
want to do that without stacking configured, because that would
make integrity exclusive.
 

>>> As for how we classify things, based on hooks...
>>>
>>> now:
>>>     always: capability
>>>     major: selinux,apparmor,smack,tomoyo
>>>     minor: yama,loadpin
>>>     init-only: integrity
>>>
>>> blob-sharing:
>>>     always: capability
>>>     exclusive: selinux,apparmor,smack
>>>     sharing: tomoyo,integrity,yama,loadpin
>>>
>>> extreme:
>>>     always: capability
>>>     sharing: selinux,apparmor,smack,tomoyo,integrity,yama,loadpin
>>>
>>> The most special are capability (unconditional, run first) and
>>> integrity (init-only, no security_add_hooks() call).
>>>
>>> Can we classify things as MAC and non-MAC for "major" vs "minor"? SARA
>>> and Landlock aren't MAC (and neither is integrity), or should we do
>>> the "-$lsm" thing instead?
>> I don't like using MAC because the use of the module isn't the issue,
>> it's the interfaces used. As ugly as it is, I like the -$lsm better.
> Agreed on MAC. And yes, I think -$lsm is best here. Should we overload
> "security=" or add "lsm.stacking="?

Keep security=$lsm with the existing exclusive behavior.

Add lsm=$lsm1,...,$lsmN which requires a full list of modules

If you want to be fancy (I don't!) you could add

lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
Kees Cook Sept. 17, 2018, 6:14 p.m. UTC | #7
On Mon, Sep 17, 2018 at 10:13 AM, Casey Schaufler
<casey@schaufler-ca.com> wrote:
> TOMOYO uses the cred blob pointer. When the blob is shared TOMOYO
> has to be allocated a pointer size chunk to store the pointer in.
> Smack has the same behavior on file blobs.

Oh dang, yes, I got confused over secid and other "extreme" shared things.

So one change of my series would be to declare tomoyo as "exclusive" too.

> Today the distinction is based on how the module registers hooks.
> Modules that use blobs (including TOMOYO) use security_module_enable()
> and those that don't just use security_add_hooks(). The "pick one"
> policy is enforced in security_module_enable(), which is why you can
> have as many non-blob users as you like. You could easily have a
> non-blob using module that was exclusive simply by using
> security_module_enable().

True. With my removal of security_module_enable(), yes, it makes sense
to mark all LSMs that were calling it before as exclusive, rather than
focusing on whether they would be exclusive under the blob-sharing
situation.

> Keep security=$lsm with the existing exclusive behavior.
> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>
> If you want to be fancy (I don't!) you could add
>
> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack

We've got two issues: ordering and enablement. It's been strongly
suggested that we should move away from per-LSM enable/disable flags
(to which I agree). If ordering should be separate from enablement (to
avoid the "booted kernel with new LSM built in, but my lsm="..." line
didn't include it so it's disabled case), then I think we need to
split the logic (otherwise we just reinvented "security=" with similar
problems).

Should "lsm=" allow arbitrary ordering? (I think yes.)

Should "lsm=" imply implicit enable/disable? (I think no: unlisted
LSMs are implicitly auto-appended to the explicit list)

So then we could have "lsm.enable=..." and "lsm.disable=...".

If builtin list was:
capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
then:

    lsm.disable=loadpin lsm=smack

becomes

    capability,smack,yama,integrity

and

    CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
    selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity

becomes

    capability,integrity,yama,loadpin,apparmor


If "lsm=" _does_ imply enablement, then how does it interact with
per-LSM disabling? i.e. what does "apparmor.enabled=0
lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
on a CONFIG-default-off LSM without specifying all the other LSMs too?

-Kees
Casey Schaufler Sept. 17, 2018, 7:23 p.m. UTC | #8
On 9/17/2018 11:14 AM, Kees Cook wrote:
>
>> Keep security=$lsm with the existing exclusive behavior.
>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>
>> If you want to be fancy (I don't!) you could add
>>
>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
> We've got two issues: ordering and enablement. It's been strongly
> suggested that we should move away from per-LSM enable/disable flags
> (to which I agree).

I also agree. There are way too many ways to turn off some LSMs.

> If ordering should be separate from enablement (to
> avoid the "booted kernel with new LSM built in, but my lsm="..." line
> didn't include it so it's disabled case), then I think we need to
> split the logic (otherwise we just reinvented "security=" with similar
> problems).

We could reduce the problem by declaring that LSM ordering is
not something you can specify on the boot line. I can see value
in specifying it when you build the kernel, but your circumstances
would have to be pretty strange to change it at boot time.

> Should "lsm=" allow arbitrary ordering? (I think yes.)

I say no. Assume you can specify it at build time. When would
you want to change the order? Why would you?

> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
> LSMs are implicitly auto-appended to the explicit list)

If you want to add something that isn't there instead of making
it explicit you want "lsm.enable=" not "lsm=".

> So then we could have "lsm.enable=..." and "lsm.disable=...".
>
> If builtin list was:
> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
> then:
>
>     lsm.disable=loadpin lsm=smack

Methinks this should be lsm.disable=loadpin lsm.enable=smack

> becomes
>
>     capability,smack,yama,integrity
>
> and
>
>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity

Do you mean
	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo

> becomes
>
>     capability,integrity,yama,loadpin,apparmor
>
>
> If "lsm=" _does_ imply enablement, then how does it interact with
> per-LSM disabling? i.e. what does "apparmor.enabled=0
> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
> on a CONFIG-default-off LSM without specifying all the other LSMs too?

There should either be one option "lsm=", which is an explicit list or
two, "lsm.enable=" and "lsm.disable", which modify the built in default.

In the "lsm=" case "apparmor.enabled=0" should be equivalent to leaving
apparmor off the list, but it's up to the AppArmor code to do that.

If "lsm.enable=apparmor apparmor.enabled=0" is specified the explict wish
of the security module is used, but it's up to the AppArmor code to do that.

If "lsm.disable=apparmor apparmor.enabled=1" is specified the infrastructure
should have shut down AppArmor before it looked to see the "apparmor.enabled=1",
so it will remain disabled.

If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
specified is used giving "lsm.disable=apparmor".
John Johansen Sept. 17, 2018, 7:35 p.m. UTC | #9
On 09/17/2018 11:14 AM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 10:13 AM, Casey Schaufler
> <casey@schaufler-ca.com> wrote:
>> TOMOYO uses the cred blob pointer. When the blob is shared TOMOYO
>> has to be allocated a pointer size chunk to store the pointer in.
>> Smack has the same behavior on file blobs.
> 
> Oh dang, yes, I got confused over secid and other "extreme" shared things.
> 
> So one change of my series would be to declare tomoyo as "exclusive" too.
> 
>> Today the distinction is based on how the module registers hooks.
>> Modules that use blobs (including TOMOYO) use security_module_enable()
>> and those that don't just use security_add_hooks(). The "pick one"
>> policy is enforced in security_module_enable(), which is why you can
>> have as many non-blob users as you like. You could easily have a
>> non-blob using module that was exclusive simply by using
>> security_module_enable().
> 
> True. With my removal of security_module_enable(), yes, it makes sense
> to mark all LSMs that were calling it before as exclusive, rather than
> focusing on whether they would be exclusive under the blob-sharing
> situation.
> 
>> Keep security=$lsm with the existing exclusive behavior.
>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>
>> If you want to be fancy (I don't!) you could add
>>
>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
> 
> We've got two issues: ordering and enablement. It's been strongly
> suggested that we should move away from per-LSM enable/disable flags
> (to which I agree). If ordering should be separate from enablement (to
> avoid the "booted kernel with new LSM built in, but my lsm="..." line
> didn't include it so it's disabled case), then I think we need to
> split the logic (otherwise we just reinvented "security=" with similar
> problems).
> 
> Should "lsm=" allow arbitrary ordering? (I think yes.)
> yes

> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
> LSMs are implicitly auto-appended to the explicit list)
> 

maybe, adding $lsm to the list could possibly considered as enabling it,
but not having it there doesn't necessarily imply it isn't

> So then we could have "lsm.enable=..." and "lsm.disable=...".
> 
> If builtin list was:
> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
> then:
> 
>     lsm.disable=loadpin lsm=smack
> 
> becomes
> 
>     capability,smack,yama,integrity
> 
> and
> 
>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
> 
> becomes
> 
>     capability,integrity,yama,loadpin,apparmor
> 
> 
> If "lsm=" _does_ imply enablement, then how does it interact with
> per-LSM disabling? i.e. what does "apparmor.enabled=0
> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
> on a CONFIG-default-off LSM without specifying all the other LSMs too?
> 

currently using

   security=apparmor apparmor=0

means apparmor is the one given the chance to register but it declines
which means you just get capabilities. And with

   # caveat not part of the current stacking patchset
   security=selinux,apparmor  apparmor=0

you end up with

   capability,selinux

However apparmor=1 does not imply apparmor is the available LSM

that is

   security=selinux  apparmor=1

gives you
   
   capability,selinux

if iirc selinux=X behaves the same way

However it is not clear to me whether this is the behavior that we
would want for $lsm.enabled, $lsm.disabled. It appears to be in
conflict with how yama, loadpin and IMA currently work.
John Johansen Sept. 17, 2018, 7:55 p.m. UTC | #10
On 09/17/2018 12:23 PM, Casey Schaufler wrote:
> On 9/17/2018 11:14 AM, Kees Cook wrote:
>>
>>> Keep security=$lsm with the existing exclusive behavior.
>>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>>
>>> If you want to be fancy (I don't!) you could add
>>>
>>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
>> We've got two issues: ordering and enablement. It's been strongly
>> suggested that we should move away from per-LSM enable/disable flags
>> (to which I agree).
> 
> I also agree. There are way too many ways to turn off some LSMs.
> 
I wont disagree, but its largely because we didn't have this discussion
when we should have. 

>> If ordering should be separate from enablement (to
>> avoid the "booted kernel with new LSM built in, but my lsm="..." line
>> didn't include it so it's disabled case), then I think we need to
>> split the logic (otherwise we just reinvented "security=" with similar
>> problems).
> 
> We could reduce the problem by declaring that LSM ordering is
> not something you can specify on the boot line. I can see value
> in specifying it when you build the kernel, but your circumstances
> would have to be pretty strange to change it at boot time.
> 

if there is LSM ordering the getting

  lsm=B,A,C

is not the behavior I would expect from specifying

  lsm=A,B,C


>> Should "lsm=" allow arbitrary ordering? (I think yes.)
> 
> I say no. Assume you can specify it at build time. When would
> you want to change the order? Why would you?
> 

because maybe you care about the denial message from one LSM more than
you do from another. Since stacking is bail on first fail the order
could be important from an auditing POV

Auditing is why apparmor's internal stacking is not bail on first
fail.

>> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
>> LSMs are implicitly auto-appended to the explicit list)
> 
> If you want to add something that isn't there instead of making
> it explicit you want "lsm.enable=" not "lsm=".
> 
>> So then we could have "lsm.enable=..." and "lsm.disable=...".
>>
>> If builtin list was:
>> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
>> then:
>>
>>     lsm.disable=loadpin lsm=smack
> 
> Methinks this should be lsm.disable=loadpin lsm.enable=smack
> 

that would only work if order is not important

>> becomes
>>
>>     capability,smack,yama,integrity
>>
>> and
>>
>>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
> 
> Do you mean
> 	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
> 	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
> 	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo
> 
>> becomes
>>
>>     capability,integrity,yama,loadpin,apparmor
>>
>>
>> If "lsm=" _does_ imply enablement, then how does it interact with
>> per-LSM disabling? i.e. what does "apparmor.enabled=0
>> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
>> on a CONFIG-default-off LSM without specifying all the other LSMs too?
> 
> There should either be one option "lsm=", which is an explicit list or
> two, "lsm.enable=" and "lsm.disable", which modify the built in default.
> 
maybe but this breaks with current behavior as their is a mismatch between
how the major lsms do selection/enablement and the minor ones.

I personally would prefer

  lsm=

but that breaks how the minor lsms are currently enable

> In the "lsm=" case "apparmor.enabled=0" should be equivalent to leaving
> apparmor off the list, but it's up to the AppArmor code to do that.
>> If "lsm.enable=apparmor apparmor.enabled=0" is specified the explict wish
> of the security module is used, but it's up to the AppArmor code to do that.
> 
current behavior

> If "lsm.disable=apparmor apparmor.enabled=1" is specified the infrastructure
> should have shut down AppArmor before it looked to see the "apparmor.enabled=1",
> so it will remain disabled.
> 
yep, current behavior

> If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
> specified is used giving "lsm.disable=apparmor".
> 
makes sense
Casey Schaufler Sept. 17, 2018, 9:57 p.m. UTC | #11
On 9/17/2018 12:55 PM, John Johansen wrote:
> On 09/17/2018 12:23 PM, Casey Schaufler wrote:
>> On 9/17/2018 11:14 AM, Kees Cook wrote:
>>>> Keep security=$lsm with the existing exclusive behavior.
>>>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>>>
>>>> If you want to be fancy (I don't!) you could add
>>>>
>>>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>>>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
>>> We've got two issues: ordering and enablement. It's been strongly
>>> suggested that we should move away from per-LSM enable/disable flags
>>> (to which I agree).
>> I also agree. There are way too many ways to turn off some LSMs.
>>
> I wont disagree, but its largely because we didn't have this discussion
> when we should have.

True that.


>>> If ordering should be separate from enablement (to
>>> avoid the "booted kernel with new LSM built in, but my lsm="..." line
>>> didn't include it so it's disabled case), then I think we need to
>>> split the logic (otherwise we just reinvented "security=" with similar
>>> problems).
>> We could reduce the problem by declaring that LSM ordering is
>> not something you can specify on the boot line. I can see value
>> in specifying it when you build the kernel, but your circumstances
>> would have to be pretty strange to change it at boot time.
>>
> if there is LSM ordering the getting
>
>   lsm=B,A,C
>
> is not the behavior I would expect from specifying
>
>   lsm=A,B,C

Right. You'd expect that they'd be used in the order specified.

>>> Should "lsm=" allow arbitrary ordering? (I think yes.)
>> I say no. Assume you can specify it at build time. When would
>> you want to change the order? Why would you?
>>
> because maybe you care about the denial message from one LSM more than
> you do from another. Since stacking is bail on first fail the order
> could be important from an auditing POV

I understand that a distribution would want to specify the order
for support purposes and that a developer would want to specify
the order to ensure reproducible behavior. But they are going to
be controlling their kernel builds. I'm not suggesting that the
order shouldn't be capable of build time specification. What I
don't see is a reason to rearrange it at boot time.

> Auditing is why apparmor's internal stacking is not bail on first
> fail.

Within a security module I get that. But we've already got the
priority wrong for audit in general, because you only get to the
LSM if the traditional code approves. Every guidance I ever got
said you should do the MAC checks first, because you're much more
concerned about getting audit records about MAC failures than DAC.

>>> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
>>> LSMs are implicitly auto-appended to the explicit list)
>> If you want to add something that isn't there instead of making
>> it explicit you want "lsm.enable=" not "lsm=".
>>
>>> So then we could have "lsm.enable=..." and "lsm.disable=...".
>>>
>>> If builtin list was:
>>> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
>>> then:
>>>
>>>     lsm.disable=loadpin lsm=smack
>> Methinks this should be lsm.disable=loadpin lsm.enable=smack
>>
> that would only work if order is not important

It works unless you want to change the order at boot, and
I still don't see a use case for that.

>>> becomes
>>>
>>>     capability,smack,yama,integrity
>>>
>>> and
>>>
>>>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>>>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
>> Do you mean
>> 	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
>> 	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
>> 	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo
>>
>>> becomes
>>>
>>>     capability,integrity,yama,loadpin,apparmor
>>>
>>>
>>> If "lsm=" _does_ imply enablement, then how does it interact with
>>> per-LSM disabling? i.e. what does "apparmor.enabled=0
>>> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
>>> on a CONFIG-default-off LSM without specifying all the other LSMs too?
>> There should either be one option "lsm=", which is an explicit list or
>> two, "lsm.enable=" and "lsm.disable", which modify the built in default.
>>
> maybe but this breaks with current behavior as their is a mismatch between
> how the major lsms do selection/enablement and the minor ones.

Which is why you have to continue supporting "security=".

> I personally would prefer
>
>   lsm=
>
> but that breaks how the minor lsms are currently enable

I don't know if I'd say "breaks", but it would require change.

>> In the "lsm=" case "apparmor.enabled=0" should be equivalent to leaving
>> apparmor off the list, but it's up to the AppArmor code to do that.
>>> If "lsm.enable=apparmor apparmor.enabled=0" is specified the explict wish
>> of the security module is used, but it's up to the AppArmor code to do that.
>>
> current behavior

That's right.

>> If "lsm.disable=apparmor apparmor.enabled=1" is specified the infrastructure
>> should have shut down AppArmor before it looked to see the "apparmor.enabled=1",
>> so it will remain disabled.
>>
> yep, current behavior

2 for 2!


>> If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
>> specified is used giving "lsm.disable=apparmor".
>>
> makes sense

The rules for modification are pretty obvious. The downside is, as
you point out, that they don't address ordering. Maybe we address that
directly:

	lsm.order=*,tomoyo

		TOMOYO should be last.

	lsm.order=apparmor,*

		AppArmor should be first.


	lsm.order=*,sara,selinux,*

		SELinux should come directly after SARA but we otherwise don't care.

	lsm.order=smack,*,landlock,*

		Smack should be first and LandLock should come sometime later.

	lsm.order=*,yama,*

		Is meaningless.

Modules not listed may go anywhere there is a "*" in the order.
An lsm.order= without a "*" is an error, and ignored.
If a module is specified in lsm.order but not built in it is ignored.
If a module is specified but disabled it is ignored.
The capability module goes first regardless.
John Johansen Sept. 17, 2018, 10:36 p.m. UTC | #12
On 09/17/2018 02:57 PM, Casey Schaufler wrote:
> On 9/17/2018 12:55 PM, John Johansen wrote:
>> On 09/17/2018 12:23 PM, Casey Schaufler wrote:
>>> On 9/17/2018 11:14 AM, Kees Cook wrote:
>>>>> Keep security=$lsm with the existing exclusive behavior.
>>>>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>>>>
>>>>> If you want to be fancy (I don't!) you could add
>>>>>
>>>>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>>>>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
>>>> We've got two issues: ordering and enablement. It's been strongly
>>>> suggested that we should move away from per-LSM enable/disable flags
>>>> (to which I agree).
>>> I also agree. There are way too many ways to turn off some LSMs.
>>>
>> I wont disagree, but its largely because we didn't have this discussion
>> when we should have.
> 
> True that.
> 
> 
>>>> If ordering should be separate from enablement (to
>>>> avoid the "booted kernel with new LSM built in, but my lsm="..." line
>>>> didn't include it so it's disabled case), then I think we need to
>>>> split the logic (otherwise we just reinvented "security=" with similar
>>>> problems).
>>> We could reduce the problem by declaring that LSM ordering is
>>> not something you can specify on the boot line. I can see value
>>> in specifying it when you build the kernel, but your circumstances
>>> would have to be pretty strange to change it at boot time.
>>>
>> if there is LSM ordering the getting
>>
>>   lsm=B,A,C
>>
>> is not the behavior I would expect from specifying
>>
>>   lsm=A,B,C
> 
> Right. You'd expect that they'd be used in the order specified.
> 

and yet you argue for something different ;)

>>>> Should "lsm=" allow arbitrary ordering? (I think yes.)
>>> I say no. Assume you can specify it at build time. When would
>>> you want to change the order? Why would you?
>>>
>> because maybe you care about the denial message from one LSM more than
>> you do from another. Since stacking is bail on first fail the order
>> could be important from an auditing POV
> 
> I understand that a distribution would want to specify the order
> for support purposes and that a developer would want to specify
> the order to ensure reproducible behavior. But they are going to
> be controlling their kernel builds. I'm not suggesting that the
> order shouldn't be capable of build time specification. What I
> don't see is a reason to rearrange it at boot time.
> 

Because not all users have the same priority as the distro. It can
also aid in debugging and testing of LSMs in a stacked situation.

>> Auditing is why apparmor's internal stacking is not bail on first
>> fail.
> 
> Within a security module I get that. But we've already got the
> priority wrong for audit in general, because you only get to the
> LSM if the traditional code approves. Every guidance I ever got

true

> said you should do the MAC checks first, because you're much more
> concerned about getting audit records about MAC failures than DAC.
> 

yep, wouldn't that be nice to have

>>>> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
>>>> LSMs are implicitly auto-appended to the explicit list)
>>> If you want to add something that isn't there instead of making
>>> it explicit you want "lsm.enable=" not "lsm=".
>>>
>>>> So then we could have "lsm.enable=..." and "lsm.disable=...".
>>>>
>>>> If builtin list was:
>>>> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
>>>> then:
>>>>
>>>>     lsm.disable=loadpin lsm=smack
>>> Methinks this should be lsm.disable=loadpin lsm.enable=smack
>>>
>> that would only work if order is not important
> 
> It works unless you want to change the order at boot, and
> I still don't see a use case for that.

see above

> 
>>>> becomes
>>>>
>>>>     capability,smack,yama,integrity
>>>>
>>>> and
>>>>
>>>>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>>>>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
>>> Do you mean
>>> 	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
>>> 	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
>>> 	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo
>>>
>>>> becomes
>>>>
>>>>     capability,integrity,yama,loadpin,apparmor
>>>>
>>>>
>>>> If "lsm=" _does_ imply enablement, then how does it interact with
>>>> per-LSM disabling? i.e. what does "apparmor.enabled=0
>>>> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
>>>> on a CONFIG-default-off LSM without specifying all the other LSMs too?
>>> There should either be one option "lsm=", which is an explicit list or
>>> two, "lsm.enable=" and "lsm.disable", which modify the built in default.
>>>
>> maybe but this breaks with current behavior as their is a mismatch between
>> how the major lsms do selection/enablement and the minor ones.
> 
> Which is why you have to continue supporting "security=".
> 
I would argue that switching to lsm= isn't exactly a fix either as we have
the whole minor lsm problem that we are currently debating.

>> I personally would prefer
>>
>>   lsm=
>>
>> but that breaks how the minor lsms are currently enable
> 
> I don't know if I'd say "breaks", but it would require change.
> 
depends how you look at it. Its a change to how its interacted with but so
is switching to lsm=

or making the minor module kconfig automatically add the current minor
lsms to a default lsm selection list, and making $lsm.disable behave
like apparmor or selinux=0.

we got it wrong early on, so now we have to live with something not
as clean as it could have been


>>> In the "lsm=" case "apparmor.enabled=0" should be equivalent to leaving
>>> apparmor off the list, but it's up to the AppArmor code to do that.
>>>> If "lsm.enable=apparmor apparmor.enabled=0" is specified the explict wish
>>> of the security module is used, but it's up to the AppArmor code to do that.
>>>
>> current behavior
> 
> That's right.
> 
>>> If "lsm.disable=apparmor apparmor.enabled=1" is specified the infrastructure
>>> should have shut down AppArmor before it looked to see the "apparmor.enabled=1",
>>> so it will remain disabled.
>>>
>> yep, current behavior
> 
> 2 for 2!
> 
> 
>>> If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
>>> specified is used giving "lsm.disable=apparmor".
>>>
>> makes sense
> 
> The rules for modification are pretty obvious. The downside is, as
> you point out, that they don't address ordering. Maybe we address that
> directly:
> 
> 	lsm.order=*,tomoyo
> 
> 		TOMOYO should be last.
> 
> 	lsm.order=apparmor,*
> 
> 		AppArmor should be first.
> 
> 
> 	lsm.order=*,sara,selinux,*
> 
> 		SELinux should come directly after SARA but we otherwise don't care.
> 
> 	lsm.order=smack,*,landlock,*
> 
> 		Smack should be first and LandLock should come sometime later.
> 
> 	lsm.order=*,yama,*
> 
> 		Is meaningless.
> 
> Modules not listed may go anywhere there is a "*" in the order.
> An lsm.order= without a "*" is an error, and ignored.
> If a module is specified in lsm.order but not built in it is ignored.
> If a module is specified but disabled it is ignored.
> The capability module goes first regardless.
> 

I don't mind using lsm.order if we must but really do not like the '*'
idea. It makes this way more complicated than it needs to be
Mickaël Salaün Sept. 17, 2018, 11:10 p.m. UTC | #13
On 9/18/18 00:36, John Johansen wrote:
> On 09/17/2018 02:57 PM, Casey Schaufler wrote:
>> On 9/17/2018 12:55 PM, John Johansen wrote:
>>> On 09/17/2018 12:23 PM, Casey Schaufler wrote:
>>>> On 9/17/2018 11:14 AM, Kees Cook wrote:
>>>>>> Keep security=$lsm with the existing exclusive behavior.
>>>>>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>>>>>
>>>>>> If you want to be fancy (I don't!) you could add
>>>>>>
>>>>>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>>>>>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
>>>>> We've got two issues: ordering and enablement. It's been strongly
>>>>> suggested that we should move away from per-LSM enable/disable flags
>>>>> (to which I agree).
>>>> I also agree. There are way too many ways to turn off some LSMs.
>>>>
>>> I wont disagree, but its largely because we didn't have this discussion
>>> when we should have.
>>
>> True that.
>>
>>
>>>>> If ordering should be separate from enablement (to
>>>>> avoid the "booted kernel with new LSM built in, but my lsm="..." line
>>>>> didn't include it so it's disabled case), then I think we need to
>>>>> split the logic (otherwise we just reinvented "security=" with similar
>>>>> problems).
>>>> We could reduce the problem by declaring that LSM ordering is
>>>> not something you can specify on the boot line. I can see value
>>>> in specifying it when you build the kernel, but your circumstances
>>>> would have to be pretty strange to change it at boot time.
>>>>
>>> if there is LSM ordering the getting
>>>
>>>   lsm=B,A,C
>>>
>>> is not the behavior I would expect from specifying
>>>
>>>   lsm=A,B,C
>>
>> Right. You'd expect that they'd be used in the order specified.
>>
> 
> and yet you argue for something different ;)
> 
>>>>> Should "lsm=" allow arbitrary ordering? (I think yes.)
>>>> I say no. Assume you can specify it at build time. When would
>>>> you want to change the order? Why would you?
>>>>
>>> because maybe you care about the denial message from one LSM more than
>>> you do from another. Since stacking is bail on first fail the order
>>> could be important from an auditing POV
>>
>> I understand that a distribution would want to specify the order
>> for support purposes and that a developer would want to specify
>> the order to ensure reproducible behavior. But they are going to
>> be controlling their kernel builds. I'm not suggesting that the
>> order shouldn't be capable of build time specification. What I
>> don't see is a reason to rearrange it at boot time.
>>
> 
> Because not all users have the same priority as the distro. It can
> also aid in debugging and testing of LSMs in a stacked situation.
> 
>>> Auditing is why apparmor's internal stacking is not bail on first
>>> fail.
>>
>> Within a security module I get that. But we've already got the
>> priority wrong for audit in general, because you only get to the
>> LSM if the traditional code approves. Every guidance I ever got
> 
> true
> 
>> said you should do the MAC checks first, because you're much more
>> concerned about getting audit records about MAC failures than DAC.
>>
> 
> yep, wouldn't that be nice to have
> 
>>>>> Should "lsm=" imply implicit enable/disable? (I think no: unlisted
>>>>> LSMs are implicitly auto-appended to the explicit list)
>>>> If you want to add something that isn't there instead of making
>>>> it explicit you want "lsm.enable=" not "lsm=".
>>>>
>>>>> So then we could have "lsm.enable=..." and "lsm.disable=...".
>>>>>
>>>>> If builtin list was:
>>>>> capability,yama,loadpin,integrity,{selinux,smack,tomoyo,apparmor}
>>>>> then:
>>>>>
>>>>>     lsm.disable=loadpin lsm=smack
>>>> Methinks this should be lsm.disable=loadpin lsm.enable=smack
>>>>
>>> that would only work if order is not important
>>
>> It works unless you want to change the order at boot, and
>> I still don't see a use case for that.
> 
> see above
> 
>>
>>>>> becomes
>>>>>
>>>>>     capability,smack,yama,integrity
>>>>>
>>>>> and
>>>>>
>>>>>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>>>>>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
>>>> Do you mean
>>>> 	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
>>>> 	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
>>>> 	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo
>>>>
>>>>> becomes
>>>>>
>>>>>     capability,integrity,yama,loadpin,apparmor
>>>>>
>>>>>
>>>>> If "lsm=" _does_ imply enablement, then how does it interact with
>>>>> per-LSM disabling? i.e. what does "apparmor.enabled=0
>>>>> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
>>>>> on a CONFIG-default-off LSM without specifying all the other LSMs too?
>>>> There should either be one option "lsm=", which is an explicit list or
>>>> two, "lsm.enable=" and "lsm.disable", which modify the built in default.
>>>>
>>> maybe but this breaks with current behavior as their is a mismatch between
>>> how the major lsms do selection/enablement and the minor ones.
>>
>> Which is why you have to continue supporting "security=".
>>
> I would argue that switching to lsm= isn't exactly a fix either as we have
> the whole minor lsm problem that we are currently debating.
> 
>>> I personally would prefer
>>>
>>>   lsm=
>>>
>>> but that breaks how the minor lsms are currently enable
>>
>> I don't know if I'd say "breaks", but it would require change.
>>
> depends how you look at it. Its a change to how its interacted with but so
> is switching to lsm=
> 
> or making the minor module kconfig automatically add the current minor
> lsms to a default lsm selection list, and making $lsm.disable behave
> like apparmor or selinux=0.
> 
> we got it wrong early on, so now we have to live with something not
> as clean as it could have been
> 
> 
>>>> In the "lsm=" case "apparmor.enabled=0" should be equivalent to leaving
>>>> apparmor off the list, but it's up to the AppArmor code to do that.
>>>>> If "lsm.enable=apparmor apparmor.enabled=0" is specified the explict wish
>>>> of the security module is used, but it's up to the AppArmor code to do that.
>>>>
>>> current behavior
>>
>> That's right.
>>
>>>> If "lsm.disable=apparmor apparmor.enabled=1" is specified the infrastructure
>>>> should have shut down AppArmor before it looked to see the "apparmor.enabled=1",
>>>> so it will remain disabled.
>>>>
>>> yep, current behavior
>>
>> 2 for 2!
>>
>>
>>>> If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
>>>> specified is used giving "lsm.disable=apparmor".
>>>>
>>> makes sense
>>
>> The rules for modification are pretty obvious. The downside is, as
>> you point out, that they don't address ordering. Maybe we address that
>> directly:
>>
>> 	lsm.order=*,tomoyo
>>
>> 		TOMOYO should be last.
>>
>> 	lsm.order=apparmor,*
>>
>> 		AppArmor should be first.
>>
>>
>> 	lsm.order=*,sara,selinux,*
>>
>> 		SELinux should come directly after SARA but we otherwise don't care.
>>
>> 	lsm.order=smack,*,landlock,*
>>
>> 		Smack should be first and LandLock should come sometime later.
>>
>> 	lsm.order=*,yama,*
>>
>> 		Is meaningless.
>>
>> Modules not listed may go anywhere there is a "*" in the order.
>> An lsm.order= without a "*" is an error, and ignored.
>> If a module is specified in lsm.order but not built in it is ignored.
>> If a module is specified but disabled it is ignored.
>> The capability module goes first regardless.
>>
> 
> I don't mind using lsm.order if we must but really do not like the '*'
> idea. It makes this way more complicated than it needs to be
> 
> 

Landlock, because it target unprivileged users, should only be called
after all other major (access-control) LSMs. The admin or distro must
not be able to change that order in any way. This constraint doesn't
apply to current LSMs, though.

 Mickaël
Kees Cook Sept. 17, 2018, 11:20 p.m. UTC | #14
On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
> Landlock, because it target unprivileged users, should only be called
> after all other major (access-control) LSMs. The admin or distro must
> not be able to change that order in any way. This constraint doesn't
> apply to current LSMs, though.

Good point! It will be easy to add LSM_ORDER_LAST, though, given the
machinery introduced in this series.

-Kees
John Johansen Sept. 17, 2018, 11:25 p.m. UTC | #15
On 09/17/2018 04:10 PM, Mickaël Salaün wrote:
> 

<< snip >>

>>>>> If "lsm.enable=apparmor lsm.disable=apparmor" is specified the last value
>>>>> specified is used giving "lsm.disable=apparmor".
>>>>>
>>>> makes sense
>>>
>>> The rules for modification are pretty obvious. The downside is, as
>>> you point out, that they don't address ordering. Maybe we address that
>>> directly:
>>>
>>> 	lsm.order=*,tomoyo
>>>
>>> 		TOMOYO should be last.
>>>
>>> 	lsm.order=apparmor,*
>>>
>>> 		AppArmor should be first.
>>>
>>>
>>> 	lsm.order=*,sara,selinux,*
>>>
>>> 		SELinux should come directly after SARA but we otherwise don't care.
>>>
>>> 	lsm.order=smack,*,landlock,*
>>>
>>> 		Smack should be first and LandLock should come sometime later.
>>>
>>> 	lsm.order=*,yama,*
>>>
>>> 		Is meaningless.
>>>
>>> Modules not listed may go anywhere there is a "*" in the order.
>>> An lsm.order= without a "*" is an error, and ignored.
>>> If a module is specified in lsm.order but not built in it is ignored.
>>> If a module is specified but disabled it is ignored.
>>> The capability module goes first regardless.
>>>
>>
>> I don't mind using lsm.order if we must but really do not like the '*'
>> idea. It makes this way more complicated than it needs to be
>>
>>
> 
> Landlock, because it target unprivileged users, should only be called
> after all other major (access-control) LSMs. The admin or distro must
> not be able to change that order in any way. This constraint doesn't
> apply to current LSMs, though.
> 

And yet another complication :)

I don't know that we can enforce a strict only after all other LSMs. Imagine
the hypothetical case of 2 LSMs targeting unprivileged users. Which one
should be called first?
Casey Schaufler Sept. 17, 2018, 11:25 p.m. UTC | #16
On 9/17/2018 3:36 PM, John Johansen wrote:
> On 09/17/2018 02:57 PM, Casey Schaufler wrote:
>> On 9/17/2018 12:55 PM, John Johansen wrote:
>>> On 09/17/2018 12:23 PM, Casey Schaufler wrote:
>>>> On 9/17/2018 11:14 AM, Kees Cook wrote:
>>>>>> Keep security=$lsm with the existing exclusive behavior.
>>>>>> Add lsm=$lsm1,...,$lsmN which requires a full list of modules
>>>>>>
>>>>>> If you want to be fancy (I don't!) you could add
>>>>>>
>>>>>> lsm.add=$lsm1,...,$lsmN which adds the modules to the stack
>>>>>> lsm.delete=$lsm1,...,$lsmN which deletes modules from the stack
>>>>> We've got two issues: ordering and enablement. It's been strongly
>>>>> suggested that we should move away from per-LSM enable/disable flags
>>>>> (to which I agree).
>>>> I also agree. There are way too many ways to turn off some LSMs.
>>>>
>>> I wont disagree, but its largely because we didn't have this discussion
>>> when we should have.
>> True that.
>>
>>
>>>>> If ordering should be separate from enablement (to
>>>>> avoid the "booted kernel with new LSM built in, but my lsm="..." line
>>>>> didn't include it so it's disabled case), then I think we need to
>>>>> split the logic (otherwise we just reinvented "security=" with similar
>>>>> problems).
>>>> We could reduce the problem by declaring that LSM ordering is
>>>> not something you can specify on the boot line. I can see value
>>>> in specifying it when you build the kernel, but your circumstances
>>>> would have to be pretty strange to change it at boot time.
>>>>
>>> if there is LSM ordering the getting
>>>
>>>   lsm=B,A,C
>>>
>>> is not the behavior I would expect from specifying
>>>
>>>   lsm=A,B,C
>> Right. You'd expect that they'd be used in the order specified.
>>
> and yet you argue for something different ;)

A foolish consistency is the hobgoblin of little minds.
Or, more to the point in this case, I don't see a way to
accomplish the ends well, so I'm casting about for something
that no one hates too badly.

>>>>> Should "lsm=" allow arbitrary ordering? (I think yes.)
>>>> I say no. Assume you can specify it at build time. When would
>>>> you want to change the order? Why would you?
>>>>
>>> because maybe you care about the denial message from one LSM more than
>>> you do from another. Since stacking is bail on first fail the order
>>> could be important from an auditing POV
>> I understand that a distribution would want to specify the order
>> for support purposes and that a developer would want to specify
>> the order to ensure reproducible behavior. But they are going to
>> be controlling their kernel builds. I'm not suggesting that the
>> order shouldn't be capable of build time specification. What I
>> don't see is a reason to rearrange it at boot time.
>>
> Because not all users have the same priority as the distro. It can
> also aid in debugging and testing of LSMs in a stacked situation.

My assumption is that specifying the LSM order on the boot line
by hand is going to be pretty rare. So it doesn't have to be easy,
it just needs to be sane.

> ... <snip>
>>>>> becomes
>>>>>
>>>>>     capability,smack,yama,integrity
>>>>>
>>>>> and
>>>>>
>>>>>     CONFIG_SECURITY_LOADPIN_DEFAULT_ENABLED=n
>>>>>     selinux.enable=0 lsm.add=loadpin lsm.disable=smack,tomoyo lsm=integrity
>>>> Do you mean
>>>> 	selinux.enable=0 lsm.enable=loadpin lsm.disable=smack,tomoyo lsm.enable=integrity
>>>> 	selinux.enable=0 lsm.enable=loadpin,integrity lsm.disable=smack,tomoyo
>>>> 	selinux.enable=0 lsm.enable=loadpin lsm.enable=integrity lsm.disable=smack lsm.disable=tomoyo
>>>>
>>>>> becomes
>>>>>
>>>>>     capability,integrity,yama,loadpin,apparmor
>>>>>
>>>>>
>>>>> If "lsm=" _does_ imply enablement, then how does it interact with
>>>>> per-LSM disabling? i.e. what does "apparmor.enabled=0
>>>>> lsm=yama,apparmor" mean? If it means "turn on apparmor" how do I turn
>>>>> on a CONFIG-default-off LSM without specifying all the other LSMs too?
>>>> There should either be one option "lsm=", which is an explicit list or
>>>> two, "lsm.enable=" and "lsm.disable", which modify the built in default.
>>>>
>>> maybe but this breaks with current behavior as their is a mismatch between
>>> how the major lsms do selection/enablement and the minor ones.
>> Which is why you have to continue supporting "security=".
>>
> I would argue that switching to lsm= isn't exactly a fix either as we have
> the whole minor lsm problem that we are currently debating.

I'm finding it hard to argue for "lsm=" because it's too clumsy.


>>> I personally would prefer
>>>
>>>   lsm=
>>>
>>> but that breaks how the minor lsms are currently enable
>> I don't know if I'd say "breaks", but it would require change.
>>
> depends how you look at it. Its a change to how its interacted with but so
> is switching to lsm=
>
> or making the minor module kconfig automatically add the current minor
> lsms to a default lsm selection list, and making $lsm.disable behave
> like apparmor or selinux=0.
>
> we got it wrong early on, so now we have to live with something not
> as clean as it could have been

It's not the first time and won't be the last.

 

>>> ... <snip>
>> The rules for modification are pretty obvious. The downside is, as
>> you point out, that they don't address ordering. Maybe we address that
>> directly:
>>
>> 	lsm.order=*,tomoyo
>>
>> 		TOMOYO should be last.
>>
>> 	lsm.order=apparmor,*
>>
>> 		AppArmor should be first.
>>
>>
>> 	lsm.order=*,sara,selinux,*
>>
>> 		SELinux should come directly after SARA but we otherwise don't care.
>>
>> 	lsm.order=smack,*,landlock,*
>>
>> 		Smack should be first and LandLock should come sometime later.
>>
>> 	lsm.order=*,yama,*
>>
>> 		Is meaningless.
>>
>> Modules not listed may go anywhere there is a "*" in the order.
>> An lsm.order= without a "*" is an error, and ignored.
>> If a module is specified in lsm.order but not built in it is ignored.
>> If a module is specified but disabled it is ignored.
>> The capability module goes first regardless.
>>
> I don't mind using lsm.order if we must but really do not like the '*'
> idea. It makes this way more complicated than it needs to be

We could arbitrarily say that anything unspecified goes after what
shows up in lsm.order (like lsm.order=yama,smack,* )
John Johansen Sept. 17, 2018, 11:26 p.m. UTC | #17
On 09/17/2018 04:20 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>> Landlock, because it target unprivileged users, should only be called
>> after all other major (access-control) LSMs. The admin or distro must
>> not be able to change that order in any way. This constraint doesn't
>> apply to current LSMs, though.
> 
> Good point! It will be easy to add LSM_ORDER_LAST, though, given the
> machinery introduced in this series.
> 

And when we have two LSMs that want to use that?
Kees Cook Sept. 17, 2018, 11:28 p.m. UTC | #18
On Mon, Sep 17, 2018 at 4:26 PM, John Johansen
<john.johansen@canonical.com> wrote:
> On 09/17/2018 04:20 PM, Kees Cook wrote:
>> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>> Landlock, because it target unprivileged users, should only be called
>>> after all other major (access-control) LSMs. The admin or distro must
>>> not be able to change that order in any way. This constraint doesn't
>>> apply to current LSMs, though.
>>
>> Good point! It will be easy to add LSM_ORDER_LAST, though, given the
>> machinery introduced in this series.
>>
>
> And when we have two LSMs that want to use that?

We'll cross that bridge when we come to it, but perhaps "last
exclusive"? (lsm.enable/disable to choose)

-Kees
Casey Schaufler Sept. 17, 2018, 11:30 p.m. UTC | #19
On 9/17/2018 4:20 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>> Landlock, because it target unprivileged users, should only be called
>> after all other major (access-control) LSMs. The admin or distro must
>> not be able to change that order in any way. This constraint doesn't
>> apply to current LSMs, though.

What harm would it cause for Landlock to get called before SELinux?
I certainly see why it seems like it ought to get called after, but
would it really make a difference?

> Good point! It will be easy to add LSM_ORDER_LAST, though, given the
> machinery introduced in this series.
>
> -Kees
>
Casey Schaufler Sept. 17, 2018, 11:40 p.m. UTC | #20
On 9/17/2018 4:28 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 4:26 PM, John Johansen
> <john.johansen@canonical.com> wrote:
>> On 09/17/2018 04:20 PM, Kees Cook wrote:
>>> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>>> Landlock, because it target unprivileged users, should only be called
>>>> after all other major (access-control) LSMs. The admin or distro must
>>>> not be able to change that order in any way. This constraint doesn't
>>>> apply to current LSMs, though.
>>> Good point! It will be easy to add LSM_ORDER_LAST, though, given the
>>> machinery introduced in this series.
>>>
>> And when we have two LSMs that want to use that?
> We'll cross that bridge when we come to it, but perhaps "last
> exclusive"? (lsm.enable/disable to choose)

If we define restrictions on use of LSM_ORDER_LAST like we have
for LSM_ORDER_FIRST (only for capabilities) before anyone starts
abusing it we may be OK. Since an LSM_ORDER_LAST has to know that
it can't count on getting called (a non-last module may return -EACCES)
I don't see any way that having multiple LSM_ORDER_LAST modules in
any given order would be a real problem. Of course, a module could be
doing state management that *really* requires it be last, but that
would be a badly designed module and someone sensible would NAK it.
Mickaël Salaün Sept. 17, 2018, 11:47 p.m. UTC | #21
On 9/18/18 01:30, Casey Schaufler wrote:
> On 9/17/2018 4:20 PM, Kees Cook wrote:
>> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>> Landlock, because it target unprivileged users, should only be called
>>> after all other major (access-control) LSMs. The admin or distro must
>>> not be able to change that order in any way. This constraint doesn't
>>> apply to current LSMs, though.
> 
> What harm would it cause for Landlock to get called before SELinux?
> I certainly see why it seems like it ought to get called after, but
> would it really make a difference?

If an unprivileged process is able to infer some properties of a file
being requested (thanks to one of its eBPF program doing checks on this
process accesses), whereas this file access would be denied by a
privileged LSM, then there is a side channel attack allowing this
process to indirectly get information otherwise inaccessible.

In other words, an unprivileged process should not be allowed to sneak
itself (via an eBPF program) before SELinux for instance. SELinux should
be able to block such information gathering the same way it can block a
fstat(2) requested by a process.
Kees Cook Sept. 18, 2018, midnight UTC | #22
On Mon, Sep 17, 2018 at 3:36 PM, John Johansen
<john.johansen@canonical.com> wrote:
> On 09/17/2018 02:57 PM, Casey Schaufler wrote:
>> Modules not listed may go anywhere there is a "*" in the order.
>> An lsm.order= without a "*" is an error, and ignored.
>> If a module is specified in lsm.order but not built in it is ignored.
>> If a module is specified but disabled it is ignored.
>> The capability module goes first regardless.
>
> I don't mind using lsm.order if we must but really do not like the '*'
> idea. It makes this way more complicated than it needs to be

Having the "*" means that _not_ having it in "lsm.order=" is an
implicit form of LSM disabling. And I think we've gotten to the point
where we agree on the enable/disable logic, so I don't want to mess
that up again.

For enable/disable, I think we're agreed on:

    lsm.enable=$lsm
    lsm.disable=$lsm

lsm.disable takes precedent for disabling. (e.g. "lsm.disable=apparmor
apparmor.enable=1" will leave apparmor disabled)
lsm.enable will allow per-LSM enable/disable to operate. (e.g.
"lsm.enable=apparmor apparmor.enable=0" will leave apparmor disabled)

lsm.enable/disable ordering will be "last match": "lsm.disable=smack
lsm.enable=smack" will leave smack enabled. The legacy per-LSM
enable/disable ordering is the same, but ordering between
lsm.enable/disable and the per-LSM options is NOT ordered. i.e. the
precedent mentioned in the prior paragraph.

To support "security=", we'll still have some kind of legacy
LSM_FLAG_MAJOR to perform implicit disabling of the non-operational
other "major" LSMs. This means "security=$foo" will be a short-hand
for "lsm.disable=all-LSM_FLAG_MAJOR-who-are-not-$foo". This will
exactly match current behavior (i.e. "security=smack" and if smack
fails initialization, we do not then fall back to another major).


I think we have to support runtime ordering for the reasons John
specifies. Additionally, I have the sense that anything we can
configure in Kconfig ultimately ends up being expressed at runtime
too, so better to just make sure the design includes it now.

What we have now:

"first" then "order-doesn't-matter-minors" then "exclusive-major"

- we can't change first.
- exclusivity-ordering only matters in the face of enable/disable
which we have solved now (?)

so, ordering can be totally arbitrary after "first" (but before some
future "last"). We must not allow a token for "everything else" since
that overlaps with enable/disable, so "everything else" stay implicit
(I would argue a trailing implicit ordering).

The one complication I see with ordering, then, is that if we change
the exclusivity over time, we change what may be present on the
system. For example, right now tomoyo is exclusive. Once we have
blob-sharing, it doesn't need to be.

so: lsm.order=tomoyo  after this series means
"capability,tomoyo,yama,loadpin,integrity", but when tomoyo becomes
non-exclusive, suddenly we get
"capability,tomoyo,yama,loadpin,{selinux,smack,apparmor},integrity".
(i.e. if selinux is disabled then move on to trying smack, then
apparmor, etc.)

I would argue that this is a design feature (LSMs aren't left behind),
and order of enabled exclusive LSMs "wins" the choice for the
exclusivity (instead of operating "by name" the way "security="
works).

-Kees
Casey Schaufler Sept. 18, 2018, midnight UTC | #23
On 9/17/2018 4:47 PM, Mickaël Salaün wrote:
> On 9/18/18 01:30, Casey Schaufler wrote:
>> On 9/17/2018 4:20 PM, Kees Cook wrote:
>>> On Mon, Sep 17, 2018 at 4:10 PM, Mickaël Salaün <mic@digikod.net> wrote:
>>>> Landlock, because it target unprivileged users, should only be called
>>>> after all other major (access-control) LSMs. The admin or distro must
>>>> not be able to change that order in any way. This constraint doesn't
>>>> apply to current LSMs, though.
>> What harm would it cause for Landlock to get called before SELinux?
>> I certainly see why it seems like it ought to get called after, but
>> would it really make a difference?
> If an unprivileged process is able to infer some properties of a file
> being requested (thanks to one of its eBPF program doing checks on this
> process accesses), whereas this file access would be denied by a
> privileged LSM, then there is a side channel attack allowing this
> process to indirectly get information otherwise inaccessible.
>
> In other words, an unprivileged process should not be allowed to sneak
> itself (via an eBPF program) before SELinux for instance. SELinux should
> be able to block such information gathering the same way it can block a
> fstat(2) requested by a process.

The argument would feel a bit stronger if LSM checks happened before
the DAC checks. The opportunity to sneak a check in already exists, but
not with the tools you get with eBPF. For now at least I'll grant that
there's good reason for Landlock to go last.
Casey Schaufler Sept. 18, 2018, 12:24 a.m. UTC | #24
On 9/17/2018 5:00 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 3:36 PM, John Johansen
> <john.johansen@canonical.com> wrote:
>> On 09/17/2018 02:57 PM, Casey Schaufler wrote:
>>> Modules not listed may go anywhere there is a "*" in the order.
>>> An lsm.order= without a "*" is an error, and ignored.
>>> If a module is specified in lsm.order but not built in it is ignored.
>>> If a module is specified but disabled it is ignored.
>>> The capability module goes first regardless.
>> I don't mind using lsm.order if we must but really do not like the '*'
>> idea. It makes this way more complicated than it needs to be
> Having the "*" means that _not_ having it in "lsm.order=" is an
> implicit form of LSM disabling.

That's not what I said. What I said was that without a "*" the ordering
goes back to what was specified at build time. lsm.order does nothing
with enablement or disablement. If you say "lsm.order=smack,sara,*" and
sara is not compiled in you get smack followed by everything else.

> And I think we've gotten to the point
> where we agree on the enable/disable logic, so I don't want to mess
> that up again.
>
> For enable/disable, I think we're agreed on:
>
>     lsm.enable=$lsm
>     lsm.disable=$lsm

Works for me.

> lsm.disable takes precedent for disabling. (e.g. "lsm.disable=apparmor
> apparmor.enable=1" will leave apparmor disabled)
> lsm.enable will allow per-LSM enable/disable to operate. (e.g.
> "lsm.enable=apparmor apparmor.enable=0" will leave apparmor disabled)
>
> lsm.enable/disable ordering will be "last match": "lsm.disable=smack
> lsm.enable=smack" will leave smack enabled.

So far do good.

> The legacy per-LSM
> enable/disable ordering is the same, but ordering between
> lsm.enable/disable and the per-LSM options is NOT ordered. i.e. the
> precedent mentioned in the prior paragraph.

That is, capability,yama,loadpin,<major>

> To support "security=", we'll still have some kind of legacy
> LSM_FLAG_MAJOR to perform implicit disabling of the non-operational
> other "major" LSMs. This means "security=$foo" will be a short-hand
> for "lsm.disable=all-LSM_FLAG_MAJOR-who-are-not-$foo". This will
> exactly match current behavior (i.e. "security=smack" and if smack
> fails initialization, we do not then fall back to another major).

Right.

> I think we have to support runtime ordering for the reasons John
> specifies. Additionally, I have the sense that anything we can
> configure in Kconfig ultimately ends up being expressed at runtime
> too, so better to just make sure the design includes it now.

Right.

> What we have now:
>
> "first" then "order-doesn't-matter-minors" then "exclusive-major"
>
> - we can't change first.
> - exclusivity-ordering only matters in the face of enable/disable
> which we have solved now (?)

I'm not sure where you get the conclusion we've solved this.
Today I can't say "lsm.enable=smack lsm.enable=apparmor", and
there's no mechanism to prevent that.

> so, ordering can be totally arbitrary after "first" (but before some
> future "last"). We must not allow a token for "everything else" since
> that overlaps with enable/disable, so "everything else" stay implicit
> (I would argue a trailing implicit ordering).

There's an assumption you're making that I'm not getting. Where does
this overlap between ordering and enable/disable come from?

> The one complication I see with ordering, then, is that if we change
> the exclusivity over time, we change what may be present on the
> system. For example, right now tomoyo is exclusive. Once we have
> blob-sharing, it doesn't need to be.
>
> so: lsm.order=tomoyo  after this series means
> "capability,tomoyo,yama,loadpin,integrity", but when tomoyo becomes
> non-exclusive, suddenly we get
> "capability,tomoyo,yama,loadpin,{selinux,smack,apparmor},integrity".
> (i.e. if selinux is disabled then move on to trying smack, then
> apparmor, etc.)

We're missing a description of what happens at build time.
It's hard to see what you expect to happen if I want to build in
all the major modules and don't plan to use the boot command line
options.

> I would argue that this is a design feature (LSMs aren't left behind),
> and order of enabled exclusive LSMs "wins" the choice for the
> exclusivity (instead of operating "by name" the way "security="
> works).

I think I see more, but I'm guessing. At build time it looks like
you're dropping the specification on the "major" module. We can't
do that because I want to build kernels that run Smack by default
but include SELinux for when I'm feeling less evil than normal.
Kees Cook Sept. 18, 2018, 12:45 a.m. UTC | #25
On Mon, Sep 17, 2018 at 5:24 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 9/17/2018 5:00 PM, Kees Cook wrote:
>> The legacy per-LSM
>> enable/disable ordering is the same, but ordering between
>> lsm.enable/disable and the per-LSM options is NOT ordered. i.e. the
>> precedent mentioned in the prior paragraph.
>
> That is, capability,yama,loadpin,<major>

Yeah, sorry, I didn't mean LSM order there, I meant the commandline
order of appearance of the options. If you mix them, the last
lsm.enable/disable for an LSM is the "real" setting, and the last
$LSM.enabled= setting is the last of _that_ one.

>> To support "security=", we'll still have some kind of legacy
>> LSM_FLAG_MAJOR to perform implicit disabling of the non-operational
>> other "major" LSMs. This means "security=$foo" will be a short-hand
>> for "lsm.disable=all-LSM_FLAG_MAJOR-who-are-not-$foo". This will
>> exactly match current behavior (i.e. "security=smack" and if smack
>> fails initialization, we do not then fall back to another major).
>
> Right.

Cool.

>> I think we have to support runtime ordering for the reasons John
>> specifies. Additionally, I have the sense that anything we can
>> configure in Kconfig ultimately ends up being expressed at runtime
>> too, so better to just make sure the design includes it now.
>
> Right.
>
>> What we have now:
>>
>> "first" then "order-doesn't-matter-minors" then "exclusive-major"
>>
>> - we can't change first.
>> - exclusivity-ordering only matters in the face of enable/disable
>> which we have solved now (?)
>
> I'm not sure where you get the conclusion we've solved this.
> Today I can't say "lsm.enable=smack lsm.enable=apparmor", and
> there's no mechanism to prevent that.
>
>> so, ordering can be totally arbitrary after "first" (but before some
>> future "last"). We must not allow a token for "everything else" since
>> that overlaps with enable/disable, so "everything else" stay implicit
>> (I would argue a trailing implicit ordering).
>
> There's an assumption you're making that I'm not getting. Where does
> this overlap between ordering and enable/disable come from?

Handling exclusivity means the non-active LSMs are disabled. We had
been saying "the other majors are disabled", but the concept of major
will become arbitrary. If instead we move to "first exclusive wins
among the exclusives", we still have the "the others are disabled"
case. So exclusivity begets disabling.

>> The one complication I see with ordering, then, is that if we change
>> the exclusivity over time, we change what may be present on the
>> system. For example, right now tomoyo is exclusive. Once we have
>> blob-sharing, it doesn't need to be.
>>
>> so: lsm.order=tomoyo  after this series means
>> "capability,tomoyo,yama,loadpin,integrity", but when tomoyo becomes
>> non-exclusive, suddenly we get
>> "capability,tomoyo,yama,loadpin,{selinux,smack,apparmor},integrity".
>> (i.e. if selinux is disabled then move on to trying smack, then
>> apparmor, etc.)
>
> We're missing a description of what happens at build time.
> It's hard to see what you expect to happen if I want to build in
> all the major modules and don't plan to use the boot command line
> options.
>
>> I would argue that this is a design feature (LSMs aren't left behind),
>> and order of enabled exclusive LSMs "wins" the choice for the
>> exclusivity (instead of operating "by name" the way "security="
>> works).
>
> I think I see more, but I'm guessing. At build time it looks like
> you're dropping the specification on the "major" module. We can't
> do that because I want to build kernels that run Smack by default
> but include SELinux for when I'm feeling less evil than normal.

Do we need build time _ordering_, or can we just go with build time
"first exclusive"? For the v1, I went with "first exclusive" from
CONFIG_SECURITY_DEFAULT, and left the rest of the ordering up to the
Makefile.

-Kees
Casey Schaufler Sept. 18, 2018, 12:57 a.m. UTC | #26
On 9/17/2018 5:45 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 5:24 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 9/17/2018 5:00 PM, Kees Cook wrote:
>>> The legacy per-LSM
>>> enable/disable ordering is the same, but ordering between
>>> lsm.enable/disable and the per-LSM options is NOT ordered. i.e. the
>>> precedent mentioned in the prior paragraph.
>> That is, capability,yama,loadpin,<major>
> Yeah, sorry, I didn't mean LSM order there, I meant the commandline
> order of appearance of the options. If you mix them, the last
> lsm.enable/disable for an LSM is the "real" setting, and the last
> $LSM.enabled= setting is the last of _that_ one.
>
>>> To support "security=", we'll still have some kind of legacy
>>> LSM_FLAG_MAJOR to perform implicit disabling of the non-operational
>>> other "major" LSMs. This means "security=$foo" will be a short-hand
>>> for "lsm.disable=all-LSM_FLAG_MAJOR-who-are-not-$foo". This will
>>> exactly match current behavior (i.e. "security=smack" and if smack
>>> fails initialization, we do not then fall back to another major).
>> Right.
> Cool.
>
>>> I think we have to support runtime ordering for the reasons John
>>> specifies. Additionally, I have the sense that anything we can
>>> configure in Kconfig ultimately ends up being expressed at runtime
>>> too, so better to just make sure the design includes it now.
>> Right.
>>
>>> What we have now:
>>>
>>> "first" then "order-doesn't-matter-minors" then "exclusive-major"
>>>
>>> - we can't change first.
>>> - exclusivity-ordering only matters in the face of enable/disable
>>> which we have solved now (?)
>> I'm not sure where you get the conclusion we've solved this.
>> Today I can't say "lsm.enable=smack lsm.enable=apparmor", and
>> there's no mechanism to prevent that.
>>
>>> so, ordering can be totally arbitrary after "first" (but before some
>>> future "last"). We must not allow a token for "everything else" since
>>> that overlaps with enable/disable, so "everything else" stay implicit
>>> (I would argue a trailing implicit ordering).
>> There's an assumption you're making that I'm not getting. Where does
>> this overlap between ordering and enable/disable come from?
> Handling exclusivity means the non-active LSMs are disabled. We had
> been saying "the other majors are disabled", but the concept of major
> will become arbitrary. If instead we move to "first exclusive wins
> among the exclusives", we still have the "the others are disabled"
> case. So exclusivity begets disabling.
>
>>> The one complication I see with ordering, then, is that if we change
>>> the exclusivity over time, we change what may be present on the
>>> system. For example, right now tomoyo is exclusive. Once we have
>>> blob-sharing, it doesn't need to be.
>>>
>>> so: lsm.order=tomoyo  after this series means
>>> "capability,tomoyo,yama,loadpin,integrity", but when tomoyo becomes
>>> non-exclusive, suddenly we get
>>> "capability,tomoyo,yama,loadpin,{selinux,smack,apparmor},integrity".
>>> (i.e. if selinux is disabled then move on to trying smack, then
>>> apparmor, etc.)
>> We're missing a description of what happens at build time.
>> It's hard to see what you expect to happen if I want to build in
>> all the major modules and don't plan to use the boot command line
>> options.
>>
>>> I would argue that this is a design feature (LSMs aren't left behind),
>>> and order of enabled exclusive LSMs "wins" the choice for the
>>> exclusivity (instead of operating "by name" the way "security="
>>> works).
>> I think I see more, but I'm guessing. At build time it looks like
>> you're dropping the specification on the "major" module. We can't
>> do that because I want to build kernels that run Smack by default
>> but include SELinux for when I'm feeling less evil than normal.
> Do we need build time _ordering_, or can we just go with build time
> "first exclusive"? For the v1, I went with "first exclusive" from
> CONFIG_SECURITY_DEFAULT, and left the rest of the ordering up to the
> Makefile.

If I read you correctly, "first exclusive" would suit my needs just fine.
I like the notion of build time ordering because I hate using the boot
command line.
Kees Cook Sept. 18, 2018, 12:59 a.m. UTC | #27
On Mon, Sep 17, 2018 at 5:57 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
> If I read you correctly, "first exclusive" would suit my needs just fine.
> I like the notion of build time ordering because I hate using the boot
> command line.

Okay, excellent. I think I have enough for a v2 on this. I'll crank it out...

-Kees
John Johansen Sept. 18, 2018, 1:08 a.m. UTC | #28
On 09/17/2018 05:45 PM, Kees Cook wrote:
> On Mon, Sep 17, 2018 at 5:24 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>> On 9/17/2018 5:00 PM, Kees Cook wrote:
>>> The legacy per-LSM
>>> enable/disable ordering is the same, but ordering between
>>> lsm.enable/disable and the per-LSM options is NOT ordered. i.e. the
>>> precedent mentioned in the prior paragraph.
>>
>> That is, capability,yama,loadpin,<major>
> 
> Yeah, sorry, I didn't mean LSM order there, I meant the commandline
> order of appearance of the options. If you mix them, the last
> lsm.enable/disable for an LSM is the "real" setting, and the last
> $LSM.enabled= setting is the last of _that_ one.
> 
>>> To support "security=", we'll still have some kind of legacy
>>> LSM_FLAG_MAJOR to perform implicit disabling of the non-operational
>>> other "major" LSMs. This means "security=$foo" will be a short-hand
>>> for "lsm.disable=all-LSM_FLAG_MAJOR-who-are-not-$foo". This will
>>> exactly match current behavior (i.e. "security=smack" and if smack
>>> fails initialization, we do not then fall back to another major).
>>
>> Right.
> 
> Cool.
> 
>>> I think we have to support runtime ordering for the reasons John
>>> specifies. Additionally, I have the sense that anything we can
>>> configure in Kconfig ultimately ends up being expressed at runtime
>>> too, so better to just make sure the design includes it now.
>>
>> Right.
>>
>>> What we have now:
>>>
>>> "first" then "order-doesn't-matter-minors" then "exclusive-major"
>>>
>>> - we can't change first.
>>> - exclusivity-ordering only matters in the face of enable/disable
>>> which we have solved now (?)
>>
>> I'm not sure where you get the conclusion we've solved this.
>> Today I can't say "lsm.enable=smack lsm.enable=apparmor", and
>> there's no mechanism to prevent that.
>>
>>> so, ordering can be totally arbitrary after "first" (but before some
>>> future "last"). We must not allow a token for "everything else" since
>>> that overlaps with enable/disable, so "everything else" stay implicit
>>> (I would argue a trailing implicit ordering).
>>
>> There's an assumption you're making that I'm not getting. Where does
>> this overlap between ordering and enable/disable come from?
> 
> Handling exclusivity means the non-active LSMs are disabled. We had
> been saying "the other majors are disabled", but the concept of major
> will become arbitrary. If instead we move to "first exclusive wins
> among the exclusives", we still have the "the others are disabled"
> case. So exclusivity begets disabling.
> 
>>> The one complication I see with ordering, then, is that if we change
>>> the exclusivity over time, we change what may be present on the
>>> system. For example, right now tomoyo is exclusive. Once we have
>>> blob-sharing, it doesn't need to be.
>>>
>>> so: lsm.order=tomoyo  after this series means
>>> "capability,tomoyo,yama,loadpin,integrity", but when tomoyo becomes
>>> non-exclusive, suddenly we get
>>> "capability,tomoyo,yama,loadpin,{selinux,smack,apparmor},integrity".
>>> (i.e. if selinux is disabled then move on to trying smack, then
>>> apparmor, etc.)
>>
>> We're missing a description of what happens at build time.
>> It's hard to see what you expect to happen if I want to build in
>> all the major modules and don't plan to use the boot command line
>> options.
>>
>>> I would argue that this is a design feature (LSMs aren't left behind),
>>> and order of enabled exclusive LSMs "wins" the choice for the
>>> exclusivity (instead of operating "by name" the way "security="
>>> works).
>>
>> I think I see more, but I'm guessing. At build time it looks like
>> you're dropping the specification on the "major" module. We can't
>> do that because I want to build kernels that run Smack by default
>> but include SELinux for when I'm feeling less evil than normal.
> 
> Do we need build time _ordering_, or can we just go with build time

depends on what you mean by build time ordering. Ordering like we
currently have based on link order, no. The ability to specify
the lsm order just like on the command line yes.

Distros are very much going to have a preferred order they want
LSMs to make supporting this more tractable when trying to deal
with issues.

> "first exclusive"? For the v1, I went with "first exclusive" from
> CONFIG_SECURITY_DEFAULT, and left the rest of the ordering up to the
> Makefile.
> 

First exclusive from CONFIG_SECURITY_DEFAULT is fine for now, I am
more interested in making sure we get it right for when exclusivity
goes away.
diff mbox series

Patch

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 9871e649ffef..6d6bb9481193 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4027,11 +4027,14 @@ 
 			Note: increases power consumption, thus should only be
 			enabled if running jitter sensitive (HPC/RT) workloads.
 
-	security=	[SECURITY] Choose a security module to enable at boot.
-			If this boot parameter is not specified, only the first
-			security module asking for security registration will be
-			loaded. An invalid security module name will be treated
-			as if no module has been chosen.
+	security=	[SECURITY] An ordered comma-separated list of
+			security modules to attempt to enable at boot. If
+			this boot parameter is not specified, only the
+			security modules asking for initialization will be
+			enabled (see CONFIG_DEFAULT_SECURITY). Duplicate
+			or invalid security modules will be ignored. The
+			capability module is always loaded first, without
+			regard to this parameter.
 
 	selinux=	[SELINUX] Disable or enable SELinux at boot time.
 			Format: { "0" | "1" }
diff --git a/security/security.c b/security/security.c
index 67532326a0ce..f09a4bb3cb86 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,17 +32,18 @@ 
 
 #define MAX_LSM_EVM_XATTR	2
 
-/* Maximum number of letters for an LSM name string */
-#define SECURITY_NAME_MAX	10
+/* How many LSMs were built into the kernel? */
+#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
 
 struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
 
 char *lsm_names;
 /* Boot-time LSM user choice */
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
-	CONFIG_DEFAULT_SECURITY;
+static const char *bootparam_lsms;
 
+/* Ordered list of possible LSMs to initialize. */
+static struct lsm_info **possible_lsms __initdata;
 static struct lsm_info *exclusive __initdata;
 
 /* Mark an LSM's enabled flag, if it exists. */
@@ -52,6 +53,108 @@  static void __init set_enabled(struct lsm_info *lsm, bool enabled)
 		*lsm->enabled = enabled;
 }
 
+/* Is an LSM already listed in the possible LSMs list? */
+static bool __init possible_lsm(struct lsm_info *lsm)
+{
+	struct lsm_info **check;
+
+	for (check = possible_lsms; *check; check++)
+		if (*check == lsm)
+			return true;
+
+	return false;
+}
+
+/* Append an LSM to the list of possible LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_possible_lsm(struct lsm_info *lsm, const char *from)
+{
+	/* Ignore duplicate selections. */
+	if (possible_lsm(lsm)) {
+		return;
+	}
+
+	if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from))
+		return;
+
+	possible_lsms[last_lsm++] = lsm;
+}
+
+/* Default boot: populate possible LSMs list with builtin ordering. */
+static void __init prepare_lsm_order_builtin(void)
+{
+	struct lsm_info *lsm;
+
+	/* All minor LSMs should go next. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->type == LSM_TYPE_MINOR &&
+		    lsm->order == LSM_ORDER_MUTABLE)
+			append_possible_lsm(lsm, "builtin minor");
+	}
+
+	/* Then the CONFIG_DEFAULT_SECURITY exclusive LSM. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->type == LSM_TYPE_EXCLUSIVE &&
+		    !strcmp(CONFIG_DEFAULT_SECURITY, lsm->name))
+			append_possible_lsm(lsm, "builtin default");
+	}
+
+	/* Then other exclusive LSMs, in case above is disabled. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->type == LSM_TYPE_EXCLUSIVE &&
+		    strcmp(CONFIG_DEFAULT_SECURITY, lsm->name))
+			append_possible_lsm(lsm, "builtin extra");
+	}
+}
+
+/* "security=" boot: populate possible LSMs list from boot commandline. */
+static void __init prepare_lsm_order_commandline(void)
+{
+	struct lsm_info *lsm;
+	char *sep, *name, *next;
+
+	sep = kstrdup(bootparam_lsms, GFP_KERNEL);
+	next = sep;
+	/* Walk commandline list, looking for matching LSMs. */
+	while ((name = strsep(&next, ",")) != NULL) {
+		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+			if (lsm->order == LSM_ORDER_MUTABLE &&
+			    !strcmp(lsm->name, name)) {
+				append_possible_lsm(lsm, "commandline");
+			}
+		}
+	}
+	kfree(sep);
+
+	/* Mark any LSMs missing from commandline as explicitly disabled. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->order == LSM_ORDER_MUTABLE) {
+			if (possible_lsm(lsm))
+				continue;
+
+			set_enabled(lsm, false);
+		}
+	}
+}
+
+/* Populate possible LSMs list from build order or commandline order. */
+static void __init prepare_lsm_order(void)
+{
+	struct lsm_info *lsm;
+
+	/* LSM_ORDER_FIRST is always first. */
+	for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+		if (lsm->order == LSM_ORDER_FIRST)
+			append_possible_lsm(lsm, "first");
+	}
+
+	/* If no commandline order defined, use builtin order. */
+	if (!bootparam_lsms)
+		prepare_lsm_order_builtin();
+	else
+		prepare_lsm_order_commandline();
+}
+
 /* Is an LSM allowed to be enabled? */
 static bool __init lsm_enabled(struct lsm_info *lsm)
 {
@@ -69,10 +172,6 @@  static bool __init lsm_enabled(struct lsm_info *lsm)
 	if (exclusive)
 		return false;
 
-	/* Disabled if this LSM isn't the chosen one. */
-	if (strcmp(lsm->name, chosen_lsm) != 0)
-		return false;
-
 	return true;
 }
 
@@ -93,17 +192,13 @@  static void __init maybe_enable_lsm(struct lsm_info *lsm)
 	}
 }
 
-static void __init lsm_init(enum lsm_type type)
+/* Initialize all possible LSMs in order, if they are enabled. */
+static void __init lsm_init(void)
 {
-	struct lsm_info *lsm;
-	enum lsm_order order;
+	struct lsm_info **lsm;
 
-	for (order = LSM_ORDER_FIRST; order < LSM_ORDER_MAX; order++) {
-		for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
-			if (lsm->type == type && lsm->order == order)
-				maybe_enable_lsm(lsm);
-		}
-	}
+	for (lsm = possible_lsms; *lsm; lsm++)
+		maybe_enable_lsm(*lsm);
 }
 
 /**
@@ -119,25 +214,21 @@  int __init security_init(void)
 	for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head);
 	     i++)
 		INIT_HLIST_HEAD(&list[i]);
+	possible_lsms = kcalloc(LSM_COUNT + 1, sizeof(*possible_lsms),
+				GFP_KERNEL);
 	pr_info("Security Framework initialized\n");
 
-	/*
-	 * Load minor LSMs, with the capability module always first.
-	 */
-	lsm_init(LSM_TYPE_MINOR);
-
-	/*
-	 * Load all the remaining security modules.
-	 */
-	lsm_init(LSM_TYPE_EXCLUSIVE);
+	prepare_lsm_order();
+	lsm_init();
 
+	kfree(possible_lsms);
 	return 0;
 }
 
 /* Save user chosen LSM */
 static int __init choose_lsm(char *str)
 {
-	strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+	bootparam_lsms = str;
 	return 1;
 }
 __setup("security=", choose_lsm);