Message ID | af077529868a212caeb822ae79d72a1ac40f17ba.1522091329.git.sargun@sargun.me (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 26/03/18 22:24, Sargun Dhillon wrote: > This patch introduces a mechanism to add mutable hooks at the end of the > callback chain for each LSM hook. It allows for built-in kernel LSMs > to be unloaded, as well as modular LSMs to be loaded after boot-time. > It also does not compromise the security of hooks which are never > meant to be unloaded. Looking at this from the perspective of really convincing people to use other modules, there is a problem, imho. [...] > /* > * Register with LSM > */ > - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); > + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", > + false); Hardcoding what is (im)mutable will never satisfy everyone. If, instead, this decision was delegated to the kernel command line, it would be possible to have any module to become immutable -or not- depending on the default values and the configuration received at boot. A distro could ship with its defaults and then any user could reconfigure it, without having to recompile or install anything, just editing the command line. -- igor -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: > > > On 26/03/18 22:24, Sargun Dhillon wrote: >> This patch introduces a mechanism to add mutable hooks at the end of the >> callback chain for each LSM hook. It allows for built-in kernel LSMs >> to be unloaded, as well as modular LSMs to be loaded after boot-time. >> It also does not compromise the security of hooks which are never >> meant to be unloaded. > > Looking at this from the perspective of really convincing people to use > other modules, there is a problem, imho. > > [...] > >> /* >> * Register with LSM >> */ >> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >> + false); > > Hardcoding what is (im)mutable will never satisfy everyone. > If, instead, this decision was delegated to the kernel command line, it > would be possible to have any module to become immutable -or not- > depending on the default values and the configuration received at boot. > > A distro could ship with its defaults and then any user could > reconfigure it, without having to recompile or install anything, just > editing the command line. > > -- > igor Today, the only "mutable" module we have is SELinux. It has a kernel config flag which determines if it is unloadable (mutable) or not. If you look at the patchset, it, in fact, sets mutability based on that config flag: - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); Similarly, modules can change this behaviour based on their own choices, whether that be config flags, boot parameters, or similar. In my opinion, most LSMs should never be unloadable. In fact, we don't really have a safe way (in this patchset) to unload the security modules' code safely. Doing this would either require usage of (s)rcu, or a similar concurrency control mechanism. -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 3/26/2018 1:24 PM, Sargun Dhillon wrote: > On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: >> >> On 26/03/18 22:24, Sargun Dhillon wrote: >>> This patch introduces a mechanism to add mutable hooks at the end of the >>> callback chain for each LSM hook. It allows for built-in kernel LSMs >>> to be unloaded, as well as modular LSMs to be loaded after boot-time. >>> It also does not compromise the security of hooks which are never >>> meant to be unloaded. >> Looking at this from the perspective of really convincing people to use >> other modules, there is a problem, imho. >> >> [...] >> >>> /* >>> * Register with LSM >>> */ >>> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >>> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >>> + false); >> Hardcoding what is (im)mutable will never satisfy everyone. >> If, instead, this decision was delegated to the kernel command line, it >> would be possible to have any module to become immutable -or not- >> depending on the default values and the configuration received at boot. >> >> A distro could ship with its defaults and then any user could >> reconfigure it, without having to recompile or install anything, just >> editing the command line. >> >> -- >> igor > Today, the only "mutable" module we have is SELinux. Paul Moore has threatened to remove the "mutable" option from SELinux should it bump up high enough on his priority list. The conditions under which you can disable SELinux are very limited, you can't unload it after the policy has been loaded. > It has a kernel > config flag which determines if it is unloadable (mutable) or not. If > you look at the patchset, it, in fact, sets mutability based on that > config flag: > > > - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); > + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", > + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); > > Similarly, modules can change this behaviour based on their own > choices, whether that be config flags, boot parameters, or similar. In > my opinion, most LSMs should never be unloadable. In fact, we don't > really have a safe way (in this patchset) to unload the security > modules' code safely. Doing this would either require usage of (s)rcu, > or a similar concurrency control mechanism. If you can't safely unload the code, what is the point of making a module unloadable? Start every hook with: if (!gonkulator_enabled) return appropriately; and provide mechanism for flipping the switch. -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Mar 26, 2018 at 2:04 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: > On 3/26/2018 1:24 PM, Sargun Dhillon wrote: >> On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: >>> >>> On 26/03/18 22:24, Sargun Dhillon wrote: >>>> This patch introduces a mechanism to add mutable hooks at the end of the >>>> callback chain for each LSM hook. It allows for built-in kernel LSMs >>>> to be unloaded, as well as modular LSMs to be loaded after boot-time. >>>> It also does not compromise the security of hooks which are never >>>> meant to be unloaded. >>> Looking at this from the perspective of really convincing people to use >>> other modules, there is a problem, imho. >>> >>> [...] >>> >>>> /* >>>> * Register with LSM >>>> */ >>>> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >>>> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >>>> + false); >>> Hardcoding what is (im)mutable will never satisfy everyone. >>> If, instead, this decision was delegated to the kernel command line, it >>> would be possible to have any module to become immutable -or not- >>> depending on the default values and the configuration received at boot. >>> >>> A distro could ship with its defaults and then any user could >>> reconfigure it, without having to recompile or install anything, just >>> editing the command line. >>> >>> -- >>> igor >> Today, the only "mutable" module we have is SELinux. > > Paul Moore has threatened to remove the "mutable" option from > SELinux should it bump up high enough on his priority list. > The conditions under which you can disable SELinux are very > limited, you can't unload it after the policy has been loaded. > >> It has a kernel >> config flag which determines if it is unloadable (mutable) or not. If >> you look at the patchset, it, in fact, sets mutability based on that >> config flag: >> >> >> - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); >> + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", >> + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); >> >> Similarly, modules can change this behaviour based on their own >> choices, whether that be config flags, boot parameters, or similar. In >> my opinion, most LSMs should never be unloadable. In fact, we don't >> really have a safe way (in this patchset) to unload the security >> modules' code safely. Doing this would either require usage of (s)rcu, >> or a similar concurrency control mechanism. > > If you can't safely unload the code, what is the point of making > a module unloadable? Start every hook with: s/module/hook/ Ask the SELinux folk? > > if (!gonkulator_enabled) > return appropriately; > > and provide mechanism for flipping the switch. > I intend to eventually follow-up this patch with a way to safely unload the code, but I'd prefer to get (safe) dynamic *hooking* and *unhooking* first, and then later on we can make it so the code can get unloaded. -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 3/26/2018 2:10 PM, Sargun Dhillon wrote: > On Mon, Mar 26, 2018 at 2:04 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: >> On 3/26/2018 1:24 PM, Sargun Dhillon wrote: >>> On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: >>>> On 26/03/18 22:24, Sargun Dhillon wrote: >>>>> This patch introduces a mechanism to add mutable hooks at the end of the >>>>> callback chain for each LSM hook. It allows for built-in kernel LSMs >>>>> to be unloaded, as well as modular LSMs to be loaded after boot-time. >>>>> It also does not compromise the security of hooks which are never >>>>> meant to be unloaded. >>>> Looking at this from the perspective of really convincing people to use >>>> other modules, there is a problem, imho. >>>> >>>> [...] >>>> >>>>> /* >>>>> * Register with LSM >>>>> */ >>>>> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >>>>> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >>>>> + false); >>>> Hardcoding what is (im)mutable will never satisfy everyone. >>>> If, instead, this decision was delegated to the kernel command line, it >>>> would be possible to have any module to become immutable -or not- >>>> depending on the default values and the configuration received at boot. >>>> >>>> A distro could ship with its defaults and then any user could >>>> reconfigure it, without having to recompile or install anything, just >>>> editing the command line. >>>> >>>> -- >>>> igor >>> Today, the only "mutable" module we have is SELinux. >> Paul Moore has threatened to remove the "mutable" option from >> SELinux should it bump up high enough on his priority list. >> The conditions under which you can disable SELinux are very >> limited, you can't unload it after the policy has been loaded. >> >>> It has a kernel >>> config flag which determines if it is unloadable (mutable) or not. If >>> you look at the patchset, it, in fact, sets mutability based on that >>> config flag: >>> >>> >>> - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); >>> + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", >>> + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); >>> >>> Similarly, modules can change this behaviour based on their own >>> choices, whether that be config flags, boot parameters, or similar. In >>> my opinion, most LSMs should never be unloadable. In fact, we don't >>> really have a safe way (in this patchset) to unload the security >>> modules' code safely. Doing this would either require usage of (s)rcu, >>> or a similar concurrency control mechanism. >> If you can't safely unload the code, what is the point of making >> a module unloadable? Start every hook with: > s/module/hook/ > Ask the SELinux folk? SELinux can safely unload the hooks because they limit the ability to unload to a point before they've started allocating data. They aren't proud of it. I seriously doubt they'd have if if you could run will a NULL policy. >> if (!gonkulator_enabled) >> return appropriately; >> >> and provide mechanism for flipping the switch. >> > I intend to eventually follow-up this patch with a way to safely > unload the code, but I'd prefer to get (safe) dynamic *hooking* and > *unhooking* first, and then later on we can make it so the code can > get unloaded. Unless you want to restrict the unhooking and unloading to a point where no data has been allocated by the module it's going to be difficult to argue that it's safe to unhook and/or unload a module. Sure, SELinux has that restriction, but the use case is a bit questionable. -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, Mar 26, 2018 at 2:46 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: > On 3/26/2018 2:10 PM, Sargun Dhillon wrote: >> On Mon, Mar 26, 2018 at 2:04 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: >>> On 3/26/2018 1:24 PM, Sargun Dhillon wrote: >>>> On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: >>>>> On 26/03/18 22:24, Sargun Dhillon wrote: >>>>>> This patch introduces a mechanism to add mutable hooks at the end of the >>>>>> callback chain for each LSM hook. It allows for built-in kernel LSMs >>>>>> to be unloaded, as well as modular LSMs to be loaded after boot-time. >>>>>> It also does not compromise the security of hooks which are never >>>>>> meant to be unloaded. >>>>> Looking at this from the perspective of really convincing people to use >>>>> other modules, there is a problem, imho. >>>>> >>>>> [...] >>>>> >>>>>> /* >>>>>> * Register with LSM >>>>>> */ >>>>>> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >>>>>> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >>>>>> + false); >>>>> Hardcoding what is (im)mutable will never satisfy everyone. >>>>> If, instead, this decision was delegated to the kernel command line, it >>>>> would be possible to have any module to become immutable -or not- >>>>> depending on the default values and the configuration received at boot. >>>>> >>>>> A distro could ship with its defaults and then any user could >>>>> reconfigure it, without having to recompile or install anything, just >>>>> editing the command line. >>>>> >>>>> -- >>>>> igor >>>> Today, the only "mutable" module we have is SELinux. >>> Paul Moore has threatened to remove the "mutable" option from >>> SELinux should it bump up high enough on his priority list. >>> The conditions under which you can disable SELinux are very >>> limited, you can't unload it after the policy has been loaded. >>> >>>> It has a kernel >>>> config flag which determines if it is unloadable (mutable) or not. If >>>> you look at the patchset, it, in fact, sets mutability based on that >>>> config flag: >>>> >>>> >>>> - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); >>>> + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", >>>> + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); >>>> >>>> Similarly, modules can change this behaviour based on their own >>>> choices, whether that be config flags, boot parameters, or similar. In >>>> my opinion, most LSMs should never be unloadable. In fact, we don't >>>> really have a safe way (in this patchset) to unload the security >>>> modules' code safely. Doing this would either require usage of (s)rcu, >>>> or a similar concurrency control mechanism. >>> If you can't safely unload the code, what is the point of making >>> a module unloadable? Start every hook with: >> s/module/hook/ >> Ask the SELinux folk? > > SELinux can safely unload the hooks because they limit the ability > to unload to a point before they've started allocating data. They > aren't proud of it. I seriously doubt they'd have if if you could > run will a NULL policy. > >>> if (!gonkulator_enabled) >>> return appropriately; >>> >>> and provide mechanism for flipping the switch. >>> >> I intend to eventually follow-up this patch with a way to safely >> unload the code, but I'd prefer to get (safe) dynamic *hooking* and >> *unhooking* first, and then later on we can make it so the code can >> get unloaded. > > Unless you want to restrict the unhooking and unloading to a point > where no data has been allocated by the module it's going to be > difficult to argue that it's safe to unhook and/or unload a module. > Sure, SELinux has that restriction, but the use case is a bit > questionable. > > What's wrong for this in the case of during development, and for minor LSMs? -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 3/26/2018 2:51 PM, Sargun Dhillon wrote: > On Mon, Mar 26, 2018 at 2:46 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: >> On 3/26/2018 2:10 PM, Sargun Dhillon wrote: >>> On Mon, Mar 26, 2018 at 2:04 PM, Casey Schaufler <casey@schaufler-ca.com> wrote: >>>> On 3/26/2018 1:24 PM, Sargun Dhillon wrote: >>>>> On Mon, Mar 26, 2018 at 1:17 PM, Igor Stoppa <igor.stoppa@huawei.com> wrote: >>>>>> On 26/03/18 22:24, Sargun Dhillon wrote: >>>>>>> This patch introduces a mechanism to add mutable hooks at the end of the >>>>>>> callback chain for each LSM hook. It allows for built-in kernel LSMs >>>>>>> to be unloaded, as well as modular LSMs to be loaded after boot-time. >>>>>>> It also does not compromise the security of hooks which are never >>>>>>> meant to be unloaded. >>>>>> Looking at this from the perspective of really convincing people to use >>>>>> other modules, there is a problem, imho. >>>>>> >>>>>> [...] >>>>>> >>>>>>> /* >>>>>>> * Register with LSM >>>>>>> */ >>>>>>> - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); >>>>>>> + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", >>>>>>> + false); >>>>>> Hardcoding what is (im)mutable will never satisfy everyone. >>>>>> If, instead, this decision was delegated to the kernel command line, it >>>>>> would be possible to have any module to become immutable -or not- >>>>>> depending on the default values and the configuration received at boot. >>>>>> >>>>>> A distro could ship with its defaults and then any user could >>>>>> reconfigure it, without having to recompile or install anything, just >>>>>> editing the command line. >>>>>> >>>>>> -- >>>>>> igor >>>>> Today, the only "mutable" module we have is SELinux. >>>> Paul Moore has threatened to remove the "mutable" option from >>>> SELinux should it bump up high enough on his priority list. >>>> The conditions under which you can disable SELinux are very >>>> limited, you can't unload it after the policy has been loaded. >>>> >>>>> It has a kernel >>>>> config flag which determines if it is unloadable (mutable) or not. If >>>>> you look at the patchset, it, in fact, sets mutability based on that >>>>> config flag: >>>>> >>>>> >>>>> - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); >>>>> + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", >>>>> + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); >>>>> >>>>> Similarly, modules can change this behaviour based on their own >>>>> choices, whether that be config flags, boot parameters, or similar. In >>>>> my opinion, most LSMs should never be unloadable. In fact, we don't >>>>> really have a safe way (in this patchset) to unload the security >>>>> modules' code safely. Doing this would either require usage of (s)rcu, >>>>> or a similar concurrency control mechanism. >>>> If you can't safely unload the code, what is the point of making >>>> a module unloadable? Start every hook with: >>> s/module/hook/ >>> Ask the SELinux folk? >> SELinux can safely unload the hooks because they limit the ability >> to unload to a point before they've started allocating data. They >> aren't proud of it. I seriously doubt they'd have if if you could >> run will a NULL policy. >> >>>> if (!gonkulator_enabled) >>>> return appropriately; >>>> >>>> and provide mechanism for flipping the switch. >>>> >>> I intend to eventually follow-up this patch with a way to safely >>> unload the code, but I'd prefer to get (safe) dynamic *hooking* and >>> *unhooking* first, and then later on we can make it so the code can >>> get unloaded. >> Unless you want to restrict the unhooking and unloading to a point >> where no data has been allocated by the module it's going to be >> difficult to argue that it's safe to unhook and/or unload a module. >> Sure, SELinux has that restriction, but the use case is a bit >> questionable. >> >> > What's wrong for this in the case of during development, and for minor LSMs? You can always add ifdefs and unnatural runtime options during development. You don't need infrastructure support for that. I will grant you minor LSMs that don't allocate and/or manage data. As you included in your patchset, you have to identify if a module is "mutable" for this to be a safe feature. My recollection from the early days of LSM that there were objections to unloadable modules for other reasons, but that was long ago and I don't recall them clearly. -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Mon, 26 Mar 2018, Sargun Dhillon wrote: > Today, the only "mutable" module we have is SELinux. It has a kernel > config flag which determines if it is unloadable (mutable) or not. If > you look at the patchset, it, in fact, sets mutability based on that > config flag: > > > - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); > + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", > + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); > There has been discussion about removing the ability to unload SELinux -- not sure what the current status of that is. Regardless, it's a special case for historical reasons and should not be thought of as an example for future use. > Similarly, modules can change this behaviour based on their own > choices, whether that be config flags, boot parameters, or similar. In > my opinion, most LSMs should never be unloadable. All, probably.
On Tue, Mar 27, 2018 at 4:08 AM, James Morris <jmorris@namei.org> wrote: > On Mon, 26 Mar 2018, Sargun Dhillon wrote: >> Today, the only "mutable" module we have is SELinux. It has a kernel >> config flag which determines if it is unloadable (mutable) or not. If >> you look at the patchset, it, in fact, sets mutability based on that >> config flag: >> >> >> - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); >> + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", >> + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); > > There has been discussion about removing the ability to unload SELinux -- > not sure what the current status of that is. It is something I would still like to do, but there is some work that needs to be done to allow a smooth transition for those people who are currently disabling/unloading SELinux at runtime.
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 09bc60fb35f1..c0c98758b1bf 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1981,7 +1981,7 @@ extern struct security_hook_heads security_hook_heads; extern char *lsm_names; extern void security_add_hooks(struct security_hook_list *hooks, int count, - char *lsm); + char *lsm, bool is_mutable); #ifdef CONFIG_SECURITY_SELINUX_DISABLE /* @@ -2006,11 +2006,12 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, } #endif /* CONFIG_SECURITY_SELINUX_DISABLE */ +#define __lsm_ro_after_init __ro_after_init /* Currently required to handle SELinux runtime hook disable. */ #ifdef CONFIG_SECURITY_WRITABLE_HOOKS -#define __lsm_ro_after_init +#define __lsm_mutable_after_init #else -#define __lsm_ro_after_init __ro_after_init +#define __lsm_mutable_after_init __ro_after_init #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ extern int __init security_module_enable(const char *module); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9a65eeaf7dfa..d6cca8169df0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1155,7 +1155,7 @@ static int __init apparmor_init(void) goto buffers_out; } security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks), - "apparmor"); + "apparmor", false); /* Report that AppArmor successfully initialized */ apparmor_initialized = 1; diff --git a/security/commoncap.c b/security/commoncap.c index 48620c93d697..fe4b0d9d44ce 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1363,7 +1363,7 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { void __init capability_add_hooks(void) { security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks), - "capability"); + "capability", false); } #endif /* CONFIG_SECURITY */ diff --git a/security/security.c b/security/security.c index 3cafff61b049..c021a34ffe4c 100644 --- a/security/security.c +++ b/security/security.c @@ -30,12 +30,16 @@ #include <linux/string.h> #include <net/flow.h> +#define SECURITY_HOOK_COUNT \ + (sizeof(security_hook_heads) / sizeof(struct hlist_head)) #define MAX_LSM_EVM_XATTR 2 /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 struct security_hook_heads security_hook_heads __lsm_ro_after_init; +EXPORT_SYMBOL_GPL(security_hook_heads); + static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); char *lsm_names; @@ -53,6 +57,55 @@ static void __init do_security_initcalls(void) } } +#ifdef CONFIG_SECURITY_WRITABLE_HOOKS +static void security_add_hook(struct security_hook_list *hook, bool is_mutable) +{ + struct security_hook_list *mutable_hook; + union { + void *cb_ptr; + union security_list_options slo; + } hook_options; + + hlist_for_each_entry(mutable_hook, hook->head, list) { + hook_options.slo = mutable_hook->hook; + if (hook_options.cb_ptr) + continue; + + if (is_mutable) + hlist_add_behind_rcu(&hook->list, &mutable_hook->list); + else + hlist_add_before_rcu(&hook->list, &mutable_hook->list); + return; + } + + panic("Unable to install hook, cannot find mutable hook\n"); +} + +static void __init add_mutable_hooks(void) +{ + struct hlist_head *list = (struct hlist_head *) &security_hook_heads; + struct security_hook_list *shl; + int i; + + for (i = 0; i < SECURITY_HOOK_COUNT; i++) { + shl = kzalloc(sizeof(*shl), GFP_KERNEL); + if (!shl) + panic("Unable to allocate memory for mutable hooks\n"); + shl->head = &list[i]; + hlist_add_head_rcu(&shl->list, shl->head); + } +} +#else +static void security_add_hook(struct security_hook_list *hook, bool is_mutable) +{ + WARN_ONCE(is_mutable, + "Mutable hook loaded with writable hooks disabled"); + hlist_add_tail_rcu(hook.list, hooks.head); +} + +static void __init add_mutable_hooks(void) {} +#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ + /** * security_init - initializes the security framework * @@ -63,11 +116,11 @@ int __init security_init(void) int i; struct hlist_head *list = (struct hlist_head *) &security_hook_heads; - for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct hlist_head); - i++) + for (i = 0; i < SECURITY_HOOK_COUNT; i++) INIT_HLIST_HEAD(&list[i]); pr_info("Security Framework initialized\n"); + add_mutable_hooks(); /* * Load minor LSMs, with the capability module always first. */ @@ -153,21 +206,24 @@ int __init security_module_enable(const char *module) * @hooks: the hooks to add * @count: the number of hooks to add * @lsm: the name of the security module + * @is_mutable: is this hook mutable after kernel init * * Each LSM has to register its hooks with the infrastructure. */ -void __init security_add_hooks(struct security_hook_list *hooks, int count, - char *lsm) +void security_add_hooks(struct security_hook_list *hooks, int count, + char *lsm, bool is_mutable) { int i; for (i = 0; i < count; i++) { hooks[i].lsm = lsm; - hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); + security_add_hook(&hooks[i], is_mutable); } + if (lsm_append(lsm, &lsm_names) < 0) panic("%s - Cannot get early memory.\n", __func__); } +EXPORT_SYMBOL_GPL(security_add_hooks); int call_lsm_notifier(enum lsm_event event, void *data) { @@ -202,7 +258,8 @@ EXPORT_SYMBOL(unregister_lsm_notifier); struct security_hook_list *P; \ \ hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ - P->hook.FUNC(__VA_ARGS__); \ + if (P->hook.FUNC) \ + P->hook.FUNC(__VA_ARGS__); \ } while (0) #define call_int_hook(FUNC, IRC, ...) ({ \ @@ -211,9 +268,11 @@ EXPORT_SYMBOL(unregister_lsm_notifier); struct security_hook_list *P; \ \ hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ - RC = P->hook.FUNC(__VA_ARGS__); \ - if (RC != 0) \ - break; \ + if (P->hook.FUNC) { \ + RC = P->hook.FUNC(__VA_ARGS__); \ + if (RC != 0) \ + break; \ + } \ } \ } while (0); \ RC; \ @@ -318,6 +377,8 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) * thinks it should not be set it won't. */ hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) { + if (!hp->hook.vm_enough_memory) + continue; rc = hp->hook.vm_enough_memory(mm, pages); if (rc <= 0) { cap_sys_admin = 0; @@ -806,6 +867,8 @@ int security_inode_getsecurity(struct inode *inode, const char *name, void **buf * Only one module will provide an attribute with a given name. */ hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) { + if (!hp->hook.inode_getsecurity) + continue; rc = hp->hook.inode_getsecurity(inode, name, buffer, alloc); if (rc != -EOPNOTSUPP) return rc; @@ -824,6 +887,8 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void * Only one module will provide an attribute with a given name. */ hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) { + if (!hp->hook.inode_setsecurity) + continue; rc = hp->hook.inode_setsecurity(inode, name, value, size, flags); if (rc != -EOPNOTSUPP) @@ -1127,6 +1192,8 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, struct security_hook_list *hp; hlist_for_each_entry(hp, &security_hook_heads.task_prctl, list) { + if (!hp->hook.task_prctl) + continue; thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5); if (thisrc != -ENOSYS) { rc = thisrc; @@ -1631,6 +1698,8 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, */ hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match, list) { + if (!hp->hook.xfrm_state_pol_flow_match) + continue; rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl); break; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 8644d864e3c1..f05184a3a7a6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6393,7 +6393,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif -static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { +static struct security_hook_list selinux_hooks[] __lsm_mutable_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), @@ -6651,7 +6651,8 @@ static __init int selinux_init(void) 0, SLAB_PANIC, NULL); avc_init(); - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); + security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux", + IS_ENABLED(CONFIG_SECURITY_SELINUX_DISABLE)); if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) panic("SELinux: Unable to register AVC netcache callback\n"); diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 03fdecba93bb..7a9f1bb06c8e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4902,7 +4902,8 @@ static __init int smack_init(void) /* * Register with LSM */ - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack", + false); return 0; } diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 213b8c593668..ba74fab0e9a5 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -543,7 +543,8 @@ static int __init tomoyo_init(void) if (!security_module_enable("tomoyo")) return 0; /* register ourselves with the security framework */ - security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); + security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo", + false); printk(KERN_INFO "TOMOYO Linux initialized\n"); cred->security = &tomoyo_kernel_domain; tomoyo_mm_init(); diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index ffda91a4a1aa..04c9aed9e951 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -480,6 +480,6 @@ static inline void yama_init_sysctl(void) { } void __init yama_add_hooks(void) { pr_info("Yama: becoming mindful.\n"); - security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama"); + security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama", false); yama_init_sysctl(); }
This patch introduces a mechanism to add mutable hooks at the end of the callback chain for each LSM hook. It allows for built-in kernel LSMs to be unloaded, as well as modular LSMs to be loaded after boot-time. It also does not compromise the security of hooks which are never meant to be unloaded. Signed-off-by: Sargun Dhillon <sargun@sargun.me> --- include/linux/lsm_hooks.h | 7 ++-- security/apparmor/lsm.c | 2 +- security/commoncap.c | 2 +- security/security.c | 87 +++++++++++++++++++++++++++++++++++++++++----- security/selinux/hooks.c | 5 +-- security/smack/smack_lsm.c | 3 +- security/tomoyo/tomoyo.c | 3 +- security/yama/yama_lsm.c | 2 +- 8 files changed, 92 insertions(+), 19 deletions(-)