[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1454049827-3726-2-git-send-email-jeyu@redhat.com>
Date: Fri, 29 Jan 2016 01:43:46 -0500
From: Jessica Yu <jeyu@...hat.com>
To: Josh Poimboeuf <jpoimboe@...hat.com>,
Seth Jennings <sjenning@...hat.com>,
Jiri Kosina <jikos@...nel.org>,
Vojtech Pavlik <vojtech@...e.com>,
Miroslav Benes <mbenes@...e.cz>,
Steven Rostedt <rostedt@...dmis.org>,
Ingo Molnar <mingo@...hat.com>
Cc: live-patching@...r.kernel.org, linux-kernel@...r.kernel.org,
Jessica Yu <jeyu@...hat.com>
Subject: [PATCH 1/2] livepatch: Implement separate coming and going module notifiers
Detangle klp_module_notify() into two separate module notifiers
klp_module_notify_{coming,going}() with the appropriate priorities,
so that on module load, the ftrace module notifier will run *before*
the livepatch coming module notifier but *after* the livepatch going
module modifier.
This fixes a notifier ordering issue in which the ftrace module notifier
(and hence ftrace_module_enable()) for COMING modules was being called
after klp_module_notify(), which caused livepatch modules to initialize
incorrectly.
Signed-off-by: Jessica Yu <jeyu@...hat.com>
---
kernel/livepatch/core.c | 128 +++++++++++++++++++++++++++---------------------
1 file changed, 73 insertions(+), 55 deletions(-)
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index bc2c85c..23f4234 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -866,60 +866,73 @@ 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)
+static int klp_module_notify_coming(struct notifier_block *nb,
+ unsigned long action, void *data)
{
- struct module *pmod = patch->mod;
- struct module *mod = obj->mod;
int ret;
+ struct module *mod = data;
+ 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 (patch->state == KLP_DISABLED)
+ if (action != MODULE_STATE_COMING)
return 0;
- pr_notice("applying patch '%s' to loading module '%s'\n",
- pmod->name, mod->name);
+ mutex_lock(&klp_mutex);
- 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;
-}
+ /*
+ * Each module has to know that the notifier has been called.
+ * We never know what module will get patched by a new patch.
+ */
+ mod->klp_alive = true;
-static void klp_module_notify_going(struct klp_patch *patch,
- struct klp_object *obj)
-{
- struct module *pmod = patch->mod;
- struct module *mod = obj->mod;
+ 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;
+
+ obj->mod = mod;
- if (patch->state == KLP_DISABLED)
- goto disabled;
+ 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;
+ }
- pr_notice("reverting patch '%s' on unloading module '%s'\n",
- pmod->name, mod->name);
+ if (patch->state == KLP_DISABLED)
+ break;
- klp_disable_object(obj);
+ pr_notice("applying patch '%s' to loading module '%s'\n",
+ patch->mod->name, obj->mod->name);
-disabled:
- klp_free_object_loaded(obj);
+ 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);
+err:
+ if (ret) {
+ obj->mod = NULL;
+ pr_warn("patch '%s' is in an inconsistent state!\n",
+ patch->mod->name);
+ }
+
+ break;
+ }
+ }
+
+ mutex_unlock(&klp_mutex);
+
+ return 0;
}
-static int klp_module_notify(struct notifier_block *nb, unsigned long action,
- void *data)
+static int klp_module_notify_going(struct notifier_block *nb,
+ unsigned long action, void *data)
{
- int ret;
struct module *mod = data;
struct klp_patch *patch;
struct klp_object *obj;
- if (action != MODULE_STATE_COMING && action != MODULE_STATE_GOING)
+ if (action != MODULE_STATE_GOING)
return 0;
mutex_lock(&klp_mutex);
@@ -928,27 +941,22 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
* 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;
+ 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)
+ goto disabled;
+
+ pr_notice("reverting patch '%s' on unloading module '%s'\n",
+ patch->mod->name, obj->mod->name);
+ klp_disable_object(obj);
+disabled:
+ klp_free_object_loaded(obj);
break;
}
}
@@ -958,9 +966,14 @@ static int klp_module_notify(struct notifier_block *nb, unsigned long action,
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 struct notifier_block klp_module_nb_coming = {
+ .notifier_call = klp_module_notify_coming,
+ .priority = INT_MIN, /* called late but after ftrace (coming) notifier */
+};
+
+static struct notifier_block klp_module_nb_going = {
+ .notifier_call = klp_module_notify_going,
+ .priority = INT_MIN+2, /* called late but before ftrace (going) notifier */
};
static int __init klp_init(void)
@@ -973,7 +986,11 @@ static int __init klp_init(void)
return -EINVAL;
}
- ret = register_module_notifier(&klp_module_nb);
+ ret = register_module_notifier(&klp_module_nb_coming);
+ if (ret)
+ return ret;
+
+ ret = register_module_notifier(&klp_module_nb_going);
if (ret)
return ret;
@@ -986,7 +1003,8 @@ static int __init klp_init(void)
return 0;
unregister:
- unregister_module_notifier(&klp_module_nb);
+ unregister_module_notifier(&klp_module_nb_coming);
+ unregister_module_notifier(&klp_module_nb_going);
return ret;
}
--
2.4.3
Powered by blists - more mailing lists