Message ID | 20180916003059.1046-17-keescook@chromium.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | LSM: Prepare for explict LSM ordering | expand |
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.
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
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.
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 >
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
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
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
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".
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.
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
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.
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
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
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
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?
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,* )
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?
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
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 >
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.
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.
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
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.
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.
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
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.
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
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 --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);
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(-)