Commit | Line | Data |
---|---|---|
1be9473e AT |
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 | /* | |
6486a57f | 14 | * Persist ELF information about a module. Copy the ELF header, |
1be9473e AT |
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 | ||
6486a57f | 28 | /* ELF header */ |
1be9473e AT |
29 | size = sizeof(mod->klp_info->hdr); |
30 | memcpy(&mod->klp_info->hdr, info->hdr, size); | |
31 | ||
6486a57f | 32 | /* ELF section header table */ |
1be9473e AT |
33 | size = sizeof(*info->sechdrs) * info->hdr->e_shnum; |
34 | mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL); | |
35 | if (!mod->klp_info->sechdrs) { | |
36 | ret = -ENOMEM; | |
37 | goto free_info; | |
38 | } | |
39 | ||
6486a57f | 40 | /* ELF section name string table */ |
1be9473e AT |
41 | size = info->sechdrs[info->hdr->e_shstrndx].sh_size; |
42 | mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL); | |
43 | if (!mod->klp_info->secstrings) { | |
44 | ret = -ENOMEM; | |
45 | goto free_sechdrs; | |
46 | } | |
47 | ||
6486a57f | 48 | /* ELF symbol section index */ |
1be9473e AT |
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(mod->klp_info->sechdrs); | |
64 | free_info: | |
65 | kfree(mod->klp_info); | |
66 | return ret; | |
67 | } | |
68 | ||
69 | void free_module_elf(struct module *mod) | |
70 | { | |
71 | kfree(mod->klp_info->sechdrs); | |
72 | kfree(mod->klp_info->secstrings); | |
73 | kfree(mod->klp_info); | |
74 | } |