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 <jba...@akamai.com>
Cc: Josh Poimboeuf <jpoim...@redhat.com>
Cc: Jessica Yu <j...@kernel.org>
Cc: Jiri Kosina <ji...@kernel.org>
Cc: Miroslav Benes <mbe...@suse.cz>
Cc: Petr Mladek <pmla...@suse.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

Reply via email to