| 1 | |
| 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 | static struct klp_patch *patch;
|
| 13 |
|
| 14 | static int __init livepatch_mod_init(void)
|
| 15 | {
|
| 16 | struct klp_object_ext *obj_exts;
|
| 17 | size_t obj_exts_sec_size;
|
| 18 | struct klp_object *objs;
|
| 19 | unsigned int nr_objs;
|
| 20 | int ret;
|
| 21 |
|
| 22 | obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
|
| 23 | &obj_exts_sec_size);
|
| 24 | nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
|
| 25 | if (!nr_objs) {
|
| 26 | pr_err("nothing to patch!\n");
|
| 27 | ret = -EINVAL;
|
| 28 | goto err;
|
| 29 | }
|
| 30 |
|
| 31 | patch = kzalloc_obj(*patch);
|
| 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 = obj_exts + 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[j].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 |
|
| 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(objs);
|
| 85 | err_free_patch:
|
| 86 | kfree(patch);
|
| 87 | err:
|
| 88 | return ret;
|
| 89 | }
|
| 90 |
|
| 91 | static void __exit livepatch_mod_exit(void)
|
| 92 | {
|
| 93 | struct klp_object *obj;
|
| 94 |
|
| 95 | klp_for_each_object_static(patch, obj)
|
| 96 | kfree(obj->funcs);
|
| 97 |
|
| 98 | kfree(patch->objs);
|
| 99 | kfree(patch);
|
| 100 | }
|
| 101 |
|
| 102 | module_init(livepatch_mod_init);
|
| 103 | module_exit(livepatch_mod_exit);
|
| 104 | MODULE_LICENSE("GPL");
|
| 105 | MODULE_INFO(livepatch, "Y");
|
| 106 | MODULE_DESCRIPTION("Livepatch module");
|