diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index e28a3aa639e8..c3843b33da9e 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2043,6 +2043,7 @@ extern void security_add_hooks(struct security_hook_list *hooks, int count, char *lsm); #define LSM_FLAG_LEGACY_MAJOR BIT(0) +#define LSM_FLAG_EXCLUSIVE BIT(1) struct lsm_info { const char *name; /* Required. */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index dfc5fbf8ba82..149a3e16b5da 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1723,7 +1723,7 @@ alloc_out: DEFINE_LSM(apparmor) = { .name = "apparmor", - .flags = LSM_FLAG_LEGACY_MAJOR, + .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .enabled = &apparmor_enabled, .init = apparmor_init, }; diff --git a/security/security.c b/security/security.c index 88de6b073246..a8dd7defe30a 100644 --- a/security/security.c +++ b/security/security.c @@ -49,6 +49,7 @@ static __initconst const char * const builtin_lsm_order = CONFIG_LSM; /* Ordered list of LSMs to initialize. */ static __initdata struct lsm_info **ordered_lsms; +static __initdata struct lsm_info *exclusive; static __initdata bool debug; #define init_debug(...) \ @@ -129,6 +130,12 @@ static bool __init lsm_allowed(struct lsm_info *lsm) if (!is_enabled(lsm)) return false; + /* Not allowed if another exclusive LSM already initialized. */ + if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) { + init_debug("exclusive disabled: %s\n", lsm->name); + return false; + } + return true; } @@ -144,6 +151,11 @@ static void __init maybe_initialize_lsm(struct lsm_info *lsm) if (enabled) { int ret; + if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) { + exclusive = lsm; + init_debug("exclusive chosen: %s\n", lsm->name); + } + init_debug("initializing %s\n", lsm->name); ret = lsm->init(); WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 0f8ae2fbd14a..49865f119b16 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6989,7 +6989,7 @@ void selinux_complete_init(void) all processes and objects when they are created. */ DEFINE_LSM(selinux) = { .name = "selinux", - .flags = LSM_FLAG_LEGACY_MAJOR, + .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .enabled = &selinux_enabled, .init = selinux_init, }; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 580e9d6e5680..780733341d02 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4809,6 +4809,6 @@ static __init int smack_init(void) */ DEFINE_LSM(smack) = { .name = "smack", - .flags = LSM_FLAG_LEGACY_MAJOR, + .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .init = smack_init, }; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index a46f6bc1e97c..daff7d7897ad 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -550,6 +550,6 @@ static int __init tomoyo_init(void) DEFINE_LSM(tomoyo) = { .name = "tomoyo", - .flags = LSM_FLAG_LEGACY_MAJOR, + .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .init = tomoyo_init, };