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