]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livep...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Mar 2016 04:46:32 +0000 (21:46 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 18 Mar 2016 04:46:32 +0000 (21:46 -0700)
Pull livepatching update from Jiri Kosina:

 - cleanup of module notifiers; this depends on a module.c cleanup which
   has been acked by Rusty; from Jessica Yu

 - small assorted fixes and MAINTAINERS update

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
  livepatch/module: remove livepatch module notifier
  modules: split part of complete_formation() into prepare_coming_module()
  livepatch: Update maintainers
  livepatch: Fix the error message about unresolvable ambiguity
  klp: remove CONFIG_LIVEPATCH dependency from klp headers
  klp: remove superfluous errors in asm/livepatch.h

MAINTAINERS
arch/s390/include/asm/livepatch.h
arch/x86/include/asm/livepatch.h
include/linux/livepatch.h
kernel/livepatch/core.c
kernel/module.c

index e32f4847e251490359d8a093796dc954add21e21..94ea42b76b30ed4f9aeaf94f896e08d290d06e06 100644 (file)
@@ -6596,9 +6596,10 @@ F:       drivers/platform/x86/hp_accel.c
 
 LIVE PATCHING
 M:     Josh Poimboeuf <jpoimboe@redhat.com>
-M:     Seth Jennings <sjenning@redhat.com>
+M:     Jessica Yu <jeyu@redhat.com>
 M:     Jiri Kosina <jikos@kernel.org>
-M:     Vojtech Pavlik <vojtech@suse.com>
+M:     Miroslav Benes <mbenes@suse.cz>
+R:     Petr Mladek <pmladek@suse.com>
 S:     Maintained
 F:     kernel/livepatch/
 F:     include/linux/livepatch.h
index a52b6cca873d380adc9bec726cc31816dba5cd6b..d5427c78b1b3edb1bbccff92bfbf4c86c45d6214 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <linux/module.h>
 
-#ifdef CONFIG_LIVEPATCH
 static inline int klp_check_compiler_support(void)
 {
        return 0;
@@ -36,8 +35,5 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 {
        regs->psw.addr = ip;
 }
-#else
-#error Include linux/livepatch.h, not asm/livepatch.h
-#endif
 
 #endif
index e795f5274217a47cf1713063399675a175d5a4ea..7e68f95585523bdc315883b023bdae4a0deeb017 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/ftrace.h>
 
-#ifdef CONFIG_LIVEPATCH
 static inline int klp_check_compiler_support(void)
 {
 #ifndef CC_USING_FENTRY
@@ -40,8 +39,5 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 {
        regs->ip = ip;
 }
-#else
-#error Include linux/livepatch.h, not asm/livepatch.h
-#endif
 
 #endif /* _ASM_X86_LIVEPATCH_H */
index a8828652f79428dfb888121489e457fe5c13bd5b..bd830d590465651f3f793e3aeb5dc55734f95d20 100644 (file)
@@ -134,6 +134,15 @@ int klp_unregister_patch(struct klp_patch *);
 int klp_enable_patch(struct klp_patch *);
 int klp_disable_patch(struct klp_patch *);
 
+/* Called from the module loader during module coming/going states */
+int klp_module_coming(struct module *mod);
+void klp_module_going(struct module *mod);
+
+#else /* !CONFIG_LIVEPATCH */
+
+static inline int klp_module_coming(struct module *mod) { return 0; }
+static inline void klp_module_going(struct module *mod) { }
+
 #endif /* CONFIG_LIVEPATCH */
 
 #endif /* _LINUX_LIVEPATCH_H_ */
index bc2c85c064c1b73cf2c393dc2278e3e3bc6dc7af..d68fbf63b0836737977882f1874c02c8cf8504d7 100644 (file)
@@ -99,12 +99,12 @@ static void klp_find_object_module(struct klp_object *obj)
        /*
         * 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.
+        * klp_module_going() instead.
         */
        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
+        * Do not mess work of klp_module_coming() and klp_module_going().
+        * Note that the patch might still be needed before klp_module_going()
         * 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.
@@ -190,8 +190,8 @@ static int klp_find_object_symbol(const char *objname, const char *name,
        if (args.addr == 0)
                pr_err("symbol '%s' not found in symbol table\n", name);
        else if (args.count > 1 && sympos == 0) {
-               pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n",
-                      args.count, name, objname);
+               pr_err("unresolvable ambiguity for symbol '%s' in object '%s'\n",
+                      name, objname);
        } else if (sympos != args.count && sympos > 0) {
                pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
                       sympos, name, objname ? objname : "vmlinux");
@@ -866,103 +866,108 @@ int klp_register_patch(struct klp_patch *patch)
 }
 EXPORT_SYMBOL_GPL(klp_register_patch);
 
-static int klp_module_notify_coming(struct klp_patch *patch,
-                                    struct klp_object *obj)
+int klp_module_coming(struct module *mod)
 {
-       struct module *pmod = patch->mod;
-       struct module *mod = obj->mod;
        int ret;
+       struct klp_patch *patch;
+       struct klp_object *obj;
 
-       ret = klp_init_object_loaded(patch, obj);
-       if (ret) {
-               pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n",
-                       pmod->name, mod->name, ret);
-               return ret;
-       }
+       if (WARN_ON(mod->state != MODULE_STATE_COMING))
+               return -EINVAL;
 
-       if (patch->state == KLP_DISABLED)
-               return 0;
+       mutex_lock(&klp_mutex);
+       /*
+        * Each module has to know that klp_module_coming()
+        * has been called. We never know what module will
+        * get patched by a new patch.
+        */
+       mod->klp_alive = true;
 
-       pr_notice("applying patch '%s' to loading module '%s'\n",
-                 pmod->name, mod->name);
+       list_for_each_entry(patch, &klp_patches, list) {
+               klp_for_each_object(patch, obj) {
+                       if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
+                               continue;
 
-       ret = klp_enable_object(obj);
-       if (ret)
-               pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
-                       pmod->name, mod->name, ret);
-       return ret;
-}
+                       obj->mod = mod;
 
-static void klp_module_notify_going(struct klp_patch *patch,
-                                   struct klp_object *obj)
-{
-       struct module *pmod = patch->mod;
-       struct module *mod = obj->mod;
+                       ret = klp_init_object_loaded(patch, obj);
+                       if (ret) {
+                               pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n",
+                                       patch->mod->name, obj->mod->name, ret);
+                               goto err;
+                       }
 
-       if (patch->state == KLP_DISABLED)
-               goto disabled;
+                       if (patch->state == KLP_DISABLED)
+                               break;
+
+                       pr_notice("applying patch '%s' to loading module '%s'\n",
+                                 patch->mod->name, obj->mod->name);
+
+                       ret = klp_enable_object(obj);
+                       if (ret) {
+                               pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
+                                       patch->mod->name, obj->mod->name, ret);
+                               goto err;
+                       }
+
+                       break;
+               }
+       }
 
-       pr_notice("reverting patch '%s' on unloading module '%s'\n",
-                 pmod->name, mod->name);
+       mutex_unlock(&klp_mutex);
 
-       klp_disable_object(obj);
+       return 0;
 
-disabled:
+err:
+       /*
+        * If a patch is unsuccessfully applied, return
+        * error to the module loader.
+        */
+       pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n",
+               patch->mod->name, obj->mod->name, obj->mod->name);
+       mod->klp_alive = false;
        klp_free_object_loaded(obj);
+       mutex_unlock(&klp_mutex);
+
+       return ret;
 }
 
-static int klp_module_notify(struct notifier_block *nb, unsigned long action,
-                            void *data)
+void klp_module_going(struct module *mod)
 {
-       int ret;
-       struct module *mod = data;
        struct klp_patch *patch;
        struct klp_object *obj;
 
-       if (action != MODULE_STATE_COMING && action != MODULE_STATE_GOING)
-               return 0;
+       if (WARN_ON(mod->state != MODULE_STATE_GOING &&
+                   mod->state != MODULE_STATE_COMING))
+               return;
 
        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.
+        * Each module has to know that klp_module_going()
+        * 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;
+       mod->klp_alive = false;
 
        list_for_each_entry(patch, &klp_patches, list) {
                klp_for_each_object(patch, obj) {
                        if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
                                continue;
 
-                       if (action == MODULE_STATE_COMING) {
-                               obj->mod = mod;
-                               ret = klp_module_notify_coming(patch, obj);
-                               if (ret) {
-                                       obj->mod = NULL;
-                                       pr_warn("patch '%s' is in an inconsistent state!\n",
-                                               patch->mod->name);
-                               }
-                       } else /* MODULE_STATE_GOING */
-                               klp_module_notify_going(patch, obj);
+                       if (patch->state != KLP_DISABLED) {
+                               pr_notice("reverting patch '%s' on unloading module '%s'\n",
+                                         patch->mod->name, obj->mod->name);
+                               klp_disable_object(obj);
+                       }
 
+                       klp_free_object_loaded(obj);
                        break;
                }
        }
 
        mutex_unlock(&klp_mutex);
-
-       return 0;
 }
 
-static struct notifier_block klp_module_nb = {
-       .notifier_call = klp_module_notify,
-       .priority = INT_MIN+1, /* called late but before ftrace notifier */
-};
-
 static int __init klp_init(void)
 {
        int ret;
@@ -973,21 +978,11 @@ static int __init klp_init(void)
                return -EINVAL;
        }
 
-       ret = register_module_notifier(&klp_module_nb);
-       if (ret)
-               return ret;
-
        klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
-       if (!klp_root_kobj) {
-               ret = -ENOMEM;
-               goto unregister;
-       }
+       if (!klp_root_kobj)
+               return -ENOMEM;
 
        return 0;
-
-unregister:
-       unregister_module_notifier(&klp_module_nb);
-       return ret;
 }
 
 module_init(klp_init);
index 87cfeb25cf65516236fbc911b1ccedd6d5f09e3d..041200ca4a2db348287394777fab8efbae58b3f2 100644 (file)
@@ -53,6 +53,7 @@
 #include <asm/sections.h>
 #include <linux/tracepoint.h>
 #include <linux/ftrace.h>
+#include <linux/livepatch.h>
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
@@ -984,6 +985,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
                mod->exit();
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
+       klp_module_going(mod);
        ftrace_release_mod(mod);
 
        async_synchronize_full();
@@ -3258,6 +3260,7 @@ fail:
        module_put(mod);
        blocking_notifier_call_chain(&module_notify_list,
                                     MODULE_STATE_GOING, mod);
+       klp_module_going(mod);
        ftrace_release_mod(mod);
        free_module(mod);
        wake_up_all(&module_wq);
@@ -3335,9 +3338,6 @@ static int complete_formation(struct module *mod, struct load_info *info)
        mod->state = MODULE_STATE_COMING;
        mutex_unlock(&module_mutex);
 
-       ftrace_module_enable(mod);
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_COMING, mod);
        return 0;
 
 out:
@@ -3345,6 +3345,20 @@ out:
        return err;
 }
 
+static int prepare_coming_module(struct module *mod)
+{
+       int err;
+
+       ftrace_module_enable(mod);
+       err = klp_module_coming(mod);
+       if (err)
+               return err;
+
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_COMING, mod);
+       return 0;
+}
+
 static int unknown_module_param_cb(char *param, char *val, const char *modname,
                                   void *arg)
 {
@@ -3459,13 +3473,17 @@ static int load_module(struct load_info *info, const char __user *uargs,
        if (err)
                goto ddebug_cleanup;
 
+       err = prepare_coming_module(mod);
+       if (err)
+               goto bug_cleanup;
+
        /* Module is ready to execute: parsing args may do that. */
        after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
                                  -32768, 32767, mod,
                                  unknown_module_param_cb);
        if (IS_ERR(after_dashes)) {
                err = PTR_ERR(after_dashes);
-               goto bug_cleanup;
+               goto coming_cleanup;
        } else if (after_dashes) {
                pr_warn("%s: parameters '%s' after `--' ignored\n",
                       mod->name, after_dashes);
@@ -3474,7 +3492,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
        /* Link in to syfs. */
        err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);
        if (err < 0)
-               goto bug_cleanup;
+               goto coming_cleanup;
 
        /* Get rid of temporary copy. */
        free_copy(info);
@@ -3484,15 +3502,17 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        return do_init_module(mod);
 
+ coming_cleanup:
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_GOING, mod);
+       klp_module_going(mod);
+
  bug_cleanup:
        /* module_bug_cleanup needs module_mutex protection */
        mutex_lock(&module_mutex);
        module_bug_cleanup(mod);
        mutex_unlock(&module_mutex);
 
-       blocking_notifier_call_chain(&module_notify_list,
-                                    MODULE_STATE_GOING, mod);
-
        /* we can't deallocate the module until we clear memory protection */
        module_disable_ro(mod);
        module_disable_nx(mod);