xref: /linux/scripts/livepatch/init.c (revision bf4afc53b77aeaa48b5409da5c8da6bb4eff7f43)
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 Poimboeuf static 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 Poimboeuf static 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