[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1472237448-22270-2-git-send-email-chris.j.arges@canonical.com>
Date: Fri, 26 Aug 2016 13:50:27 -0500
From: Chris J Arges <chris.j.arges@...onical.com>
To: live-patching@...r.kernel.org
Cc: Chris J Arges <chris.j.arges@...onical.com>,
Josh Poimboeuf <jpoimboe@...hat.com>,
Jessica Yu <jeyu@...hat.com>, Jiri Kosina <jikos@...nel.org>,
Miroslav Benes <mbenes@...e.cz>,
Petr Mladek <pmladek@...e.com>, linux-kernel@...r.kernel.org
Subject: [PATCH] livepatch: add load/unload hooks to objects
It can be useful to execute hook functions whenever a livepatch is applied
or unapplied to a particular object. Currently this is possible by writing
logic in the __init function of the livepatch kernel module. However to
handle executing functions when a module loads requires an additional
module notifier to be set up with the correct priority.
By using load/unload hooks we can execute these functions using the
existing livepatch notifier infrastructure and ensure consistent ordering
of notifications.
The load hook executes right before enabling functions, and the unload hook
executes right after disabling functions.
Signed-off-by: Chris J Arges <chris.j.arges@...onical.com>
---
include/linux/livepatch.h | 33 +++++++++++++++++++++++++++------
kernel/livepatch/core.c | 29 +++++++++++++++++++++++++++++
2 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 9072f04..bb32a66 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -65,18 +65,32 @@ struct klp_func {
};
/**
+ * struct klp_hook - hook structure for live patching
+ * @hook: function to be executed on hook
+ *
+ */
+struct klp_hook {
+ int (*hook)(void);
+};
+
+/**
* struct klp_object - kernel object structure for live patching
- * @name: module name (or NULL for vmlinux)
- * @funcs: function entries for functions to be patched in the object
- * @kobj: kobject for sysfs resources
- * @mod: kernel module associated with the patched object
- * (NULL for vmlinux)
- * @state: tracks object-level patch application state
+ * @name: module name (or NULL for vmlinux)
+ * @funcs: function entries for functions to be patched in the
+ * object
+ * @load_hooks: functions to be executed before load time (optional)
+ * @unload_hooks: functions to be executed before load time (optional)
+ * @kobj: kobject for sysfs resources
+ * @mod: kernel module associated with the patched object
+ * (NULL for vmlinux)
+ * @state: tracks object-level patch application state
*/
struct klp_object {
/* external */
const char *name;
struct klp_func *funcs;
+ struct klp_hook *load_hooks;
+ struct klp_hook *unload_hooks;
/* internal */
struct kobject kobj;
@@ -111,6 +125,13 @@ struct klp_patch {
func->old_name || func->new_func || func->old_sympos; \
func++)
+#define klp_for_each_load_hook(obj, hook) \
+ for (hook = obj->load_hooks; hook && hook->hook; hook++)
+
+#define klp_for_each_unload_hook(obj, hook) \
+ for (hook = obj->unload_hooks; hook && hook->hook; hook++)
+
+
int klp_register_patch(struct klp_patch *);
int klp_unregister_patch(struct klp_patch *);
int klp_enable_patch(struct klp_patch *);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 5fbabe0..00e7d9c 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -378,6 +378,14 @@ static void klp_disable_func(struct klp_func *func)
func->state = KLP_DISABLED;
}
+static int klp_run_hook(struct klp_hook *hook)
+{
+ if (hook && hook->hook)
+ return (*hook->hook)();
+
+ return 0;
+}
+
static int klp_enable_func(struct klp_func *func)
{
struct klp_ops *ops;
@@ -448,17 +456,28 @@ err:
static void klp_disable_object(struct klp_object *obj)
{
struct klp_func *func;
+ struct klp_hook *hook;
+ int ret;
klp_for_each_func(obj, func)
if (func->state == KLP_ENABLED)
klp_disable_func(func);
+ klp_for_each_unload_hook(obj, hook) {
+ ret = klp_run_hook(hook);
+ if (ret) {
+ pr_warn("unload hook '%p' failed for object '%s'\n",
+ hook, klp_is_module(obj) ? obj->name : "vmlinux");
+ }
+ }
+
obj->state = KLP_DISABLED;
}
static int klp_enable_object(struct klp_object *obj)
{
struct klp_func *func;
+ struct klp_hook *hook;
int ret;
if (WARN_ON(obj->state != KLP_DISABLED))
@@ -467,6 +486,16 @@ static int klp_enable_object(struct klp_object *obj)
if (WARN_ON(!klp_is_object_loaded(obj)))
return -EINVAL;
+ klp_for_each_load_hook(obj, hook) {
+ ret = klp_run_hook(hook);
+ if (ret) {
+ pr_warn("load hook '%p' failed for object '%s'\n",
+ hook, klp_is_module(obj) ? obj->name : "vmlinux");
+ klp_disable_object(obj);
+ return ret;
+ }
+ }
+
klp_for_each_func(obj, func) {
ret = klp_enable_func(func);
if (ret) {
--
2.7.4
Powered by blists - more mailing lists