xref: /linux-6.15/kernel/livepatch/core.c (revision c349cdca)
1b700e7f0SSeth Jennings /*
2b700e7f0SSeth Jennings  * core.c - Kernel Live Patching Core
3b700e7f0SSeth Jennings  *
4b700e7f0SSeth Jennings  * Copyright (C) 2014 Seth Jennings <[email protected]>
5b700e7f0SSeth Jennings  * Copyright (C) 2014 SUSE
6b700e7f0SSeth Jennings  *
7b700e7f0SSeth Jennings  * This program is free software; you can redistribute it and/or
8b700e7f0SSeth Jennings  * modify it under the terms of the GNU General Public License
9b700e7f0SSeth Jennings  * as published by the Free Software Foundation; either version 2
10b700e7f0SSeth Jennings  * of the License, or (at your option) any later version.
11b700e7f0SSeth Jennings  *
12b700e7f0SSeth Jennings  * This program is distributed in the hope that it will be useful,
13b700e7f0SSeth Jennings  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14b700e7f0SSeth Jennings  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b700e7f0SSeth Jennings  * GNU General Public License for more details.
16b700e7f0SSeth Jennings  *
17b700e7f0SSeth Jennings  * You should have received a copy of the GNU General Public License
18b700e7f0SSeth Jennings  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19b700e7f0SSeth Jennings  */
20b700e7f0SSeth Jennings 
21b700e7f0SSeth Jennings #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22b700e7f0SSeth Jennings 
23b700e7f0SSeth Jennings #include <linux/module.h>
24b700e7f0SSeth Jennings #include <linux/kernel.h>
25b700e7f0SSeth Jennings #include <linux/mutex.h>
26b700e7f0SSeth Jennings #include <linux/slab.h>
27b700e7f0SSeth Jennings #include <linux/list.h>
28b700e7f0SSeth Jennings #include <linux/kallsyms.h>
29b700e7f0SSeth Jennings #include <linux/livepatch.h>
30425595a7SJessica Yu #include <linux/elf.h>
31425595a7SJessica Yu #include <linux/moduleloader.h>
32b56b36eeSJosh Poimboeuf #include <asm/cacheflush.h>
33*c349cdcaSJosh Poimboeuf #include "patch.h"
34b700e7f0SSeth Jennings 
353c33f5b9SJosh Poimboeuf /*
363c33f5b9SJosh Poimboeuf  * The klp_mutex protects the global lists and state transitions of any
373c33f5b9SJosh Poimboeuf  * structure reachable from them.  References to any structure must be obtained
383c33f5b9SJosh Poimboeuf  * under mutex protection (except in klp_ftrace_handler(), which uses RCU to
393c33f5b9SJosh Poimboeuf  * ensure it gets consistent data).
403c33f5b9SJosh Poimboeuf  */
41b700e7f0SSeth Jennings static DEFINE_MUTEX(klp_mutex);
423c33f5b9SJosh Poimboeuf 
43b700e7f0SSeth Jennings static LIST_HEAD(klp_patches);
44b700e7f0SSeth Jennings 
45b700e7f0SSeth Jennings static struct kobject *klp_root_kobj;
46b700e7f0SSeth Jennings 
4746c5a011SJosh Poimboeuf /* TODO: temporary stub */
4846c5a011SJosh Poimboeuf void klp_update_patch_state(struct task_struct *task) {}
4946c5a011SJosh Poimboeuf 
50b700e7f0SSeth Jennings static bool klp_is_module(struct klp_object *obj)
51b700e7f0SSeth Jennings {
52b700e7f0SSeth Jennings 	return obj->name;
53b700e7f0SSeth Jennings }
54b700e7f0SSeth Jennings 
55b700e7f0SSeth Jennings static bool klp_is_object_loaded(struct klp_object *obj)
56b700e7f0SSeth Jennings {
57b700e7f0SSeth Jennings 	return !obj->name || obj->mod;
58b700e7f0SSeth Jennings }
59b700e7f0SSeth Jennings 
60b700e7f0SSeth Jennings /* sets obj->mod if object is not vmlinux and module is found */
61b700e7f0SSeth Jennings static void klp_find_object_module(struct klp_object *obj)
62b700e7f0SSeth Jennings {
638cb2c2dcSPetr Mladek 	struct module *mod;
648cb2c2dcSPetr Mladek 
65b700e7f0SSeth Jennings 	if (!klp_is_module(obj))
66b700e7f0SSeth Jennings 		return;
67b700e7f0SSeth Jennings 
68b700e7f0SSeth Jennings 	mutex_lock(&module_mutex);
69b700e7f0SSeth Jennings 	/*
708cb2c2dcSPetr Mladek 	 * We do not want to block removal of patched modules and therefore
718cb2c2dcSPetr Mladek 	 * we do not take a reference here. The patches are removed by
727e545d6eSJessica Yu 	 * klp_module_going() instead.
73b700e7f0SSeth Jennings 	 */
748cb2c2dcSPetr Mladek 	mod = find_module(obj->name);
758cb2c2dcSPetr Mladek 	/*
767e545d6eSJessica Yu 	 * Do not mess work of klp_module_coming() and klp_module_going().
777e545d6eSJessica Yu 	 * Note that the patch might still be needed before klp_module_going()
788cb2c2dcSPetr Mladek 	 * is called. Module functions can be called even in the GOING state
798cb2c2dcSPetr Mladek 	 * until mod->exit() finishes. This is especially important for
808cb2c2dcSPetr Mladek 	 * patches that modify semantic of the functions.
818cb2c2dcSPetr Mladek 	 */
828cb2c2dcSPetr Mladek 	if (mod && mod->klp_alive)
838cb2c2dcSPetr Mladek 		obj->mod = mod;
848cb2c2dcSPetr Mladek 
85b700e7f0SSeth Jennings 	mutex_unlock(&module_mutex);
86b700e7f0SSeth Jennings }
87b700e7f0SSeth Jennings 
88b700e7f0SSeth Jennings /* klp_mutex must be held by caller */
89b700e7f0SSeth Jennings static bool klp_is_patch_registered(struct klp_patch *patch)
90b700e7f0SSeth Jennings {
91b700e7f0SSeth Jennings 	struct klp_patch *mypatch;
92b700e7f0SSeth Jennings 
93b700e7f0SSeth Jennings 	list_for_each_entry(mypatch, &klp_patches, list)
94b700e7f0SSeth Jennings 		if (mypatch == patch)
95b700e7f0SSeth Jennings 			return true;
96b700e7f0SSeth Jennings 
97b700e7f0SSeth Jennings 	return false;
98b700e7f0SSeth Jennings }
99b700e7f0SSeth Jennings 
100b700e7f0SSeth Jennings static bool klp_initialized(void)
101b700e7f0SSeth Jennings {
102e76ff06aSNicholas Mc Guire 	return !!klp_root_kobj;
103b700e7f0SSeth Jennings }
104b700e7f0SSeth Jennings 
105b700e7f0SSeth Jennings struct klp_find_arg {
106b700e7f0SSeth Jennings 	const char *objname;
107b700e7f0SSeth Jennings 	const char *name;
108b700e7f0SSeth Jennings 	unsigned long addr;
109b700e7f0SSeth Jennings 	unsigned long count;
110b2b018efSChris J Arges 	unsigned long pos;
111b700e7f0SSeth Jennings };
112b700e7f0SSeth Jennings 
113b700e7f0SSeth Jennings static int klp_find_callback(void *data, const char *name,
114b700e7f0SSeth Jennings 			     struct module *mod, unsigned long addr)
115b700e7f0SSeth Jennings {
116b700e7f0SSeth Jennings 	struct klp_find_arg *args = data;
117b700e7f0SSeth Jennings 
118b700e7f0SSeth Jennings 	if ((mod && !args->objname) || (!mod && args->objname))
119b700e7f0SSeth Jennings 		return 0;
120b700e7f0SSeth Jennings 
121b700e7f0SSeth Jennings 	if (strcmp(args->name, name))
122b700e7f0SSeth Jennings 		return 0;
123b700e7f0SSeth Jennings 
124b700e7f0SSeth Jennings 	if (args->objname && strcmp(args->objname, mod->name))
125b700e7f0SSeth Jennings 		return 0;
126b700e7f0SSeth Jennings 
127b700e7f0SSeth Jennings 	args->addr = addr;
128b700e7f0SSeth Jennings 	args->count++;
129b700e7f0SSeth Jennings 
130b2b018efSChris J Arges 	/*
131b2b018efSChris J Arges 	 * Finish the search when the symbol is found for the desired position
132b2b018efSChris J Arges 	 * or the position is not defined for a non-unique symbol.
133b2b018efSChris J Arges 	 */
134b2b018efSChris J Arges 	if ((args->pos && (args->count == args->pos)) ||
135b2b018efSChris J Arges 	    (!args->pos && (args->count > 1)))
136b2b018efSChris J Arges 		return 1;
137b2b018efSChris J Arges 
138b700e7f0SSeth Jennings 	return 0;
139b700e7f0SSeth Jennings }
140b700e7f0SSeth Jennings 
141b700e7f0SSeth Jennings static int klp_find_object_symbol(const char *objname, const char *name,
142b2b018efSChris J Arges 				  unsigned long sympos, unsigned long *addr)
143b700e7f0SSeth Jennings {
144b700e7f0SSeth Jennings 	struct klp_find_arg args = {
145b700e7f0SSeth Jennings 		.objname = objname,
146b700e7f0SSeth Jennings 		.name = name,
147b700e7f0SSeth Jennings 		.addr = 0,
148b2b018efSChris J Arges 		.count = 0,
149b2b018efSChris J Arges 		.pos = sympos,
150b700e7f0SSeth Jennings 	};
151b700e7f0SSeth Jennings 
1529a1bd63cSMiroslav Benes 	mutex_lock(&module_mutex);
153b700e7f0SSeth Jennings 	kallsyms_on_each_symbol(klp_find_callback, &args);
1549a1bd63cSMiroslav Benes 	mutex_unlock(&module_mutex);
155b700e7f0SSeth Jennings 
156b2b018efSChris J Arges 	/*
157b2b018efSChris J Arges 	 * Ensure an address was found. If sympos is 0, ensure symbol is unique;
158b2b018efSChris J Arges 	 * otherwise ensure the symbol position count matches sympos.
159b2b018efSChris J Arges 	 */
160b2b018efSChris J Arges 	if (args.addr == 0)
161b700e7f0SSeth Jennings 		pr_err("symbol '%s' not found in symbol table\n", name);
162b2b018efSChris J Arges 	else if (args.count > 1 && sympos == 0) {
163f995b5f7SPetr Mladek 		pr_err("unresolvable ambiguity for symbol '%s' in object '%s'\n",
164f995b5f7SPetr Mladek 		       name, objname);
165b2b018efSChris J Arges 	} else if (sympos != args.count && sympos > 0) {
166b2b018efSChris J Arges 		pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n",
167b2b018efSChris J Arges 		       sympos, name, objname ? objname : "vmlinux");
168b2b018efSChris J Arges 	} else {
169b700e7f0SSeth Jennings 		*addr = args.addr;
170b700e7f0SSeth Jennings 		return 0;
171b700e7f0SSeth Jennings 	}
172b700e7f0SSeth Jennings 
173b700e7f0SSeth Jennings 	*addr = 0;
174b700e7f0SSeth Jennings 	return -EINVAL;
175b700e7f0SSeth Jennings }
176b700e7f0SSeth Jennings 
177425595a7SJessica Yu static int klp_resolve_symbols(Elf_Shdr *relasec, struct module *pmod)
178b700e7f0SSeth Jennings {
179425595a7SJessica Yu 	int i, cnt, vmlinux, ret;
180425595a7SJessica Yu 	char objname[MODULE_NAME_LEN];
181425595a7SJessica Yu 	char symname[KSYM_NAME_LEN];
182425595a7SJessica Yu 	char *strtab = pmod->core_kallsyms.strtab;
183425595a7SJessica Yu 	Elf_Rela *relas;
184425595a7SJessica Yu 	Elf_Sym *sym;
185425595a7SJessica Yu 	unsigned long sympos, addr;
186b700e7f0SSeth Jennings 
187b2b018efSChris J Arges 	/*
188425595a7SJessica Yu 	 * Since the field widths for objname and symname in the sscanf()
189425595a7SJessica Yu 	 * call are hard-coded and correspond to MODULE_NAME_LEN and
190425595a7SJessica Yu 	 * KSYM_NAME_LEN respectively, we must make sure that MODULE_NAME_LEN
191425595a7SJessica Yu 	 * and KSYM_NAME_LEN have the values we expect them to have.
192425595a7SJessica Yu 	 *
193425595a7SJessica Yu 	 * Because the value of MODULE_NAME_LEN can differ among architectures,
194425595a7SJessica Yu 	 * we use the smallest/strictest upper bound possible (56, based on
195425595a7SJessica Yu 	 * the current definition of MODULE_NAME_LEN) to prevent overflows.
196b2b018efSChris J Arges 	 */
197425595a7SJessica Yu 	BUILD_BUG_ON(MODULE_NAME_LEN < 56 || KSYM_NAME_LEN != 128);
198425595a7SJessica Yu 
199425595a7SJessica Yu 	relas = (Elf_Rela *) relasec->sh_addr;
200425595a7SJessica Yu 	/* For each rela in this klp relocation section */
201425595a7SJessica Yu 	for (i = 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) {
202425595a7SJessica Yu 		sym = pmod->core_kallsyms.symtab + ELF_R_SYM(relas[i].r_info);
203425595a7SJessica Yu 		if (sym->st_shndx != SHN_LIVEPATCH) {
204425595a7SJessica Yu 			pr_err("symbol %s is not marked as a livepatch symbol",
205425595a7SJessica Yu 			       strtab + sym->st_name);
206425595a7SJessica Yu 			return -EINVAL;
207425595a7SJessica Yu 		}
208425595a7SJessica Yu 
209425595a7SJessica Yu 		/* Format: .klp.sym.objname.symname,sympos */
210425595a7SJessica Yu 		cnt = sscanf(strtab + sym->st_name,
211425595a7SJessica Yu 			     ".klp.sym.%55[^.].%127[^,],%lu",
212425595a7SJessica Yu 			     objname, symname, &sympos);
213425595a7SJessica Yu 		if (cnt != 3) {
214425595a7SJessica Yu 			pr_err("symbol %s has an incorrectly formatted name",
215425595a7SJessica Yu 			       strtab + sym->st_name);
216425595a7SJessica Yu 			return -EINVAL;
217425595a7SJessica Yu 		}
218425595a7SJessica Yu 
219425595a7SJessica Yu 		/* klp_find_object_symbol() treats a NULL objname as vmlinux */
220425595a7SJessica Yu 		vmlinux = !strcmp(objname, "vmlinux");
221425595a7SJessica Yu 		ret = klp_find_object_symbol(vmlinux ? NULL : objname,
222425595a7SJessica Yu 					     symname, sympos, &addr);
223425595a7SJessica Yu 		if (ret)
224425595a7SJessica Yu 			return ret;
225425595a7SJessica Yu 
226425595a7SJessica Yu 		sym->st_value = addr;
227425595a7SJessica Yu 	}
228425595a7SJessica Yu 
229425595a7SJessica Yu 	return 0;
230b700e7f0SSeth Jennings }
231b700e7f0SSeth Jennings 
232b700e7f0SSeth Jennings static int klp_write_object_relocations(struct module *pmod,
233b700e7f0SSeth Jennings 					struct klp_object *obj)
234b700e7f0SSeth Jennings {
235425595a7SJessica Yu 	int i, cnt, ret = 0;
236425595a7SJessica Yu 	const char *objname, *secname;
237425595a7SJessica Yu 	char sec_objname[MODULE_NAME_LEN];
238425595a7SJessica Yu 	Elf_Shdr *sec;
239b700e7f0SSeth Jennings 
240b700e7f0SSeth Jennings 	if (WARN_ON(!klp_is_object_loaded(obj)))
241b700e7f0SSeth Jennings 		return -EINVAL;
242b700e7f0SSeth Jennings 
243425595a7SJessica Yu 	objname = klp_is_module(obj) ? obj->name : "vmlinux";
244b700e7f0SSeth Jennings 
245425595a7SJessica Yu 	/* For each klp relocation section */
246425595a7SJessica Yu 	for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
247425595a7SJessica Yu 		sec = pmod->klp_info->sechdrs + i;
248425595a7SJessica Yu 		secname = pmod->klp_info->secstrings + sec->sh_name;
249425595a7SJessica Yu 		if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
250425595a7SJessica Yu 			continue;
251b56b36eeSJosh Poimboeuf 
252425595a7SJessica Yu 		/*
253425595a7SJessica Yu 		 * Format: .klp.rela.sec_objname.section_name
254425595a7SJessica Yu 		 * See comment in klp_resolve_symbols() for an explanation
255425595a7SJessica Yu 		 * of the selected field width value.
256425595a7SJessica Yu 		 */
257425595a7SJessica Yu 		cnt = sscanf(secname, ".klp.rela.%55[^.]", sec_objname);
258425595a7SJessica Yu 		if (cnt != 1) {
259425595a7SJessica Yu 			pr_err("section %s has an incorrectly formatted name",
260425595a7SJessica Yu 			       secname);
261b56b36eeSJosh Poimboeuf 			ret = -EINVAL;
262425595a7SJessica Yu 			break;
263b700e7f0SSeth Jennings 		}
264425595a7SJessica Yu 
265425595a7SJessica Yu 		if (strcmp(objname, sec_objname))
266425595a7SJessica Yu 			continue;
267425595a7SJessica Yu 
268425595a7SJessica Yu 		ret = klp_resolve_symbols(sec, pmod);
269064c89dfSChris J Arges 		if (ret)
270425595a7SJessica Yu 			break;
271064c89dfSChris J Arges 
272425595a7SJessica Yu 		ret = apply_relocate_add(pmod->klp_info->sechdrs,
273425595a7SJessica Yu 					 pmod->core_kallsyms.strtab,
274425595a7SJessica Yu 					 pmod->klp_info->symndx, i, pmod);
275425595a7SJessica Yu 		if (ret)
276425595a7SJessica Yu 			break;
277b700e7f0SSeth Jennings 	}
278b700e7f0SSeth Jennings 
279b56b36eeSJosh Poimboeuf 	return ret;
280b700e7f0SSeth Jennings }
281b700e7f0SSeth Jennings 
282b700e7f0SSeth Jennings static int __klp_disable_patch(struct klp_patch *patch)
283b700e7f0SSeth Jennings {
284b700e7f0SSeth Jennings 	struct klp_object *obj;
285b700e7f0SSeth Jennings 
28683a90bb1SJosh Poimboeuf 	/* enforce stacking: only the last enabled patch can be disabled */
28783a90bb1SJosh Poimboeuf 	if (!list_is_last(&patch->list, &klp_patches) &&
2880dade9f3SJosh Poimboeuf 	    list_next_entry(patch, list)->enabled)
28983a90bb1SJosh Poimboeuf 		return -EBUSY;
29083a90bb1SJosh Poimboeuf 
291b700e7f0SSeth Jennings 	pr_notice("disabling patch '%s'\n", patch->mod->name);
292b700e7f0SSeth Jennings 
2938cdd043aSJiri Slaby 	klp_for_each_object(patch, obj) {
2940dade9f3SJosh Poimboeuf 		if (obj->patched)
2950dade9f3SJosh Poimboeuf 			klp_unpatch_object(obj);
296b700e7f0SSeth Jennings 	}
297b700e7f0SSeth Jennings 
2980dade9f3SJosh Poimboeuf 	patch->enabled = false;
299b700e7f0SSeth Jennings 
300b700e7f0SSeth Jennings 	return 0;
301b700e7f0SSeth Jennings }
302b700e7f0SSeth Jennings 
303b700e7f0SSeth Jennings /**
304b700e7f0SSeth Jennings  * klp_disable_patch() - disables a registered patch
305b700e7f0SSeth Jennings  * @patch:	The registered, enabled patch to be disabled
306b700e7f0SSeth Jennings  *
307b700e7f0SSeth Jennings  * Unregisters the patched functions from ftrace.
308b700e7f0SSeth Jennings  *
309b700e7f0SSeth Jennings  * Return: 0 on success, otherwise error
310b700e7f0SSeth Jennings  */
311b700e7f0SSeth Jennings int klp_disable_patch(struct klp_patch *patch)
312b700e7f0SSeth Jennings {
313b700e7f0SSeth Jennings 	int ret;
314b700e7f0SSeth Jennings 
315b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
316b700e7f0SSeth Jennings 
317b700e7f0SSeth Jennings 	if (!klp_is_patch_registered(patch)) {
318b700e7f0SSeth Jennings 		ret = -EINVAL;
319b700e7f0SSeth Jennings 		goto err;
320b700e7f0SSeth Jennings 	}
321b700e7f0SSeth Jennings 
3220dade9f3SJosh Poimboeuf 	if (!patch->enabled) {
323b700e7f0SSeth Jennings 		ret = -EINVAL;
324b700e7f0SSeth Jennings 		goto err;
325b700e7f0SSeth Jennings 	}
326b700e7f0SSeth Jennings 
327b700e7f0SSeth Jennings 	ret = __klp_disable_patch(patch);
328b700e7f0SSeth Jennings 
329b700e7f0SSeth Jennings err:
330b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
331b700e7f0SSeth Jennings 	return ret;
332b700e7f0SSeth Jennings }
333b700e7f0SSeth Jennings EXPORT_SYMBOL_GPL(klp_disable_patch);
334b700e7f0SSeth Jennings 
335b700e7f0SSeth Jennings static int __klp_enable_patch(struct klp_patch *patch)
336b700e7f0SSeth Jennings {
337b700e7f0SSeth Jennings 	struct klp_object *obj;
338b700e7f0SSeth Jennings 	int ret;
339b700e7f0SSeth Jennings 
3400dade9f3SJosh Poimboeuf 	if (WARN_ON(patch->enabled))
341b700e7f0SSeth Jennings 		return -EINVAL;
342b700e7f0SSeth Jennings 
34383a90bb1SJosh Poimboeuf 	/* enforce stacking: only the first disabled patch can be enabled */
34483a90bb1SJosh Poimboeuf 	if (patch->list.prev != &klp_patches &&
3450dade9f3SJosh Poimboeuf 	    !list_prev_entry(patch, list)->enabled)
34683a90bb1SJosh Poimboeuf 		return -EBUSY;
34783a90bb1SJosh Poimboeuf 
348b700e7f0SSeth Jennings 	pr_notice("enabling patch '%s'\n", patch->mod->name);
349b700e7f0SSeth Jennings 
3508cdd043aSJiri Slaby 	klp_for_each_object(patch, obj) {
351b700e7f0SSeth Jennings 		if (!klp_is_object_loaded(obj))
352b700e7f0SSeth Jennings 			continue;
353b700e7f0SSeth Jennings 
3540dade9f3SJosh Poimboeuf 		ret = klp_patch_object(obj);
355b700e7f0SSeth Jennings 		if (ret)
356b700e7f0SSeth Jennings 			goto unregister;
357b700e7f0SSeth Jennings 	}
358b700e7f0SSeth Jennings 
3590dade9f3SJosh Poimboeuf 	patch->enabled = true;
360b700e7f0SSeth Jennings 
361b700e7f0SSeth Jennings 	return 0;
362b700e7f0SSeth Jennings 
363b700e7f0SSeth Jennings unregister:
364b700e7f0SSeth Jennings 	WARN_ON(__klp_disable_patch(patch));
365b700e7f0SSeth Jennings 	return ret;
366b700e7f0SSeth Jennings }
367b700e7f0SSeth Jennings 
368b700e7f0SSeth Jennings /**
369b700e7f0SSeth Jennings  * klp_enable_patch() - enables a registered patch
370b700e7f0SSeth Jennings  * @patch:	The registered, disabled patch to be enabled
371b700e7f0SSeth Jennings  *
372b700e7f0SSeth Jennings  * Performs the needed symbol lookups and code relocations,
373b700e7f0SSeth Jennings  * then registers the patched functions with ftrace.
374b700e7f0SSeth Jennings  *
375b700e7f0SSeth Jennings  * Return: 0 on success, otherwise error
376b700e7f0SSeth Jennings  */
377b700e7f0SSeth Jennings int klp_enable_patch(struct klp_patch *patch)
378b700e7f0SSeth Jennings {
379b700e7f0SSeth Jennings 	int ret;
380b700e7f0SSeth Jennings 
381b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
382b700e7f0SSeth Jennings 
383b700e7f0SSeth Jennings 	if (!klp_is_patch_registered(patch)) {
384b700e7f0SSeth Jennings 		ret = -EINVAL;
385b700e7f0SSeth Jennings 		goto err;
386b700e7f0SSeth Jennings 	}
387b700e7f0SSeth Jennings 
388b700e7f0SSeth Jennings 	ret = __klp_enable_patch(patch);
389b700e7f0SSeth Jennings 
390b700e7f0SSeth Jennings err:
391b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
392b700e7f0SSeth Jennings 	return ret;
393b700e7f0SSeth Jennings }
394b700e7f0SSeth Jennings EXPORT_SYMBOL_GPL(klp_enable_patch);
395b700e7f0SSeth Jennings 
396b700e7f0SSeth Jennings /*
397b700e7f0SSeth Jennings  * Sysfs Interface
398b700e7f0SSeth Jennings  *
399b700e7f0SSeth Jennings  * /sys/kernel/livepatch
400b700e7f0SSeth Jennings  * /sys/kernel/livepatch/<patch>
401b700e7f0SSeth Jennings  * /sys/kernel/livepatch/<patch>/enabled
402b700e7f0SSeth Jennings  * /sys/kernel/livepatch/<patch>/<object>
403444f9e99SChris J Arges  * /sys/kernel/livepatch/<patch>/<object>/<function,sympos>
404b700e7f0SSeth Jennings  */
405b700e7f0SSeth Jennings 
406b700e7f0SSeth Jennings static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
407b700e7f0SSeth Jennings 			     const char *buf, size_t count)
408b700e7f0SSeth Jennings {
409b700e7f0SSeth Jennings 	struct klp_patch *patch;
410b700e7f0SSeth Jennings 	int ret;
411b700e7f0SSeth Jennings 	unsigned long val;
412b700e7f0SSeth Jennings 
413b700e7f0SSeth Jennings 	ret = kstrtoul(buf, 10, &val);
414b700e7f0SSeth Jennings 	if (ret)
415b700e7f0SSeth Jennings 		return -EINVAL;
416b700e7f0SSeth Jennings 
4170dade9f3SJosh Poimboeuf 	if (val > 1)
418b700e7f0SSeth Jennings 		return -EINVAL;
419b700e7f0SSeth Jennings 
420b700e7f0SSeth Jennings 	patch = container_of(kobj, struct klp_patch, kobj);
421b700e7f0SSeth Jennings 
422b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
423b700e7f0SSeth Jennings 
4240dade9f3SJosh Poimboeuf 	if (patch->enabled == val) {
425b700e7f0SSeth Jennings 		/* already in requested state */
426b700e7f0SSeth Jennings 		ret = -EINVAL;
427b700e7f0SSeth Jennings 		goto err;
428b700e7f0SSeth Jennings 	}
429b700e7f0SSeth Jennings 
4300dade9f3SJosh Poimboeuf 	if (val) {
431b700e7f0SSeth Jennings 		ret = __klp_enable_patch(patch);
432b700e7f0SSeth Jennings 		if (ret)
433b700e7f0SSeth Jennings 			goto err;
434b700e7f0SSeth Jennings 	} else {
435b700e7f0SSeth Jennings 		ret = __klp_disable_patch(patch);
436b700e7f0SSeth Jennings 		if (ret)
437b700e7f0SSeth Jennings 			goto err;
438b700e7f0SSeth Jennings 	}
439b700e7f0SSeth Jennings 
440b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
441b700e7f0SSeth Jennings 
442b700e7f0SSeth Jennings 	return count;
443b700e7f0SSeth Jennings 
444b700e7f0SSeth Jennings err:
445b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
446b700e7f0SSeth Jennings 	return ret;
447b700e7f0SSeth Jennings }
448b700e7f0SSeth Jennings 
449b700e7f0SSeth Jennings static ssize_t enabled_show(struct kobject *kobj,
450b700e7f0SSeth Jennings 			    struct kobj_attribute *attr, char *buf)
451b700e7f0SSeth Jennings {
452b700e7f0SSeth Jennings 	struct klp_patch *patch;
453b700e7f0SSeth Jennings 
454b700e7f0SSeth Jennings 	patch = container_of(kobj, struct klp_patch, kobj);
4550dade9f3SJosh Poimboeuf 	return snprintf(buf, PAGE_SIZE-1, "%d\n", patch->enabled);
456b700e7f0SSeth Jennings }
457b700e7f0SSeth Jennings 
458b700e7f0SSeth Jennings static struct kobj_attribute enabled_kobj_attr = __ATTR_RW(enabled);
459b700e7f0SSeth Jennings static struct attribute *klp_patch_attrs[] = {
460b700e7f0SSeth Jennings 	&enabled_kobj_attr.attr,
461b700e7f0SSeth Jennings 	NULL
462b700e7f0SSeth Jennings };
463b700e7f0SSeth Jennings 
464b700e7f0SSeth Jennings static void klp_kobj_release_patch(struct kobject *kobj)
465b700e7f0SSeth Jennings {
466b700e7f0SSeth Jennings 	/*
467b700e7f0SSeth Jennings 	 * Once we have a consistency model we'll need to module_put() the
468b700e7f0SSeth Jennings 	 * patch module here.  See klp_register_patch() for more details.
469b700e7f0SSeth Jennings 	 */
470b700e7f0SSeth Jennings }
471b700e7f0SSeth Jennings 
472b700e7f0SSeth Jennings static struct kobj_type klp_ktype_patch = {
473b700e7f0SSeth Jennings 	.release = klp_kobj_release_patch,
474b700e7f0SSeth Jennings 	.sysfs_ops = &kobj_sysfs_ops,
475b700e7f0SSeth Jennings 	.default_attrs = klp_patch_attrs,
476b700e7f0SSeth Jennings };
477b700e7f0SSeth Jennings 
478cad706dfSMiroslav Benes static void klp_kobj_release_object(struct kobject *kobj)
479cad706dfSMiroslav Benes {
480cad706dfSMiroslav Benes }
481cad706dfSMiroslav Benes 
482cad706dfSMiroslav Benes static struct kobj_type klp_ktype_object = {
483cad706dfSMiroslav Benes 	.release = klp_kobj_release_object,
484cad706dfSMiroslav Benes 	.sysfs_ops = &kobj_sysfs_ops,
485cad706dfSMiroslav Benes };
486cad706dfSMiroslav Benes 
487b700e7f0SSeth Jennings static void klp_kobj_release_func(struct kobject *kobj)
488b700e7f0SSeth Jennings {
489b700e7f0SSeth Jennings }
490b700e7f0SSeth Jennings 
491b700e7f0SSeth Jennings static struct kobj_type klp_ktype_func = {
492b700e7f0SSeth Jennings 	.release = klp_kobj_release_func,
493b700e7f0SSeth Jennings 	.sysfs_ops = &kobj_sysfs_ops,
494b700e7f0SSeth Jennings };
495b700e7f0SSeth Jennings 
496b700e7f0SSeth Jennings /*
497b700e7f0SSeth Jennings  * Free all functions' kobjects in the array up to some limit. When limit is
498b700e7f0SSeth Jennings  * NULL, all kobjects are freed.
499b700e7f0SSeth Jennings  */
500b700e7f0SSeth Jennings static void klp_free_funcs_limited(struct klp_object *obj,
501b700e7f0SSeth Jennings 				   struct klp_func *limit)
502b700e7f0SSeth Jennings {
503b700e7f0SSeth Jennings 	struct klp_func *func;
504b700e7f0SSeth Jennings 
505b700e7f0SSeth Jennings 	for (func = obj->funcs; func->old_name && func != limit; func++)
506b700e7f0SSeth Jennings 		kobject_put(&func->kobj);
507b700e7f0SSeth Jennings }
508b700e7f0SSeth Jennings 
509b700e7f0SSeth Jennings /* Clean up when a patched object is unloaded */
510b700e7f0SSeth Jennings static void klp_free_object_loaded(struct klp_object *obj)
511b700e7f0SSeth Jennings {
512b700e7f0SSeth Jennings 	struct klp_func *func;
513b700e7f0SSeth Jennings 
514b700e7f0SSeth Jennings 	obj->mod = NULL;
515b700e7f0SSeth Jennings 
5168cdd043aSJiri Slaby 	klp_for_each_func(obj, func)
517b700e7f0SSeth Jennings 		func->old_addr = 0;
518b700e7f0SSeth Jennings }
519b700e7f0SSeth Jennings 
520b700e7f0SSeth Jennings /*
521b700e7f0SSeth Jennings  * Free all objects' kobjects in the array up to some limit. When limit is
522b700e7f0SSeth Jennings  * NULL, all kobjects are freed.
523b700e7f0SSeth Jennings  */
524b700e7f0SSeth Jennings static void klp_free_objects_limited(struct klp_patch *patch,
525b700e7f0SSeth Jennings 				     struct klp_object *limit)
526b700e7f0SSeth Jennings {
527b700e7f0SSeth Jennings 	struct klp_object *obj;
528b700e7f0SSeth Jennings 
529b700e7f0SSeth Jennings 	for (obj = patch->objs; obj->funcs && obj != limit; obj++) {
530b700e7f0SSeth Jennings 		klp_free_funcs_limited(obj, NULL);
531cad706dfSMiroslav Benes 		kobject_put(&obj->kobj);
532b700e7f0SSeth Jennings 	}
533b700e7f0SSeth Jennings }
534b700e7f0SSeth Jennings 
535b700e7f0SSeth Jennings static void klp_free_patch(struct klp_patch *patch)
536b700e7f0SSeth Jennings {
537b700e7f0SSeth Jennings 	klp_free_objects_limited(patch, NULL);
538b700e7f0SSeth Jennings 	if (!list_empty(&patch->list))
539b700e7f0SSeth Jennings 		list_del(&patch->list);
540b700e7f0SSeth Jennings 	kobject_put(&patch->kobj);
541b700e7f0SSeth Jennings }
542b700e7f0SSeth Jennings 
543b700e7f0SSeth Jennings static int klp_init_func(struct klp_object *obj, struct klp_func *func)
544b700e7f0SSeth Jennings {
545f09d9086SMiroslav Benes 	if (!func->old_name || !func->new_func)
546f09d9086SMiroslav Benes 		return -EINVAL;
547f09d9086SMiroslav Benes 
5483c33f5b9SJosh Poimboeuf 	INIT_LIST_HEAD(&func->stack_node);
5490dade9f3SJosh Poimboeuf 	func->patched = false;
550b700e7f0SSeth Jennings 
551444f9e99SChris J Arges 	/* The format for the sysfs directory is <function,sympos> where sympos
552444f9e99SChris J Arges 	 * is the nth occurrence of this symbol in kallsyms for the patched
553444f9e99SChris J Arges 	 * object. If the user selects 0 for old_sympos, then 1 will be used
554444f9e99SChris J Arges 	 * since a unique symbol will be the first occurrence.
555444f9e99SChris J Arges 	 */
5563c33f5b9SJosh Poimboeuf 	return kobject_init_and_add(&func->kobj, &klp_ktype_func,
557444f9e99SChris J Arges 				    &obj->kobj, "%s,%lu", func->old_name,
558444f9e99SChris J Arges 				    func->old_sympos ? func->old_sympos : 1);
559b700e7f0SSeth Jennings }
560b700e7f0SSeth Jennings 
561255e732cSJessica Yu /* Arches may override this to finish any remaining arch-specific tasks */
562255e732cSJessica Yu void __weak arch_klp_init_object_loaded(struct klp_patch *patch,
563255e732cSJessica Yu 					struct klp_object *obj)
564255e732cSJessica Yu {
565255e732cSJessica Yu }
566255e732cSJessica Yu 
567b700e7f0SSeth Jennings /* parts of the initialization that is done only when the object is loaded */
568b700e7f0SSeth Jennings static int klp_init_object_loaded(struct klp_patch *patch,
569b700e7f0SSeth Jennings 				  struct klp_object *obj)
570b700e7f0SSeth Jennings {
571b700e7f0SSeth Jennings 	struct klp_func *func;
572b700e7f0SSeth Jennings 	int ret;
573b700e7f0SSeth Jennings 
574255e732cSJessica Yu 	module_disable_ro(patch->mod);
575b700e7f0SSeth Jennings 	ret = klp_write_object_relocations(patch->mod, obj);
576255e732cSJessica Yu 	if (ret) {
577255e732cSJessica Yu 		module_enable_ro(patch->mod, true);
578b700e7f0SSeth Jennings 		return ret;
579255e732cSJessica Yu 	}
580255e732cSJessica Yu 
581255e732cSJessica Yu 	arch_klp_init_object_loaded(patch, obj);
582255e732cSJessica Yu 	module_enable_ro(patch->mod, true);
583b700e7f0SSeth Jennings 
5848cdd043aSJiri Slaby 	klp_for_each_func(obj, func) {
585b2b018efSChris J Arges 		ret = klp_find_object_symbol(obj->name, func->old_name,
586b2b018efSChris J Arges 					     func->old_sympos,
587b2b018efSChris J Arges 					     &func->old_addr);
588b700e7f0SSeth Jennings 		if (ret)
589b700e7f0SSeth Jennings 			return ret;
590b700e7f0SSeth Jennings 	}
591b700e7f0SSeth Jennings 
592b700e7f0SSeth Jennings 	return 0;
593b700e7f0SSeth Jennings }
594b700e7f0SSeth Jennings 
595b700e7f0SSeth Jennings static int klp_init_object(struct klp_patch *patch, struct klp_object *obj)
596b700e7f0SSeth Jennings {
597b700e7f0SSeth Jennings 	struct klp_func *func;
598b700e7f0SSeth Jennings 	int ret;
599b700e7f0SSeth Jennings 	const char *name;
600b700e7f0SSeth Jennings 
601b700e7f0SSeth Jennings 	if (!obj->funcs)
602b700e7f0SSeth Jennings 		return -EINVAL;
603b700e7f0SSeth Jennings 
6040dade9f3SJosh Poimboeuf 	obj->patched = false;
6058cb2c2dcSPetr Mladek 	obj->mod = NULL;
606b700e7f0SSeth Jennings 
607b700e7f0SSeth Jennings 	klp_find_object_module(obj);
608b700e7f0SSeth Jennings 
609b700e7f0SSeth Jennings 	name = klp_is_module(obj) ? obj->name : "vmlinux";
610cad706dfSMiroslav Benes 	ret = kobject_init_and_add(&obj->kobj, &klp_ktype_object,
611cad706dfSMiroslav Benes 				   &patch->kobj, "%s", name);
612cad706dfSMiroslav Benes 	if (ret)
613cad706dfSMiroslav Benes 		return ret;
614b700e7f0SSeth Jennings 
6158cdd043aSJiri Slaby 	klp_for_each_func(obj, func) {
616b700e7f0SSeth Jennings 		ret = klp_init_func(obj, func);
617b700e7f0SSeth Jennings 		if (ret)
618b700e7f0SSeth Jennings 			goto free;
619b700e7f0SSeth Jennings 	}
620b700e7f0SSeth Jennings 
621b700e7f0SSeth Jennings 	if (klp_is_object_loaded(obj)) {
622b700e7f0SSeth Jennings 		ret = klp_init_object_loaded(patch, obj);
623b700e7f0SSeth Jennings 		if (ret)
624b700e7f0SSeth Jennings 			goto free;
625b700e7f0SSeth Jennings 	}
626b700e7f0SSeth Jennings 
627b700e7f0SSeth Jennings 	return 0;
628b700e7f0SSeth Jennings 
629b700e7f0SSeth Jennings free:
630b700e7f0SSeth Jennings 	klp_free_funcs_limited(obj, func);
631cad706dfSMiroslav Benes 	kobject_put(&obj->kobj);
632b700e7f0SSeth Jennings 	return ret;
633b700e7f0SSeth Jennings }
634b700e7f0SSeth Jennings 
635b700e7f0SSeth Jennings static int klp_init_patch(struct klp_patch *patch)
636b700e7f0SSeth Jennings {
637b700e7f0SSeth Jennings 	struct klp_object *obj;
638b700e7f0SSeth Jennings 	int ret;
639b700e7f0SSeth Jennings 
640b700e7f0SSeth Jennings 	if (!patch->objs)
641b700e7f0SSeth Jennings 		return -EINVAL;
642b700e7f0SSeth Jennings 
643b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
644b700e7f0SSeth Jennings 
6450dade9f3SJosh Poimboeuf 	patch->enabled = false;
646b700e7f0SSeth Jennings 
647b700e7f0SSeth Jennings 	ret = kobject_init_and_add(&patch->kobj, &klp_ktype_patch,
648e0b561eeSJiri Kosina 				   klp_root_kobj, "%s", patch->mod->name);
649b700e7f0SSeth Jennings 	if (ret)
650b700e7f0SSeth Jennings 		goto unlock;
651b700e7f0SSeth Jennings 
6528cdd043aSJiri Slaby 	klp_for_each_object(patch, obj) {
653b700e7f0SSeth Jennings 		ret = klp_init_object(patch, obj);
654b700e7f0SSeth Jennings 		if (ret)
655b700e7f0SSeth Jennings 			goto free;
656b700e7f0SSeth Jennings 	}
657b700e7f0SSeth Jennings 
65899590ba5SJosh Poimboeuf 	list_add_tail(&patch->list, &klp_patches);
659b700e7f0SSeth Jennings 
660b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
661b700e7f0SSeth Jennings 
662b700e7f0SSeth Jennings 	return 0;
663b700e7f0SSeth Jennings 
664b700e7f0SSeth Jennings free:
665b700e7f0SSeth Jennings 	klp_free_objects_limited(patch, obj);
666b700e7f0SSeth Jennings 	kobject_put(&patch->kobj);
667b700e7f0SSeth Jennings unlock:
668b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
669b700e7f0SSeth Jennings 	return ret;
670b700e7f0SSeth Jennings }
671b700e7f0SSeth Jennings 
672b700e7f0SSeth Jennings /**
673b700e7f0SSeth Jennings  * klp_unregister_patch() - unregisters a patch
674b700e7f0SSeth Jennings  * @patch:	Disabled patch to be unregistered
675b700e7f0SSeth Jennings  *
676b700e7f0SSeth Jennings  * Frees the data structures and removes the sysfs interface.
677b700e7f0SSeth Jennings  *
678b700e7f0SSeth Jennings  * Return: 0 on success, otherwise error
679b700e7f0SSeth Jennings  */
680b700e7f0SSeth Jennings int klp_unregister_patch(struct klp_patch *patch)
681b700e7f0SSeth Jennings {
682b700e7f0SSeth Jennings 	int ret = 0;
683b700e7f0SSeth Jennings 
684b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
685b700e7f0SSeth Jennings 
686b700e7f0SSeth Jennings 	if (!klp_is_patch_registered(patch)) {
687b700e7f0SSeth Jennings 		ret = -EINVAL;
688b700e7f0SSeth Jennings 		goto out;
689b700e7f0SSeth Jennings 	}
690b700e7f0SSeth Jennings 
6910dade9f3SJosh Poimboeuf 	if (patch->enabled) {
692b700e7f0SSeth Jennings 		ret = -EBUSY;
693b700e7f0SSeth Jennings 		goto out;
694b700e7f0SSeth Jennings 	}
695b700e7f0SSeth Jennings 
696b700e7f0SSeth Jennings 	klp_free_patch(patch);
697b700e7f0SSeth Jennings 
698b700e7f0SSeth Jennings out:
699b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
700b700e7f0SSeth Jennings 	return ret;
701b700e7f0SSeth Jennings }
702b700e7f0SSeth Jennings EXPORT_SYMBOL_GPL(klp_unregister_patch);
703b700e7f0SSeth Jennings 
704b700e7f0SSeth Jennings /**
705b700e7f0SSeth Jennings  * klp_register_patch() - registers a patch
706b700e7f0SSeth Jennings  * @patch:	Patch to be registered
707b700e7f0SSeth Jennings  *
708b700e7f0SSeth Jennings  * Initializes the data structure associated with the patch and
709b700e7f0SSeth Jennings  * creates the sysfs interface.
710b700e7f0SSeth Jennings  *
711b700e7f0SSeth Jennings  * Return: 0 on success, otherwise error
712b700e7f0SSeth Jennings  */
713b700e7f0SSeth Jennings int klp_register_patch(struct klp_patch *patch)
714b700e7f0SSeth Jennings {
715b700e7f0SSeth Jennings 	int ret;
716b700e7f0SSeth Jennings 
717b700e7f0SSeth Jennings 	if (!patch || !patch->mod)
718b700e7f0SSeth Jennings 		return -EINVAL;
719b700e7f0SSeth Jennings 
720425595a7SJessica Yu 	if (!is_livepatch_module(patch->mod)) {
721425595a7SJessica Yu 		pr_err("module %s is not marked as a livepatch module",
722425595a7SJessica Yu 		       patch->mod->name);
723425595a7SJessica Yu 		return -EINVAL;
724425595a7SJessica Yu 	}
725425595a7SJessica Yu 
726b700e7f0SSeth Jennings 	if (!klp_initialized())
727b700e7f0SSeth Jennings 		return -ENODEV;
728b700e7f0SSeth Jennings 
729b700e7f0SSeth Jennings 	/*
730b700e7f0SSeth Jennings 	 * A reference is taken on the patch module to prevent it from being
731b700e7f0SSeth Jennings 	 * unloaded.  Right now, we don't allow patch modules to unload since
732b700e7f0SSeth Jennings 	 * there is currently no method to determine if a thread is still
733b700e7f0SSeth Jennings 	 * running in the patched code contained in the patch module once
734b700e7f0SSeth Jennings 	 * the ftrace registration is successful.
735b700e7f0SSeth Jennings 	 */
736b700e7f0SSeth Jennings 	if (!try_module_get(patch->mod))
737b700e7f0SSeth Jennings 		return -ENODEV;
738b700e7f0SSeth Jennings 
739b700e7f0SSeth Jennings 	ret = klp_init_patch(patch);
740b700e7f0SSeth Jennings 	if (ret)
741b700e7f0SSeth Jennings 		module_put(patch->mod);
742b700e7f0SSeth Jennings 
743b700e7f0SSeth Jennings 	return ret;
744b700e7f0SSeth Jennings }
745b700e7f0SSeth Jennings EXPORT_SYMBOL_GPL(klp_register_patch);
746b700e7f0SSeth Jennings 
7477e545d6eSJessica Yu int klp_module_coming(struct module *mod)
748b700e7f0SSeth Jennings {
74936e505c1SMinfei Huang 	int ret;
750b700e7f0SSeth Jennings 	struct klp_patch *patch;
751b700e7f0SSeth Jennings 	struct klp_object *obj;
752b700e7f0SSeth Jennings 
7537e545d6eSJessica Yu 	if (WARN_ON(mod->state != MODULE_STATE_COMING))
7547e545d6eSJessica Yu 		return -EINVAL;
755b700e7f0SSeth Jennings 
756b700e7f0SSeth Jennings 	mutex_lock(&klp_mutex);
7578cb2c2dcSPetr Mladek 	/*
7587e545d6eSJessica Yu 	 * Each module has to know that klp_module_coming()
7597e545d6eSJessica Yu 	 * has been called. We never know what module will
7607e545d6eSJessica Yu 	 * get patched by a new patch.
7618cb2c2dcSPetr Mladek 	 */
7628cb2c2dcSPetr Mladek 	mod->klp_alive = true;
7638cb2c2dcSPetr Mladek 
764b700e7f0SSeth Jennings 	list_for_each_entry(patch, &klp_patches, list) {
7658cdd043aSJiri Slaby 		klp_for_each_object(patch, obj) {
766b700e7f0SSeth Jennings 			if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
767b700e7f0SSeth Jennings 				continue;
768b700e7f0SSeth Jennings 
769b700e7f0SSeth Jennings 			obj->mod = mod;
7707e545d6eSJessica Yu 
7717e545d6eSJessica Yu 			ret = klp_init_object_loaded(patch, obj);
77236e505c1SMinfei Huang 			if (ret) {
7737e545d6eSJessica Yu 				pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n",
7747e545d6eSJessica Yu 					patch->mod->name, obj->mod->name, ret);
7757e545d6eSJessica Yu 				goto err;
77636e505c1SMinfei Huang 			}
7777e545d6eSJessica Yu 
7780dade9f3SJosh Poimboeuf 			if (!patch->enabled)
7797e545d6eSJessica Yu 				break;
7807e545d6eSJessica Yu 
7817e545d6eSJessica Yu 			pr_notice("applying patch '%s' to loading module '%s'\n",
7827e545d6eSJessica Yu 				  patch->mod->name, obj->mod->name);
7837e545d6eSJessica Yu 
7840dade9f3SJosh Poimboeuf 			ret = klp_patch_object(obj);
7857e545d6eSJessica Yu 			if (ret) {
7867e545d6eSJessica Yu 				pr_warn("failed to apply patch '%s' to module '%s' (%d)\n",
7877e545d6eSJessica Yu 					patch->mod->name, obj->mod->name, ret);
7887e545d6eSJessica Yu 				goto err;
7897e545d6eSJessica Yu 			}
790b700e7f0SSeth Jennings 
791b700e7f0SSeth Jennings 			break;
792b700e7f0SSeth Jennings 		}
793b700e7f0SSeth Jennings 	}
794b700e7f0SSeth Jennings 
795b700e7f0SSeth Jennings 	mutex_unlock(&klp_mutex);
796b700e7f0SSeth Jennings 
797b700e7f0SSeth Jennings 	return 0;
7987e545d6eSJessica Yu 
7997e545d6eSJessica Yu err:
8007e545d6eSJessica Yu 	/*
8017e545d6eSJessica Yu 	 * If a patch is unsuccessfully applied, return
8027e545d6eSJessica Yu 	 * error to the module loader.
8037e545d6eSJessica Yu 	 */
8047e545d6eSJessica Yu 	pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n",
8057e545d6eSJessica Yu 		patch->mod->name, obj->mod->name, obj->mod->name);
8067e545d6eSJessica Yu 	mod->klp_alive = false;
8077e545d6eSJessica Yu 	klp_free_object_loaded(obj);
8087e545d6eSJessica Yu 	mutex_unlock(&klp_mutex);
8097e545d6eSJessica Yu 
8107e545d6eSJessica Yu 	return ret;
811b700e7f0SSeth Jennings }
812b700e7f0SSeth Jennings 
8137e545d6eSJessica Yu void klp_module_going(struct module *mod)
8147e545d6eSJessica Yu {
8157e545d6eSJessica Yu 	struct klp_patch *patch;
8167e545d6eSJessica Yu 	struct klp_object *obj;
8177e545d6eSJessica Yu 
8187e545d6eSJessica Yu 	if (WARN_ON(mod->state != MODULE_STATE_GOING &&
8197e545d6eSJessica Yu 		    mod->state != MODULE_STATE_COMING))
8207e545d6eSJessica Yu 		return;
8217e545d6eSJessica Yu 
8227e545d6eSJessica Yu 	mutex_lock(&klp_mutex);
8237e545d6eSJessica Yu 	/*
8247e545d6eSJessica Yu 	 * Each module has to know that klp_module_going()
8257e545d6eSJessica Yu 	 * has been called. We never know what module will
8267e545d6eSJessica Yu 	 * get patched by a new patch.
8277e545d6eSJessica Yu 	 */
8287e545d6eSJessica Yu 	mod->klp_alive = false;
8297e545d6eSJessica Yu 
8307e545d6eSJessica Yu 	list_for_each_entry(patch, &klp_patches, list) {
8317e545d6eSJessica Yu 		klp_for_each_object(patch, obj) {
8327e545d6eSJessica Yu 			if (!klp_is_module(obj) || strcmp(obj->name, mod->name))
8337e545d6eSJessica Yu 				continue;
8347e545d6eSJessica Yu 
8350dade9f3SJosh Poimboeuf 			if (patch->enabled) {
8367e545d6eSJessica Yu 				pr_notice("reverting patch '%s' on unloading module '%s'\n",
8377e545d6eSJessica Yu 					  patch->mod->name, obj->mod->name);
8380dade9f3SJosh Poimboeuf 				klp_unpatch_object(obj);
8397e545d6eSJessica Yu 			}
8407e545d6eSJessica Yu 
8417e545d6eSJessica Yu 			klp_free_object_loaded(obj);
8427e545d6eSJessica Yu 			break;
8437e545d6eSJessica Yu 		}
8447e545d6eSJessica Yu 	}
8457e545d6eSJessica Yu 
8467e545d6eSJessica Yu 	mutex_unlock(&klp_mutex);
8477e545d6eSJessica Yu }
848b700e7f0SSeth Jennings 
84926029d88SMinfei Huang static int __init klp_init(void)
850b700e7f0SSeth Jennings {
851b700e7f0SSeth Jennings 	int ret;
852b700e7f0SSeth Jennings 
853b9dfe0beSJiri Kosina 	ret = klp_check_compiler_support();
854b9dfe0beSJiri Kosina 	if (ret) {
855b9dfe0beSJiri Kosina 		pr_info("Your compiler is too old; turning off.\n");
856b9dfe0beSJiri Kosina 		return -EINVAL;
857b9dfe0beSJiri Kosina 	}
858b9dfe0beSJiri Kosina 
859b700e7f0SSeth Jennings 	klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
8607e545d6eSJessica Yu 	if (!klp_root_kobj)
8617e545d6eSJessica Yu 		return -ENOMEM;
862b700e7f0SSeth Jennings 
863b700e7f0SSeth Jennings 	return 0;
864b700e7f0SSeth Jennings }
865b700e7f0SSeth Jennings 
866b700e7f0SSeth Jennings module_init(klp_init);
867