module: Move livepatch support to a separate file
No functional change. This patch migrates livepatch support (i.e. used during module add/or load and remove/or deletion) from core module code into kernel/module/livepatch.c. At the moment it contains code to persist Elf information about a given livepatch module, only. The new file was added to MAINTAINERS. Reviewed-by: Petr Mladek <pmladek@suse.com> Tested-by: Petr Mladek <pmladek@suse.com> Signed-off-by: Aaron Tomlin <atomlin@redhat.com> Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
This commit is contained in:
Родитель
5aff4dfdb4
Коммит
1be9473e31
|
@ -11360,6 +11360,7 @@ F: arch/s390/include/asm/livepatch.h
|
|||
F: arch/x86/include/asm/livepatch.h
|
||||
F: include/linux/livepatch.h
|
||||
F: kernel/livepatch/
|
||||
F: kernel/module/livepatch.c
|
||||
F: lib/livepatch/
|
||||
F: samples/livepatch/
|
||||
F: tools/testing/selftests/livepatch/
|
||||
|
|
|
@ -663,17 +663,14 @@ static inline bool module_requested_async_probing(struct module *module)
|
|||
return module && module->async_probe_requested;
|
||||
}
|
||||
|
||||
static inline bool is_livepatch_module(struct module *mod)
|
||||
{
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
static inline bool is_livepatch_module(struct module *mod)
|
||||
{
|
||||
return mod->klp;
|
||||
}
|
||||
#else /* !CONFIG_LIVEPATCH */
|
||||
static inline bool is_livepatch_module(struct module *mod)
|
||||
{
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
|
||||
bool is_module_sig_enforced(void);
|
||||
void set_module_sig_enforced(void);
|
||||
|
|
|
@ -10,3 +10,4 @@ KCOV_INSTRUMENT_module.o := n
|
|||
obj-y += main.o
|
||||
obj-$(CONFIG_MODULE_DECOMPRESS) += decompress.o
|
||||
obj-$(CONFIG_MODULE_SIG) += signing.o
|
||||
obj-$(CONFIG_LIVEPATCH) += livepatch.o
|
||||
|
|
|
@ -57,6 +57,28 @@ struct load_info {
|
|||
|
||||
int mod_verify_sig(const void *mod, struct load_info *info);
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
int copy_module_elf(struct module *mod, struct load_info *info);
|
||||
void free_module_elf(struct module *mod);
|
||||
#else /* !CONFIG_LIVEPATCH */
|
||||
static inline int copy_module_elf(struct module *mod, struct load_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void free_module_elf(struct module *mod) { }
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
|
||||
static inline bool set_livepatch_module(struct module *mod)
|
||||
{
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
mod->klp = true;
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULE_DECOMPRESS
|
||||
int module_decompress(struct load_info *info, const void *buf, size_t size);
|
||||
void module_decompress_cleanup(struct load_info *info);
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Module livepatch support
|
||||
*
|
||||
* Copyright (C) 2016 Jessica Yu <jeyu@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* Persist Elf information about a module. Copy the Elf header,
|
||||
* section header table, section string table, and symtab section
|
||||
* index from info to mod->klp_info.
|
||||
*/
|
||||
int copy_module_elf(struct module *mod, struct load_info *info)
|
||||
{
|
||||
unsigned int size, symndx;
|
||||
int ret;
|
||||
|
||||
size = sizeof(*mod->klp_info);
|
||||
mod->klp_info = kmalloc(size, GFP_KERNEL);
|
||||
if (!mod->klp_info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Elf header */
|
||||
size = sizeof(mod->klp_info->hdr);
|
||||
memcpy(&mod->klp_info->hdr, info->hdr, size);
|
||||
|
||||
/* Elf section header table */
|
||||
size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
|
||||
mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
|
||||
if (!mod->klp_info->sechdrs) {
|
||||
ret = -ENOMEM;
|
||||
goto free_info;
|
||||
}
|
||||
|
||||
/* Elf section name string table */
|
||||
size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
|
||||
mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
|
||||
if (!mod->klp_info->secstrings) {
|
||||
ret = -ENOMEM;
|
||||
goto free_sechdrs;
|
||||
}
|
||||
|
||||
/* Elf symbol section index */
|
||||
symndx = info->index.sym;
|
||||
mod->klp_info->symndx = symndx;
|
||||
|
||||
/*
|
||||
* For livepatch modules, core_kallsyms.symtab is a complete
|
||||
* copy of the original symbol table. Adjust sh_addr to point
|
||||
* to core_kallsyms.symtab since the copy of the symtab in module
|
||||
* init memory is freed at the end of do_init_module().
|
||||
*/
|
||||
mod->klp_info->sechdrs[symndx].sh_addr = (unsigned long)mod->core_kallsyms.symtab;
|
||||
|
||||
return 0;
|
||||
|
||||
free_sechdrs:
|
||||
kfree(mod->klp_info->sechdrs);
|
||||
free_info:
|
||||
kfree(mod->klp_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void free_module_elf(struct module *mod)
|
||||
{
|
||||
kfree(mod->klp_info->sechdrs);
|
||||
kfree(mod->klp_info->secstrings);
|
||||
kfree(mod->klp_info);
|
||||
}
|
|
@ -2043,81 +2043,6 @@ static int module_enforce_rwx_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
|||
}
|
||||
#endif /* CONFIG_STRICT_MODULE_RWX */
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
/*
|
||||
* Persist Elf information about a module. Copy the Elf header,
|
||||
* section header table, section string table, and symtab section
|
||||
* index from info to mod->klp_info.
|
||||
*/
|
||||
static int copy_module_elf(struct module *mod, struct load_info *info)
|
||||
{
|
||||
unsigned int size, symndx;
|
||||
int ret;
|
||||
|
||||
size = sizeof(*mod->klp_info);
|
||||
mod->klp_info = kmalloc(size, GFP_KERNEL);
|
||||
if (mod->klp_info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Elf header */
|
||||
size = sizeof(mod->klp_info->hdr);
|
||||
memcpy(&mod->klp_info->hdr, info->hdr, size);
|
||||
|
||||
/* Elf section header table */
|
||||
size = sizeof(*info->sechdrs) * info->hdr->e_shnum;
|
||||
mod->klp_info->sechdrs = kmemdup(info->sechdrs, size, GFP_KERNEL);
|
||||
if (mod->klp_info->sechdrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto free_info;
|
||||
}
|
||||
|
||||
/* Elf section name string table */
|
||||
size = info->sechdrs[info->hdr->e_shstrndx].sh_size;
|
||||
mod->klp_info->secstrings = kmemdup(info->secstrings, size, GFP_KERNEL);
|
||||
if (mod->klp_info->secstrings == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto free_sechdrs;
|
||||
}
|
||||
|
||||
/* Elf symbol section index */
|
||||
symndx = info->index.sym;
|
||||
mod->klp_info->symndx = symndx;
|
||||
|
||||
/*
|
||||
* For livepatch modules, core_kallsyms.symtab is a complete
|
||||
* copy of the original symbol table. Adjust sh_addr to point
|
||||
* to core_kallsyms.symtab since the copy of the symtab in module
|
||||
* init memory is freed at the end of do_init_module().
|
||||
*/
|
||||
mod->klp_info->sechdrs[symndx].sh_addr = \
|
||||
(unsigned long) mod->core_kallsyms.symtab;
|
||||
|
||||
return 0;
|
||||
|
||||
free_sechdrs:
|
||||
kfree(mod->klp_info->sechdrs);
|
||||
free_info:
|
||||
kfree(mod->klp_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void free_module_elf(struct module *mod)
|
||||
{
|
||||
kfree(mod->klp_info->sechdrs);
|
||||
kfree(mod->klp_info->secstrings);
|
||||
kfree(mod->klp_info);
|
||||
}
|
||||
#else /* !CONFIG_LIVEPATCH */
|
||||
static int copy_module_elf(struct module *mod, struct load_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_module_elf(struct module *mod)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
|
||||
void __weak module_memfree(void *module_region)
|
||||
{
|
||||
/*
|
||||
|
@ -3092,30 +3017,23 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
|
||||
{
|
||||
if (get_modinfo(info, "livepatch")) {
|
||||
mod->klp = true;
|
||||
if (!get_modinfo(info, "livepatch"))
|
||||
/* Nothing more to do */
|
||||
return 0;
|
||||
|
||||
if (set_livepatch_module(mod)) {
|
||||
add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
|
||||
pr_notice_once("%s: tainting kernel with TAINT_LIVEPATCH\n",
|
||||
mod->name);
|
||||
mod->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
|
||||
mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#else /* !CONFIG_LIVEPATCH */
|
||||
static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
|
||||
{
|
||||
if (get_modinfo(info, "livepatch")) {
|
||||
pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
|
||||
mod->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_LIVEPATCH */
|
||||
|
||||
static void check_modinfo_retpoline(struct module *mod, struct load_info *info)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче