11be9473eSAaron Tomlin // SPDX-License-Identifier: GPL-2.0-or-later
21be9473eSAaron Tomlin /*
31be9473eSAaron Tomlin * Module livepatch support
41be9473eSAaron Tomlin *
51be9473eSAaron Tomlin * Copyright (C) 2016 Jessica Yu <jeyu@redhat.com>
61be9473eSAaron Tomlin */
71be9473eSAaron Tomlin
81be9473eSAaron Tomlin #include <linux/module.h>
91be9473eSAaron Tomlin #include <linux/string.h>
101be9473eSAaron Tomlin #include <linux/slab.h>
111be9473eSAaron Tomlin #include "internal.h"
121be9473eSAaron Tomlin
131be9473eSAaron Tomlin /*
14*6486a57fSAlexey Dobriyan * Persist ELF information about a module. Copy the ELF header,
151be9473eSAaron Tomlin * section header table, section string table, and symtab section
161be9473eSAaron Tomlin * index from info to mod->klp_info.
171be9473eSAaron Tomlin */
copy_module_elf(struct module * mod,struct load_info * info)181be9473eSAaron Tomlin int copy_module_elf(struct module *mod, struct load_info *info)
191be9473eSAaron Tomlin {
201be9473eSAaron Tomlin unsigned int size, symndx;
211be9473eSAaron Tomlin int ret;
221be9473eSAaron Tomlin
231be9473eSAaron Tomlin size = sizeof(*mod->klp_info);
241be9473eSAaron Tomlin mod->klp_info = kmalloc(size, GFP_KERNEL);
251be9473eSAaron Tomlin if (!mod->klp_info)
261be9473eSAaron Tomlin return -ENOMEM;
271be9473eSAaron Tomlin
28*6486a57fSAlexey Dobriyan /* ELF header */
291be9473eSAaron Tomlin size = sizeof(mod->klp_info->hdr);
301be9473eSAaron Tomlin memcpy(&mod->klp_info->hdr, info->hdr, size);
311be9473eSAaron Tomlin
32*6486a57fSAlexey Dobriyan /* ELF section header table */
331be9473eSAaron Tomlin size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
341be9473eSAaron Tomlin mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
351be9473eSAaron Tomlin if (!mod->klp_info->sechdrs) {
361be9473eSAaron Tomlin ret = -ENOMEM;
371be9473eSAaron Tomlin goto free_info;
381be9473eSAaron Tomlin }
391be9473eSAaron Tomlin
40*6486a57fSAlexey Dobriyan /* ELF section name string table */
411be9473eSAaron Tomlin size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
421be9473eSAaron Tomlin mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
431be9473eSAaron Tomlin if (!mod->klp_info->secstrings) {
441be9473eSAaron Tomlin ret = -ENOMEM;
451be9473eSAaron Tomlin goto free_sechdrs;
461be9473eSAaron Tomlin }
471be9473eSAaron Tomlin
48*6486a57fSAlexey Dobriyan /* ELF symbol section index */
491be9473eSAaron Tomlin symndx = info->index.sym;
501be9473eSAaron Tomlin mod->klp_info->symndx = symndx;
511be9473eSAaron Tomlin
521be9473eSAaron Tomlin /*
531be9473eSAaron Tomlin * For livepatch modules, core_kallsyms.symtab is a complete
541be9473eSAaron Tomlin * copy of the original symbol table. Adjust sh_addr to point
551be9473eSAaron Tomlin * to core_kallsyms.symtab since the copy of the symtab in module
561be9473eSAaron Tomlin * init memory is freed at the end of do_init_module().
571be9473eSAaron Tomlin */
581be9473eSAaron Tomlin mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
591be9473eSAaron Tomlin
601be9473eSAaron Tomlin return 0;
611be9473eSAaron Tomlin
621be9473eSAaron Tomlin free_sechdrs:
631be9473eSAaron Tomlin kfree(mod->klp_info->sechdrs);
641be9473eSAaron Tomlin free_info:
651be9473eSAaron Tomlin kfree(mod->klp_info);
661be9473eSAaron Tomlin return ret;
671be9473eSAaron Tomlin }
681be9473eSAaron Tomlin
free_module_elf(struct module * mod)691be9473eSAaron Tomlin void free_module_elf(struct module *mod)
701be9473eSAaron Tomlin {
711be9473eSAaron Tomlin kfree(mod->klp_info->sechdrs);
721be9473eSAaron Tomlin kfree(mod->klp_info->secstrings);
731be9473eSAaron Tomlin kfree(mod->klp_info);
741be9473eSAaron Tomlin }
75