[PATCH v6 1/1] security: Add mechanism to safely (un)load LSMs after boot time
Tetsuo Handa
penguin-kernel at I-love.SAKURA.ne.jp
Sun Apr 15 12:03:56 UTC 2018
Sargun Dhillon wrote:
> On Fri, Apr 13, 2018 at 7:13 AM, Tetsuo Handa
> <penguin-kernel at i-love.sakura.ne.jp> wrote:
> > +#define LSM_MODULE_INIT(NAME, HOOKS) \
> > + { \
> > + .name = NAME, \
> > + .hooks = HOOKS, \
> > + .count = ARRAY_SIZE(HOOKS), \
> > + .owner = THIS_MODULE, \
> > + }
> > +
> > +extern int __must_check security_add_hooks(struct lsm_info *lsm,
> > + const bool is_mutable);
> > +#ifdef CONFIG_SECURITY_SELINUX_DISABLE
> > +extern void __security_delete_hooks(struct lsm_info *lsm);
> > +#endif
> Why expose __security_delete_hooks in lsm_hooks.h? Given SELinux is
> the only consumer, and shouldn't be using it much longer, I think it
> makes sense to let it stay part of the SELinux hooks.c.
Because scripts/checkpatch.pl says so. In fact, I was puzzled by strange
NULL pointer dereference bug at list_del() in __security_delete_hooks(), for
the compiler did not find for me that I forgot to update the argument of
__security_delete_hooks() in security/selinux/hooks.c .
> > +int __must_check security_add_hooks(struct lsm_info *lsm,
> > + const bool is_mutable)
> > {
> > - struct hlist_head *heads;
> > - int i, hook_idx, ret = 0;
> > + struct security_hook_heads *heads = get_heads(is_mutable);
> > + struct security_hook_list *hooks = lsm->hooks;
> > + const int count = lsm->count;
> > + int i, ret;
> >
> > - mutex_lock(&security_hook_mutex);
> > - heads = get_heads(is_mutable);
> > - if (IS_ERR(heads)) {
> > - ret = PTR_ERR(heads);
> > + INIT_LIST_HEAD(&lsm->list);
> Can't this happen in the macro to setup LSM_INFO?
Yes if the variable's name is passed into the LSM_MODULE_INIT() macro, for
LIST_HEAD_INIT() needs the variable's address.
> > + if (IS_ERR(heads))
> > + return PTR_ERR(heads);
> > + for (i = 0; i < count; i++) {
> > + unsigned int offset = hooks[i].offset;
> > +
> > + if (offset % sizeof(struct hlist_head) ||
> > + offset + sizeof(struct hlist_head) >
> > + sizeof(struct security_hook_heads))
> > + return -EINVAL;
> > + }
> > + if (!security_allow_unregister_hooks &&
> > + !try_module_get(lsm->owner))
> > + return -EINVAL;
> What case is it okay if try_module_get fails? Won't this return
> -EINVAL on built-in modules because lsm->owner is NULL?
try_module_get(NULL) == true.
> > +int __must_check security_delete_hooks(struct lsm_info *lsm)
> > {
> > - int i, ret = 0;
> > + struct security_hook_list *hooks = lsm->hooks;
> > + const int count = lsm->count;
> > + int i, ret = -EPERM;
> >
> > - mutex_lock(&security_hook_mutex);
> > - if (security_allow_unregister_hooks)
> > + if (mutex_lock_killable(&security_hook_mutex))
> Why mutex_lock_killable?
If a function can fail safely, it is preferable to allow it be interrupted
when waiting for something.
By the way, how do you guarantee that security_delete_hooks() was called before
delete_module() request of that lsm module starts? Well, rereading your patch:
/**
* security_delete_hooks - Remove modules hooks from the mutable hooks lists.
* @hooks: the hooks to remove
* @count: the number of hooks to remove
*
* 0 is returned on success, otherwise -errno is returned on failure.
* If an error is returned, it is up to the LSM author to handle the error
* appropriately. If they do not, their code could be unloaded, while
* leaving dangling pointers.
*
* At best, this will cause a kernel oops. At worst case scenario, this can
* lead to arbitrary code execution. Therefore, it is critical that module
* authors check the return code here, and act appropriately. In most cases
* a failure should result in panic.
*/
Your patch tries to prevent security_delete_hooks() from module_exit() function by
holding module_mutex when try_module_get() is called, doesn't it? And you leave
handling of CONFIG_MODULE_FORCE_UNLOAD=y kernels to the module authors when forced
unload is used, don't you? But what the authors can do when security_delete_hooks()
returned an error? They can do nothing other than calling panic(). I think that
security_delete_hooks() is effectively not allowed to fail...
By the way, did you test with CONFIG_PROVE_LOCKING=y? lock_existing_hooks() has
security_hook_mutex -> module_mutex dependency while init_module()/delete_module()
have module_mutex -> security_hook_mutex dependency?
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
More information about the Linux-security-module-archive
mailing list