xref: /linux/scripts/livepatch/init.c (revision 7fc2cd2e4b398c57c9cf961cfea05eadbf34c05c)
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(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 	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(patch->objs[i].funcs);
99 
100 	kfree(patch->objs);
101 	kfree(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