[RFC kgr on klp 5/9] livepatch: teach klp about consistency models

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We want more concise consistency models than simple is. This is a
preparation for other, more complex ones. It moves the simple handling
out of ftrace handler and is called as newly introduced struct
klp_cmodel->stub. This way, every model can implement its own handler.

On the top of that, I assume the structure will be extended over time.
For example, kGraft-like patching will need pre-patch and post-patch
hooks and more.

We store the models in a list and all have its ID, specified in every
patch. The ID is then looked up in the list and appropriate cmodel
used.

Signed-off-by: Jiri Slaby <jslaby@xxxxxxx>
---
 include/linux/livepatch.h            | 35 ++++++++++++++++++++++++++++++++
 kernel/livepatch/Makefile            |  2 +-
 kernel/livepatch/cmodel-simple.c     | 39 ++++++++++++++++++++++++++++++++++++
 kernel/livepatch/core.c              | 37 ++++++++++++++++++++++++++++++----
 samples/livepatch/livepatch-sample.c |  1 +
 5 files changed, 109 insertions(+), 5 deletions(-)
 create mode 100644 kernel/livepatch/cmodel-simple.c

diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index fabb067a3f1d..009f308ff756 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -23,11 +23,36 @@
 
 #include <linux/module.h>
 #include <linux/ftrace.h>
+#include <linux/ptrace.h>
 
 #if IS_ENABLED(CONFIG_LIVEPATCH)
 
 #include <asm/livepatch.h>
 
+struct klp_func;
+
+/**
+ * enum klp_cmodel_id - possible consistency models
+ */
+enum klp_cmodel_id {
+	KLP_CM_INVALID = 0,
+	KLP_CM_SIMPLE, /* LEAVE_FUNCTION and SWITCH_FUNCTION */
+};
+
+/**
+ * struct klp_cmodel - implementation of a consistency model
+ * @id: id of this model (from enum klp_cmodel_id)
+ * @list: member of klp_cmodel_list
+ * @stub: what to use as an ftrace handler (annotate with notrace!)
+ */
+struct klp_cmodel {
+	const enum klp_cmodel_id id;
+	struct list_head list;
+
+	void (*stub)(struct list_head *func_stack, struct klp_func *func,
+			struct pt_regs *regs);
+};
+
 enum klp_state {
 	KLP_DISABLED,
 	KLP_ENABLED
@@ -42,6 +67,7 @@ enum klp_state {
  * @kobj:	kobject for sysfs resources
  * @state:	tracks function-level patch application state
  * @stack_node:	list node for klp_ops func_stack list
+ * @stub:	cache of klp_patch.cmodel.stub
  */
 struct klp_func {
 	/* external */
@@ -61,6 +87,8 @@ struct klp_func {
 	struct kobject kobj;
 	enum klp_state state;
 	struct list_head stack_node;
+	void (*stub)(struct list_head *func_stack, struct klp_func *func,
+			struct pt_regs *regs);
 };
 
 /**
@@ -108,19 +136,23 @@ struct klp_object {
  * struct klp_patch - patch structure for live patching
  * @mod:	reference to the live patch module
  * @objs:	object entries for kernel objects to be patched
+ * @cmodel_id:	consistency model used to apply this patch
  * @list:	list node for global list of registered patches
  * @kobj:	kobject for sysfs resources
  * @state:	tracks patch-level application state
+ * @cmodel:	cmodel_id's implementation
  */
 struct klp_patch {
 	/* external */
 	struct module *mod;
 	struct klp_object *objs;
+	const enum klp_cmodel_id cmodel_id;
 
 	/* internal */
 	struct list_head list;
 	struct kobject kobj;
 	enum klp_state state;
+	struct klp_cmodel *cmodel;
 };
 
 #define klp_for_each_object(patch, obj) \
@@ -144,6 +176,9 @@ int klp_unregister_patch(struct klp_patch *);
 int klp_enable_patch(struct klp_patch *);
 int klp_disable_patch(struct klp_patch *);
 
+void klp_init_cmodel_simple(void);
+void klp_register_cmodel(struct klp_cmodel *);
+
 #endif /* CONFIG_LIVEPATCH */
 
 #endif /* _LINUX_LIVEPATCH_H_ */
diff --git a/kernel/livepatch/Makefile b/kernel/livepatch/Makefile
index e8780c0901d9..926533777247 100644
--- a/kernel/livepatch/Makefile
+++ b/kernel/livepatch/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
 
-livepatch-objs := core.o
+livepatch-objs := core.o cmodel-simple.o
diff --git a/kernel/livepatch/cmodel-simple.c b/kernel/livepatch/cmodel-simple.c
new file mode 100644
index 000000000000..d4e430ff40c0
--- /dev/null
+++ b/kernel/livepatch/cmodel-simple.c
@@ -0,0 +1,39 @@
+/*
+ * cmodel-simple.c - KLP Simple Consistency Model
+ *
+ * Copyright (C) 2015 Seth Jennings <sjenning@xxxxxxxxxx>
+ * Copyright (C) 2015 SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/list.h>
+#include <linux/livepatch.h>
+
+static void notrace klp_simple_stub(struct list_head *func_stack,
+		struct klp_func *func, struct pt_regs *regs)
+{
+	klp_arch_set_pc(regs, (unsigned long)func->new_func);
+}
+
+static struct klp_cmodel klp_simple_model = {
+	.id = KLP_CM_SIMPLE,
+	.stub = klp_simple_stub,
+};
+
+void klp_init_cmodel_simple(void)
+{
+	klp_register_cmodel(&klp_simple_model);
+}
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 2da42be84452..ab6a36688c93 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -58,6 +58,7 @@ static DEFINE_MUTEX(klp_mutex);
 
 static LIST_HEAD(klp_patches);
 static LIST_HEAD(klp_ops);
+static LIST_HEAD(klp_cmodel_list);
 
 static struct kobject *klp_root_kobj;
 
@@ -319,18 +320,16 @@ static void notrace klp_ftrace_handler(unsigned long ip,
 				       struct ftrace_ops *fops,
 				       struct pt_regs *regs)
 {
-	struct klp_ops *ops;
+	struct klp_ops *ops = container_of(fops, struct klp_ops, fops);
 	struct klp_func *func;
 
-	ops = container_of(fops, struct klp_ops, fops);
-
 	rcu_read_lock();
 	func = list_first_or_null_rcu(&ops->func_stack, struct klp_func,
 				      stack_node);
 	if (WARN_ON_ONCE(!func))
 		goto unlock;
 
-	klp_arch_set_pc(regs, (unsigned long)func->new_func);
+	func->stub(&ops->func_stack, func, regs);
 unlock:
 	rcu_read_unlock();
 }
@@ -720,6 +719,7 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
 {
 	INIT_LIST_HEAD(&func->stack_node);
 	func->state = KLP_DISABLED;
+	func->stub = klp_object_to_patch(obj)->cmodel->stub;
 
 	return kobject_init_and_add(&func->kobj, &klp_ktype_func,
 				    &obj->kobj, "%s", func->old_name);
@@ -790,13 +790,28 @@ free:
 static int klp_init_patch(struct klp_patch *patch)
 {
 	struct klp_object *obj;
+	struct klp_cmodel *cm, *cmodel = NULL;
 	int ret;
 
 	if (!patch->objs)
 		return -EINVAL;
 
+	list_for_each_entry(cm, &klp_cmodel_list, list) {
+		if (patch->cmodel_id == cm->id) {
+			cmodel = cm;
+			break;
+		}
+	}
+
+	if (!cmodel) {
+		pr_err("%s: patch '%ps' requires unknown consistency model %d\n",
+				__func__, patch, patch->cmodel_id);
+		return -EINVAL;
+	}
+
 	mutex_lock(&klp_mutex);
 
+	patch->cmodel = cmodel;
 	patch->state = KLP_DISABLED;
 
 	ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
@@ -893,6 +908,18 @@ int klp_register_patch(struct klp_patch *patch)
 }
 EXPORT_SYMBOL_GPL(klp_register_patch);
 
+/**
+ * klp_register_cmodel - register a consistency model
+ * @model: model to register
+ *
+ * This functions has to be synchronously called before klp_root_kobj is
+ * created in klp_init since we use no locking.
+ */
+void klp_register_cmodel(struct klp_cmodel *model)
+{
+	list_add_tail(&model->list, &klp_cmodel_list);
+}
+
 static void klp_module_notify_coming(struct klp_patch *patch,
 				     struct klp_object *obj)
 {
@@ -993,6 +1020,8 @@ static int klp_init(void)
 		return -EINVAL;
 	}
 
+	klp_init_cmodel_simple();
+
 	ret = register_module_notifier(&klp_module_nb);
 	if (ret)
 		return ret;
diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c
index fb8c8614e728..48621de040db 100644
--- a/samples/livepatch/livepatch-sample.c
+++ b/samples/livepatch/livepatch-sample.c
@@ -63,6 +63,7 @@ static struct klp_object objs[] = {
 static struct klp_patch patch = {
 	.mod = THIS_MODULE,
 	.objs = objs,
+	.cmodel_id = KLP_CM_SIMPLE,
 };
 
 static int livepatch_init(void)
-- 
2.3.5

--
To unsubscribe from this list: send the line "unsubscribe live-patching" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux