159adee07SJosh Poimboeuf // SPDX-License-Identifier: GPL-2.0 259adee07SJosh Poimboeuf /* 359adee07SJosh Poimboeuf * Init code for a livepatch kernel module 459adee07SJosh Poimboeuf */ 559adee07SJosh Poimboeuf 659adee07SJosh Poimboeuf #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 759adee07SJosh Poimboeuf 859adee07SJosh Poimboeuf #include <linux/kernel.h> 959adee07SJosh Poimboeuf #include <linux/slab.h> 1059adee07SJosh Poimboeuf #include <linux/livepatch.h> 1159adee07SJosh Poimboeuf 1259adee07SJosh Poimboeuf static struct klp_patch *patch; 1359adee07SJosh Poimboeuf livepatch_mod_init(void)1459adee07SJosh Poimboeufstatic int __init livepatch_mod_init(void) 1559adee07SJosh Poimboeuf { 16ab108154SPetr Pavlu struct klp_object_ext *obj_exts; 17ab108154SPetr Pavlu size_t obj_exts_sec_size; 1859adee07SJosh Poimboeuf struct klp_object *objs; 1959adee07SJosh Poimboeuf unsigned int nr_objs; 2059adee07SJosh Poimboeuf int ret; 2159adee07SJosh Poimboeuf 22b525fcafSPetr Pavlu obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects", 23ab108154SPetr Pavlu &obj_exts_sec_size); 24ab108154SPetr Pavlu nr_objs = obj_exts_sec_size / sizeof(*obj_exts); 2559adee07SJosh Poimboeuf if (!nr_objs) { 2659adee07SJosh Poimboeuf pr_err("nothing to patch!\n"); 2759adee07SJosh Poimboeuf ret = -EINVAL; 2859adee07SJosh Poimboeuf goto err; 2959adee07SJosh Poimboeuf } 3059adee07SJosh Poimboeuf 31*bf4afc53SLinus Torvalds patch = kzalloc_obj(*patch); 3259adee07SJosh Poimboeuf if (!patch) { 3359adee07SJosh Poimboeuf ret = -ENOMEM; 3459adee07SJosh Poimboeuf goto err; 3559adee07SJosh Poimboeuf } 3659adee07SJosh Poimboeuf 3759adee07SJosh Poimboeuf objs = kzalloc(sizeof(struct klp_object) * (nr_objs + 1), GFP_KERNEL); 3859adee07SJosh Poimboeuf if (!objs) { 3959adee07SJosh Poimboeuf ret = -ENOMEM; 4059adee07SJosh Poimboeuf goto err_free_patch; 4159adee07SJosh Poimboeuf } 4259adee07SJosh Poimboeuf 4359adee07SJosh Poimboeuf for (int i = 0; i < nr_objs; i++) { 44ab108154SPetr Pavlu struct klp_object_ext *obj_ext = obj_exts + i; 4559adee07SJosh Poimboeuf struct klp_func_ext *funcs_ext = obj_ext->funcs; 4659adee07SJosh Poimboeuf unsigned int nr_funcs = obj_ext->nr_funcs; 4759adee07SJosh Poimboeuf struct klp_func *funcs = objs[i].funcs; 4859adee07SJosh Poimboeuf struct klp_object *obj = objs + i; 4959adee07SJosh Poimboeuf 5059adee07SJosh Poimboeuf funcs = kzalloc(sizeof(struct klp_func) * (nr_funcs + 1), GFP_KERNEL); 5159adee07SJosh Poimboeuf if (!funcs) { 5259adee07SJosh Poimboeuf ret = -ENOMEM; 5359adee07SJosh Poimboeuf for (int j = 0; j < i; j++) 5459adee07SJosh Poimboeuf kfree(objs[i].funcs); 5559adee07SJosh Poimboeuf goto err_free_objs; 5659adee07SJosh Poimboeuf } 5759adee07SJosh Poimboeuf 5859adee07SJosh Poimboeuf for (int j = 0; j < nr_funcs; j++) { 5959adee07SJosh Poimboeuf funcs[j].old_name = funcs_ext[j].old_name; 6059adee07SJosh Poimboeuf funcs[j].new_func = funcs_ext[j].new_func; 6159adee07SJosh Poimboeuf funcs[j].old_sympos = funcs_ext[j].sympos; 6259adee07SJosh Poimboeuf } 6359adee07SJosh Poimboeuf 6459adee07SJosh Poimboeuf obj->name = obj_ext->name; 6559adee07SJosh Poimboeuf obj->funcs = funcs; 6659adee07SJosh Poimboeuf 6759adee07SJosh Poimboeuf memcpy(&obj->callbacks, &obj_ext->callbacks, sizeof(struct klp_callbacks)); 6859adee07SJosh Poimboeuf } 6959adee07SJosh Poimboeuf 7059adee07SJosh Poimboeuf patch->mod = THIS_MODULE; 7159adee07SJosh Poimboeuf patch->objs = objs; 7259adee07SJosh Poimboeuf 7359adee07SJosh Poimboeuf /* TODO patch->states */ 7459adee07SJosh Poimboeuf 7559adee07SJosh Poimboeuf #ifdef KLP_NO_REPLACE 7659adee07SJosh Poimboeuf patch->replace = false; 7759adee07SJosh Poimboeuf #else 7859adee07SJosh Poimboeuf patch->replace = true; 7959adee07SJosh Poimboeuf #endif 8059adee07SJosh Poimboeuf 8159adee07SJosh Poimboeuf return klp_enable_patch(patch); 8259adee07SJosh Poimboeuf 8359adee07SJosh Poimboeuf err_free_objs: 8459adee07SJosh Poimboeuf kfree(objs); 8559adee07SJosh Poimboeuf err_free_patch: 8659adee07SJosh Poimboeuf kfree(patch); 8759adee07SJosh Poimboeuf err: 8859adee07SJosh Poimboeuf return ret; 8959adee07SJosh Poimboeuf } 9059adee07SJosh Poimboeuf livepatch_mod_exit(void)9159adee07SJosh Poimboeufstatic void __exit livepatch_mod_exit(void) 9259adee07SJosh Poimboeuf { 93ab108154SPetr Pavlu struct klp_object *obj; 9459adee07SJosh Poimboeuf 95ab108154SPetr Pavlu klp_for_each_object_static(patch, obj) 96ab108154SPetr Pavlu kfree(obj->funcs); 9759adee07SJosh Poimboeuf 9859adee07SJosh Poimboeuf kfree(patch->objs); 9959adee07SJosh Poimboeuf kfree(patch); 10059adee07SJosh Poimboeuf } 10159adee07SJosh Poimboeuf 10259adee07SJosh Poimboeuf module_init(livepatch_mod_init); 10359adee07SJosh Poimboeuf module_exit(livepatch_mod_exit); 10459adee07SJosh Poimboeuf MODULE_LICENSE("GPL"); 10559adee07SJosh Poimboeuf MODULE_INFO(livepatch, "Y"); 10659adee07SJosh Poimboeuf MODULE_DESCRIPTION("Livepatch module"); 107