1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Module livepatch support |
4 | * |
5 | * Copyright (C) 2016 Jessica Yu <jeyu@redhat.com> |
6 | */ |
7 | |
8 | #include <linux/module.h> |
9 | #include <linux/string.h> |
10 | #include <linux/slab.h> |
11 | #include "internal.h" |
12 | |
13 | /* |
14 | * Persist ELF information about a module. Copy the ELF header, |
15 | * section header table, section string table, and symtab section |
16 | * index from info to mod->klp_info. |
17 | */ |
18 | int copy_module_elf(struct module *mod, struct load_info *info) |
19 | { |
20 | unsigned int size, symndx; |
21 | int ret; |
22 | |
23 | size = sizeof(*mod->klp_info); |
24 | mod->klp_info = kmalloc(size, GFP_KERNEL); |
25 | if (!mod->klp_info) |
26 | return -ENOMEM; |
27 | |
28 | /* ELF header */ |
29 | size = sizeof(mod->klp_info->hdr); |
30 | memcpy(&mod->klp_info->hdr, info->hdr, size); |
31 | |
32 | /* ELF section header table */ |
33 | size = sizeof(*info->sechdrs) * info->hdr->e_shnum; |
34 | mod->klp_info->sechdrs = kmemdup(p: info->sechdrs, size, GFP_KERNEL); |
35 | if (!mod->klp_info->sechdrs) { |
36 | ret = -ENOMEM; |
37 | goto free_info; |
38 | } |
39 | |
40 | /* ELF section name string table */ |
41 | size = info->sechdrs[info->hdr->e_shstrndx].sh_size; |
42 | mod->klp_info->secstrings = kmemdup(p: info->secstrings, size, GFP_KERNEL); |
43 | if (!mod->klp_info->secstrings) { |
44 | ret = -ENOMEM; |
45 | goto free_sechdrs; |
46 | } |
47 | |
48 | /* ELF symbol section index */ |
49 | symndx = info->index.sym; |
50 | mod->klp_info->symndx = symndx; |
51 | |
52 | /* |
53 | * For livepatch modules, core_kallsyms.symtab is a complete |
54 | * copy of the original symbol table. Adjust sh_addr to point |
55 | * to core_kallsyms.symtab since the copy of the symtab in module |
56 | * init memory is freed at the end of do_init_module(). |
57 | */ |
58 | mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab; |
59 | |
60 | return 0; |
61 | |
62 | free_sechdrs: |
63 | kfree(objp: mod->klp_info->sechdrs); |
64 | free_info: |
65 | kfree(objp: mod->klp_info); |
66 | return ret; |
67 | } |
68 | |
69 | void free_module_elf(struct module *mod) |
70 | { |
71 | kfree(objp: mod->klp_info->sechdrs); |
72 | kfree(objp: mod->klp_info->secstrings); |
73 | kfree(objp: mod->klp_info); |
74 | } |
75 | |