@@ -28,7 +28,7 @@
#include <linux/security.h>
#include <linux/init.h>
#include <linux/rculist.h>
-
+#include <linux/module.h>
/**
* union security_list_options - Linux Security Module hook function list
*
@@ -2010,6 +2010,7 @@ struct lsm_info {
const char *name;
const unsigned int count;
struct security_hook_list *hooks;
+ struct module *owner;
} __randomize_layout;
struct security_hook_list {
@@ -2039,9 +2040,11 @@ struct security_hook_list {
.name = NAME, \
.hooks = HOOKS, \
.count = ARRAY_SIZE(HOOKS), \
+ .owner = THIS_MODULE, \
}
-extern void security_add_hooks(struct lsm_info *lsm, bool is_mutable);
+extern int __must_check security_add_hooks(struct lsm_info *lsm,
+ bool is_mutable);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void security_delete_hooks(struct lsm_info *lsm);
@@ -1564,7 +1564,7 @@ static int __init apparmor_init(void)
aa_free_root_ns();
goto buffers_out;
}
- security_add_hooks(&apparmor_info, false);
+ BUG_ON(security_add_hooks(&apparmor_info, false));
/* Report that AppArmor successfully initialized */
apparmor_initialized = 1;
@@ -1365,7 +1365,7 @@ static struct lsm_info capability_info =
void __init capability_add_hooks(void)
{
- security_add_hooks(&capability_info, false);
+ BUG_ON(security_add_hooks(&capability_info, false));
}
#endif /* CONFIG_SECURITY */
@@ -183,7 +183,7 @@ static struct lsm_info loadpin_info = LSM_MODULE_INIT("loadpin", loadpin_hooks);
void __init loadpin_add_hooks(void)
{
pr_info("ready to pin (currently %sabled)", enabled ? "en" : "dis");
- security_add_hooks(&loadpin_info, false);
+ BUG_ON(security_add_hooks(&loadpin_info, false));
}
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
@@ -174,9 +174,9 @@ void security_delete_hooks(struct lsm_info *info)
}
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
-static void __init security_add_hook(struct security_hook_list *hook,
- struct lsm_info *info,
- struct security_hook_heads *heads)
+static void security_add_hook(struct security_hook_list *hook,
+ struct lsm_info *info,
+ struct security_hook_heads *heads)
{
const unsigned int offset = hook->offset;
const unsigned int idx = offset / sizeof(struct hlist_head);
@@ -194,23 +194,32 @@ static void __init security_add_hook(struct security_hook_list *hook,
* @is_mutable: Can these hooks be loaded or unloaded after boot time
*
* Each LSM has to register its hooks with the infrastructure.
+ * Return 0 on success
*/
-void __init security_add_hooks(struct lsm_info *info, bool is_mutable)
+int __must_check security_add_hooks(struct lsm_info *info, bool is_mutable)
{
struct security_hook_heads *heads;
int i;
heads = get_security_hook_heads(is_mutable);
if (IS_ERR(heads))
- panic("Failed to get security heads: %ld\n", PTR_ERR(heads));
+ return PTR_ERR(heads);
+ if (!try_module_get(info->owner))
+ return -EINVAL;
+
+ if (mutex_lock_killable(&lsm_info_lock)) {
+ module_put(info->owner);
+ return -EINTR;
+ }
for (i = 0; i < info->count; i++)
security_add_hook(&info->hooks[i], info, heads);
-
- mutex_lock(&lsm_info_lock);
hlist_add_tail_rcu(&info->list, &lsm_info_head);
mutex_unlock(&lsm_info_lock);
+
+ return 0;
}
+EXPORT_SYMBOL_GPL(security_add_hooks);
int call_lsm_notifier(enum lsm_event event, void *data)
{
@@ -7132,7 +7132,7 @@ static __init int selinux_init(void)
hashtab_cache_init();
- security_add_hooks(&selinux_info, is_mutable);
+ BUG_ON(security_add_hooks(&selinux_info, is_mutable));
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n");
@@ -4843,7 +4843,7 @@ static __init int smack_init(void)
/*
* Register with LSM
*/
- security_add_hooks(&smack_info, false);
+ BUG_ON(security_add_hooks(&smack_info, false));
return 0;
}
@@ -545,7 +545,7 @@ static int __init tomoyo_init(void)
if (!security_module_enable("tomoyo"))
return 0;
/* register ourselves with the security framework */
- security_add_hooks(&tomoyo_info, false);
+ BUG_ON(security_add_hooks(&tomoyo_info, false));
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
tomoyo_mm_init();
@@ -482,6 +482,6 @@ static inline void yama_init_sysctl(void) { }
void __init yama_add_hooks(void)
{
pr_info("Yama: becoming mindful.\n");
- security_add_hooks(&yama_info, false);
+ BUG_ON(security_add_hooks(&yama_info, false));
yama_init_sysctl();
}
This exports security_add_hooks. In order to safely export it, we need have proper error handling for when mutable hooks are not available, rather than crashing the kernel. It now returns an error if it's unable to get a lock to install hooks. For built-in modules, this should never happen, so by default, they crash the kernel. It is up to 3rd party module authors to handle this case for their own modules. Signed-off-by: Sargun Dhillon <sargun@sargun.me> --- include/linux/lsm_hooks.h | 7 +++++-- security/apparmor/lsm.c | 2 +- security/commoncap.c | 2 +- security/loadpin/loadpin.c | 2 +- security/security.c | 23 ++++++++++++++++------- security/selinux/hooks.c | 2 +- security/smack/smack_lsm.c | 2 +- security/tomoyo/tomoyo.c | 2 +- security/yama/yama_lsm.c | 2 +- 9 files changed, 28 insertions(+), 16 deletions(-)