| 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|---|
| 2 | /* |
| 3 | * Init code for a livepatch kernel module |
| 4 | */ |
| 5 | |
| 6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 7 | |
| 8 | #include <linux/kernel.h> |
| 9 | #include <linux/slab.h> |
| 10 | #include <linux/livepatch.h> |
| 11 | |
| 12 | extern struct klp_object_ext __start_klp_objects[]; |
| 13 | extern struct klp_object_ext __stop_klp_objects[]; |
| 14 | |
| 15 | static struct klp_patch *patch; |
| 16 | |
| 17 | static int __init livepatch_mod_init(void) |
| 18 | { |
| 19 | struct klp_object *objs; |
| 20 | unsigned int nr_objs; |
| 21 | int ret; |
| 22 | |
| 23 | nr_objs = __stop_klp_objects - __start_klp_objects; |
| 24 | |
| 25 | if (!nr_objs) { |
| 26 | pr_err("nothing to patch!\n"); |
| 27 | ret = -EINVAL; |
| 28 | goto err; |
| 29 | } |
| 30 | |
| 31 | patch = kzalloc(sizeof(*patch), GFP_KERNEL); |
| 32 | if (!patch) { |
| 33 | ret = -ENOMEM; |
| 34 | goto err; |
| 35 | } |
| 36 | |
| 37 | objs = kzalloc(sizeof(struct klp_object) * (nr_objs + 1), GFP_KERNEL); |
| 38 | if (!objs) { |
| 39 | ret = -ENOMEM; |
| 40 | goto err_free_patch; |
| 41 | } |
| 42 | |
| 43 | for (int i = 0; i < nr_objs; i++) { |
| 44 | struct klp_object_ext *obj_ext = __start_klp_objects + i; |
| 45 | struct klp_func_ext *funcs_ext = obj_ext->funcs; |
| 46 | unsigned int nr_funcs = obj_ext->nr_funcs; |
| 47 | struct klp_func *funcs = objs[i].funcs; |
| 48 | struct klp_object *obj = objs + i; |
| 49 | |
| 50 | funcs = kzalloc(sizeof(struct klp_func) * (nr_funcs + 1), GFP_KERNEL); |
| 51 | if (!funcs) { |
| 52 | ret = -ENOMEM; |
| 53 | for (int j = 0; j < i; j++) |
| 54 | kfree(objs[i].funcs); |
| 55 | goto err_free_objs; |
| 56 | } |
| 57 | |
| 58 | for (int j = 0; j < nr_funcs; j++) { |
| 59 | funcs[j].old_name = funcs_ext[j].old_name; |
| 60 | funcs[j].new_func = funcs_ext[j].new_func; |
| 61 | funcs[j].old_sympos = funcs_ext[j].sympos; |
| 62 | } |
| 63 | |
| 64 | obj->name = obj_ext->name; |
| 65 | obj->funcs = funcs; |
| 66 | |
| 67 | memcpy(&obj->callbacks, &obj_ext->callbacks, sizeof(struct klp_callbacks)); |
| 68 | } |
| 69 | |
| 70 | patch->mod = THIS_MODULE; |
| 71 | patch->objs = objs; |
| 72 | |
| 73 | /* TODO patch->states */ |
| 74 | |
| 75 | #ifdef KLP_NO_REPLACE |
| 76 | patch->replace = false; |
| 77 | #else |
| 78 | patch->replace = true; |
| 79 | #endif |
| 80 | |
| 81 | return klp_enable_patch(patch); |
| 82 | |
| 83 | err_free_objs: |
| 84 | kfree(objp: objs); |
| 85 | err_free_patch: |
| 86 | kfree(objp: patch); |
| 87 | err: |
| 88 | return ret; |
| 89 | } |
| 90 | |
| 91 | static void __exit livepatch_mod_exit(void) |
| 92 | { |
| 93 | unsigned int nr_objs; |
| 94 | |
| 95 | nr_objs = __stop_klp_objects - __start_klp_objects; |
| 96 | |
| 97 | for (int i = 0; i < nr_objs; i++) |
| 98 | kfree(objp: patch->objs[i].funcs); |
| 99 | |
| 100 | kfree(objp: patch->objs); |
| 101 | kfree(objp: patch); |
| 102 | } |
| 103 | |
| 104 | module_init(livepatch_mod_init); |
| 105 | module_exit(livepatch_mod_exit); |
| 106 | MODULE_LICENSE("GPL"); |
| 107 | MODULE_INFO(livepatch, "Y"); |
| 108 | MODULE_DESCRIPTION("Livepatch module"); |
| 109 |
