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