2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-02 02:14:01 +08:00

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching

Pull livepatching fix from Jiri Kosina:

 - fix for potential race with module loading, from Petr Mladek.

   The race is very unlikely to be seen in real world and has been found
   by code inspection, but should be fixed for 4.0 anyway.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
  livepatch: Fix subtle race with coming and going modules
This commit is contained in:
Linus Torvalds 2015-03-18 10:46:39 -07:00
commit da11508eb0
2 changed files with 30 additions and 4 deletions

View File

@ -344,6 +344,10 @@ struct module {
unsigned long *ftrace_callsites;
#endif
#ifdef CONFIG_LIVEPATCH
bool klp_alive;
#endif
#ifdef CONFIG_MODULE_UNLOAD
/* What modules depend on me? */
struct list_head source_list;

View File

@ -89,16 +89,28 @@ static bool klp_is_object_loaded(struct klp_object *obj)
/* sets obj->mod if object is not vmlinux and module is found */
static void klp_find_object_module(struct klp_object *obj)
{
struct module *mod;
if (!klp_is_module(obj))
return;
mutex_lock(&module_mutex);
/*
* We don't need to take a reference on the module here because we have
* the klp_mutex, which is also taken by the module notifier. This
* prevents any module from unloading until we release the klp_mutex.
* We do not want to block removal of patched modules and therefore
* we do not take a reference here. The patches are removed by
* a going module handler instead.
*/
obj->mod = find_module(obj->name);
mod = find_module(obj->name);
/*
* Do not mess work of the module coming and going notifiers.
* Note that the patch might still be needed before the going handler
* is called. Module functions can be called even in the GOING state
* until mod->exit() finishes. This is especially important for
* patches that modify semantic of the functions.
*/
if (mod && mod->klp_alive)
obj->mod = mod;
mutex_unlock(&module_mutex);
}
@ -767,6 +779,7 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
return -EINVAL;
obj->state = KLP_DISABLED;
obj->mod = NULL;
klp_find_object_module(obj);
@ -961,6 +974,15 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
mutex_lock(&klp_mutex);
/*
* Each module has to know that the notifier has been called.
* We never know what module will get patched by a new patch.
*/
if (action == MODULE_STATE_COMING)
mod->klp_alive = true;
else /* MODULE_STATE_GOING */
mod->klp_alive = false;
list_for_each_entry(patch, &klp_patches, list) {
for (obj = patch->objs; obj->funcs; obj++) {
if (!klp_is_module(obj) || strcmp(obj->name, mod->name))