| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * livepatch.c - x86-specific Kernel Live Patching Core |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/kallsyms.h> |
| #include <linux/livepatch.h> |
| #include <asm/text-patching.h> |
| |
| /* Apply per-object alternatives. Based on x86 module_finalize() */ |
| void arch_klp_init_object_loaded(struct klp_patch *patch, |
| struct klp_object *obj) |
| { |
| int cnt; |
| struct klp_modinfo *info; |
| Elf_Shdr *s, *alt = NULL, *para = NULL; |
| void *aseg, *pseg; |
| const char *objname; |
| char sec_objname[MODULE_NAME_LEN]; |
| char secname[KSYM_NAME_LEN]; |
| |
| info = patch->mod->klp_info; |
| objname = obj->name ? obj->name : "vmlinux"; |
| |
| /* See livepatch core code for BUILD_BUG_ON() explanation */ |
| BUILD_BUG_ON(MODULE_NAME_LEN < 56 || KSYM_NAME_LEN != 128); |
| |
| for (s = info->sechdrs; s < info->sechdrs + info->hdr.e_shnum; s++) { |
| /* Apply per-object .klp.arch sections */ |
| cnt = sscanf(info->secstrings + s->sh_name, |
| ".klp.arch.%55[^.].%127s", |
| sec_objname, secname); |
| if (cnt != 2) |
| continue; |
| if (strcmp(sec_objname, objname)) |
| continue; |
| if (!strcmp(".altinstructions", secname)) |
| alt = s; |
| if (!strcmp(".parainstructions", secname)) |
| para = s; |
| } |
| |
| if (alt) { |
| aseg = (void *) alt->sh_addr; |
| apply_alternatives(aseg, aseg + alt->sh_size); |
| } |
| |
| if (para) { |
| pseg = (void *) para->sh_addr; |
| apply_paravirt(pseg, pseg + para->sh_size); |
| } |
| } |