lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 27 Sep 2017 23:41:29 -0400
From:   Jason Baron <jbaron@...mai.com>
To:     linux-kernel@...r.kernel.org, live-patching@...r.kernel.org
Cc:     jpoimboe@...hat.com, jeyu@...nel.org, jikos@...nel.org,
        mbenes@...e.cz, pmladek@...e.com
Subject: [PATCH v3 1/2] livepatch: Add dynamic klp_object and klp_func iterators

In preparation to introducing atomic replace, introduce iterators for
klp_func and klp_object, such that objects and functions can be dynamically
allocated (needed for atomic replace). This patch is intended to
effectively be a no-op until atomic replace is introduced.

Signed-off-by: Jason Baron <jbaron@...mai.com>
Cc: Josh Poimboeuf <jpoimboe@...hat.com>
Cc: Jessica Yu <jeyu@...nel.org>
Cc: Jiri Kosina <jikos@...nel.org>
Cc: Miroslav Benes <mbenes@...e.cz>
Cc: Petr Mladek <pmladek@...e.com>
---
 include/linux/livepatch.h |  81 +++++++++++++++++++++-------------
 kernel/livepatch/core.c   | 110 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 160 insertions(+), 31 deletions(-)

diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 194991e..e03ce11 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/ftrace.h>
 #include <linux/completion.h>
+#include <linux/list.h>
 
 #if IS_ENABLED(CONFIG_LIVEPATCH)
 
@@ -36,18 +37,20 @@
 
 /**
  * struct klp_func - function structure for live patching
- * @old_name:	name of the function to be patched
- * @new_func:	pointer to the patched function code
- * @old_sympos: a hint indicating which symbol position the old function
- *		can be found (optional)
- * @immediate:  patch the func immediately, bypassing safety mechanisms
- * @old_addr:	the address of the function being patched
- * @kobj:	kobject for sysfs resources
- * @stack_node:	list node for klp_ops func_stack list
- * @old_size:	size of the old function
- * @new_size:	size of the new function
- * @patched:	the func has been added to the klp_ops list
- * @transition:	the func is currently being applied or reverted
+ * @old_name:	    name of the function to be patched
+ * @new_func:	    pointer to the patched function code
+ * @old_sympos:	    a hint indicating which symbol position the old function
+ *		    can be found (optional)
+ * @immediate:	    patch the func immediately, bypassing safety mechanisms
+ * @old_addr:	    the address of the function being patched
+ * @kobj:	    kobject for sysfs resources
+ * @stack_node:	    list node for klp_ops func_stack list
+ * @nop_func_entry: links dynamically allocated struct klp_func to struct
+ *		    klp_object
+ * @old_size:	    size of the old function
+ * @new_size:	    size of the new function
+ * @patched:	    the func has been added to the klp_ops list
+ * @transition:	    the func is currently being applied or reverted
  *
  * The patched and transition variables define the func's patching state.  When
  * patching, a func is always in one of the following states:
@@ -82,6 +85,7 @@ struct klp_func {
 	unsigned long old_addr;
 	struct kobject kobj;
 	struct list_head stack_node;
+	struct list_head nop_func_entry;
 	unsigned long old_size, new_size;
 	bool patched;
 	bool transition;
@@ -89,12 +93,15 @@ struct klp_func {
 
 /**
  * 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)
- * @patched:	the object's funcs have been added to the klp_ops list
+ * @name:	   module name (or NULL for vmlinux)
+ * @funcs:	   function entries for functions to be patched in the object
+ * @kobj:	   kobject for sysfs resources
+ * @nop_func_list: head of list for dynamically allocated struct klp_func
+ * @nop_obj_entry: links dynamically allocated struct klp_object to struct
+ *		   klp_patch
+ * @mod:	   kernel module associated with the patched object
+ *		   (NULL for vmlinux)
+ * @patched:	   the object's funcs have been added to the klp_ops list
  */
 struct klp_object {
 	/* external */
@@ -103,19 +110,22 @@ struct klp_object {
 
 	/* internal */
 	struct kobject kobj;
+	struct list_head nop_func_list;
+	struct list_head nop_obj_entry;
 	struct module *mod;
 	bool patched;
 };
 
 /**
  * struct klp_patch - patch structure for live patching
- * @mod:	reference to the live patch module
- * @objs:	object entries for kernel objects to be patched
- * @immediate:  patch all funcs immediately, bypassing safety mechanisms
- * @list:	list node for global list of registered patches
- * @kobj:	kobject for sysfs resources
- * @enabled:	the patch is enabled (but operation may be incomplete)
- * @finish:	for waiting till it is safe to remove the patch module
+ * @mod:	  reference to the live patch module
+ * @objs:	  object entries for kernel objects to be patched
+ * @immediate:	  patch all funcs immediately, bypassing safety mechanisms
+ * @list:	  list node for global list of registered patches
+ * @kobj:	  kobject for sysfs resources
+ * @nop_obj_list: head of list for dynamically allocated struct klp_object
+ * @enabled:	  the patch is enabled (but operation may be incomplete)
+ * @finish:	  for waiting till it is safe to remove the patch module
  */
 struct klp_patch {
 	/* external */
@@ -126,17 +136,26 @@ struct klp_patch {
 	/* internal */
 	struct list_head list;
 	struct kobject kobj;
+	struct list_head nop_obj_list;
 	bool enabled;
 	struct completion finish;
 };
 
-#define klp_for_each_object(patch, obj) \
-	for (obj = patch->objs; obj->funcs || obj->name; obj++)
+struct klp_object *klp_obj_iter_init(struct klp_patch *patch);
+struct klp_object *klp_obj_iter_next(struct klp_patch *patch,
+				     struct klp_object *obj);
 
-#define klp_for_each_func(obj, func) \
-	for (func = obj->funcs; \
-	     func->old_name || func->new_func || func->old_sympos; \
-	     func++)
+#define klp_for_each_object(patch, obj)		  \
+	for (obj = klp_obj_iter_init(patch); obj; \
+	     obj = klp_obj_iter_next(patch, obj))
+
+struct klp_func *klp_func_iter_init(struct klp_object *obj);
+struct klp_func *klp_func_iter_next(struct klp_object *obj,
+				    struct klp_func *func);
+
+#define klp_for_each_func(obj, func)		   \
+	for (func = klp_func_iter_init(obj); func; \
+	     func = klp_func_iter_next(obj, func))
 
 int klp_register_patch(struct klp_patch *);
 int klp_unregister_patch(struct klp_patch *);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index b9628e4..0d92fe6 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -49,6 +49,100 @@ static LIST_HEAD(klp_patches);
 
 static struct kobject *klp_root_kobj;
 
+static bool klp_valid_obj_entry(struct klp_object *obj)
+{
+	return obj->funcs || obj->name;
+}
+
+struct klp_object *klp_obj_iter_init(struct klp_patch *patch)
+{
+	if (klp_valid_obj_entry(patch->objs))
+		return patch->objs;
+
+	return NULL;
+}
+
+struct klp_object *klp_obj_iter_next(struct klp_patch *patch,
+				 struct klp_object *obj)
+{
+	struct klp_object *next_obj = NULL;
+
+	/*
+	 * Statically defined objects are in NULL-ended array.
+	 * Only dynamic ones are in the nop_obj_list.
+	 */
+	if (list_empty(&obj->nop_obj_entry)) {
+		next_obj = obj + 1;
+		if (klp_valid_obj_entry(next_obj))
+			goto out;
+		next_obj = NULL;
+		if (!list_empty(&patch->nop_obj_list))
+			next_obj = list_entry(patch->nop_obj_list.next,
+					      struct klp_object,
+					      nop_obj_entry);
+		goto out;
+	}
+
+	if (obj->nop_obj_entry.next != &patch->nop_obj_list)
+		next_obj = list_entry(obj->nop_obj_entry.next,
+				      struct klp_object,
+				      nop_obj_entry);
+
+out:
+	return next_obj;
+}
+
+static bool klp_valid_func_entry(struct klp_func *func)
+{
+	return func->old_name || func->new_func || func->old_sympos;
+}
+
+struct klp_func *klp_func_iter_init(struct klp_object *obj)
+{
+	/* statically allocated */
+	if (list_empty(&obj->nop_obj_entry)) {
+		if (klp_valid_func_entry(obj->funcs))
+			return obj->funcs;
+	} else {
+		if (!list_empty(obj->nop_func_list.next))
+			return list_entry(obj->nop_func_list.next,
+					  struct klp_func,
+					  nop_func_entry);
+	}
+
+	return NULL;
+}
+
+struct klp_func *klp_func_iter_next(struct klp_object *obj,
+				    struct klp_func *func)
+{
+	struct klp_func *next_func = NULL;
+
+	/*
+	 * Statically defined functions are in NULL-ended array.
+	 * Only dynamic ones are in the nop_func_list.
+	 */
+	if (list_empty(&func->nop_func_entry)) {
+		next_func = func + 1;
+		if (klp_valid_func_entry(next_func))
+			goto out;
+		next_func = NULL;
+		if (!list_empty(&obj->nop_func_list))
+			next_func = list_entry(obj->nop_func_list.next,
+					       struct klp_func,
+					       nop_func_entry);
+		goto out;
+	}
+
+	if (func->nop_func_entry.next != &obj->nop_func_list)
+		next_func = list_entry(func->nop_func_entry.next,
+				       struct klp_func,
+				       nop_func_entry);
+
+out:
+	return next_func;
+}
+
 static bool klp_is_module(struct klp_object *obj)
 {
 	return obj->name;
@@ -709,6 +803,20 @@ static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
 	return ret;
 }
 
+static void klp_init_patch_dyn(struct klp_patch *patch)
+{
+	struct klp_object *obj;
+	struct klp_func *func;
+
+	INIT_LIST_HEAD(&patch->nop_obj_list);
+	klp_for_each_object(patch, obj) {
+		INIT_LIST_HEAD(&obj->nop_obj_entry);
+		INIT_LIST_HEAD(&obj->nop_func_list);
+		klp_for_each_func(obj, func)
+			INIT_LIST_HEAD(&func->nop_func_entry);
+	}
+}
+
 static int klp_init_patch(struct klp_patch *patch)
 {
 	struct klp_object *obj;
@@ -729,6 +837,8 @@ static int klp_init_patch(struct klp_patch *patch)
 		return ret;
 	}
 
+	klp_init_patch_dyn(patch);
+
 	klp_for_each_object(patch, obj) {
 		ret = klp_init_object(patch, obj);
 		if (ret)
-- 
2.6.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ