Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching updates from Jiri Kosina: - fix for patching modules that contain .altinstructions or .parainstructions sections, from Jessica Yu - make TAINT_LIVEPATCH a per-module flag (so that it's immediately clear which module caused the taint), from Josh Poimboeuf * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching: livepatch/module: make TAINT_LIVEPATCH module-specific Documentation: livepatch: add section about arch-specific code livepatch/x86: apply alternatives and paravirt patches after relocations livepatch: use arch_klp_init_object_loaded() to finish arch-specific tasks
This commit is contained in:
commit
ddc4e6d232
|
@ -25,7 +25,8 @@ Table of Contents
|
|||
3.3.2 Required name format
|
||||
3.3.3 Example livepatch symbol names
|
||||
3.3.4 Example `readelf --symbols` output
|
||||
4. Symbol table and Elf section access
|
||||
4. Architecture-specific sections
|
||||
5. Symbol table and Elf section access
|
||||
|
||||
----------------------------
|
||||
0. Background and motivation
|
||||
|
@ -46,7 +47,7 @@ architecture.
|
|||
|
||||
Since apply_relocate_add() requires access to a module's section header
|
||||
table, symbol table, and relocation section indices, Elf information is
|
||||
preserved for livepatch modules (see section 4). Livepatch manages its own
|
||||
preserved for livepatch modules (see section 5). Livepatch manages its own
|
||||
relocation sections and symbols, which are described in this document. The
|
||||
Elf constants used to mark livepatch symbols and relocation sections were
|
||||
selected from OS-specific ranges according to the definitions from glibc.
|
||||
|
@ -117,7 +118,7 @@ also possible for a livepatch module to have no livepatch relocation
|
|||
sections, as in the case of the sample livepatch module (see
|
||||
samples/livepatch).
|
||||
|
||||
Since Elf information is preserved for livepatch modules (see Section 4), a
|
||||
Since Elf information is preserved for livepatch modules (see Section 5), a
|
||||
livepatch relocation section can be applied simply by passing in the
|
||||
appropriate section index to apply_relocate_add(), which then uses it to
|
||||
access the relocation section and apply the relocations.
|
||||
|
@ -292,8 +293,19 @@ Symbol table '.symtab' contains 127 entries:
|
|||
[*] Note that the 'Ndx' (Section index) for these symbols is SHN_LIVEPATCH (0xff20).
|
||||
"OS" means OS-specific.
|
||||
|
||||
---------------------------------
|
||||
4. Architecture-specific sections
|
||||
---------------------------------
|
||||
Architectures may override arch_klp_init_object_loaded() to perform
|
||||
additional arch-specific tasks when a target module loads, such as applying
|
||||
arch-specific sections. On x86 for example, we must apply per-object
|
||||
.altinstructions and .parainstructions sections when a target module loads.
|
||||
These sections must be prefixed with ".klp.arch.$objname." so that they can
|
||||
be easily identified when iterating through a patch module's Elf sections
|
||||
(See arch/x86/kernel/livepatch.c for a complete example).
|
||||
|
||||
--------------------------------------
|
||||
4. Symbol table and Elf section access
|
||||
5. Symbol table and Elf section access
|
||||
--------------------------------------
|
||||
A livepatch module's symbol table is accessible through module->symtab.
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o
|
|||
obj-y += apic/
|
||||
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
|
||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||
obj-$(CONFIG_LIVEPATCH) += livepatch.o
|
||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
|
||||
obj-$(CONFIG_X86_TSC) += trace_clock.o
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* livepatch.c - x86-specific Kernel Live Patching Core
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/livepatch.h>
|
||||
#include <asm/text-patching.h>
|
||||
|
||||
/* Apply per-object alternatives. Based on x86 module_finalize() */
|
||||
void arch_klp_init_object_loaded(struct klp_patch *patch,
|
||||
struct klp_object *obj)
|
||||
{
|
||||
int cnt;
|
||||
struct klp_modinfo *info;
|
||||
Elf_Shdr *s, *alt = NULL, *para = NULL;
|
||||
void *aseg, *pseg;
|
||||
const char *objname;
|
||||
char sec_objname[MODULE_NAME_LEN];
|
||||
char secname[KSYM_NAME_LEN];
|
||||
|
||||
info = patch->mod->klp_info;
|
||||
objname = obj->name ? obj->name : "vmlinux";
|
||||
|
||||
/* See livepatch core code for BUILD_BUG_ON() explanation */
|
||||
BUILD_BUG_ON(MODULE_NAME_LEN < 56 || KSYM_NAME_LEN != 128);
|
||||
|
||||
for (s = info->sechdrs; s < info->sechdrs + info->hdr.e_shnum; s++) {
|
||||
/* Apply per-object .klp.arch sections */
|
||||
cnt = sscanf(info->secstrings + s->sh_name,
|
||||
".klp.arch.%55[^.].%127s",
|
||||
sec_objname, secname);
|
||||
if (cnt != 2)
|
||||
continue;
|
||||
if (strcmp(sec_objname, objname))
|
||||
continue;
|
||||
if (!strcmp(".altinstructions", secname))
|
||||
alt = s;
|
||||
if (!strcmp(".parainstructions", secname))
|
||||
para = s;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
aseg = (void *) alt->sh_addr;
|
||||
apply_alternatives(aseg, aseg + alt->sh_size);
|
||||
}
|
||||
|
||||
if (para) {
|
||||
pseg = (void *) para->sh_addr;
|
||||
apply_paravirt(pseg, pseg + para->sh_size);
|
||||
}
|
||||
}
|
|
@ -116,6 +116,9 @@ int klp_unregister_patch(struct klp_patch *);
|
|||
int klp_enable_patch(struct klp_patch *);
|
||||
int klp_disable_patch(struct klp_patch *);
|
||||
|
||||
void arch_klp_init_object_loaded(struct klp_patch *patch,
|
||||
struct klp_object *obj);
|
||||
|
||||
/* Called from the module loader during module coming/going states */
|
||||
int klp_module_coming(struct module *mod);
|
||||
void klp_module_going(struct module *mod);
|
||||
|
|
|
@ -274,7 +274,6 @@ static int klp_write_object_relocations(struct module *pmod,
|
|||
|
||||
objname = klp_is_module(obj) ? obj->name : "vmlinux";
|
||||
|
||||
module_disable_ro(pmod);
|
||||
/* For each klp relocation section */
|
||||
for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
|
||||
sec = pmod->klp_info->sechdrs + i;
|
||||
|
@ -309,7 +308,6 @@ static int klp_write_object_relocations(struct module *pmod,
|
|||
break;
|
||||
}
|
||||
|
||||
module_enable_ro(pmod, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -547,9 +545,6 @@ static int __klp_enable_patch(struct klp_patch *patch)
|
|||
list_prev_entry(patch, list)->state == KLP_DISABLED)
|
||||
return -EBUSY;
|
||||
|
||||
pr_notice_once("tainting kernel with TAINT_LIVEPATCH\n");
|
||||
add_taint(TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
|
||||
|
||||
pr_notice("enabling patch '%s'\n", patch->mod->name);
|
||||
|
||||
klp_for_each_object(patch, obj) {
|
||||
|
@ -763,6 +758,12 @@ static int klp_init_func(struct klp_object *obj, struct klp_func *func)
|
|||
func->old_sympos ? func->old_sympos : 1);
|
||||
}
|
||||
|
||||
/* Arches may override this to finish any remaining arch-specific tasks */
|
||||
void __weak arch_klp_init_object_loaded(struct klp_patch *patch,
|
||||
struct klp_object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
/* parts of the initialization that is done only when the object is loaded */
|
||||
static int klp_init_object_loaded(struct klp_patch *patch,
|
||||
struct klp_object *obj)
|
||||
|
@ -770,9 +771,15 @@ static int klp_init_object_loaded(struct klp_patch *patch,
|
|||
struct klp_func *func;
|
||||
int ret;
|
||||
|
||||
module_disable_ro(patch->mod);
|
||||
ret = klp_write_object_relocations(patch->mod, obj);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
module_enable_ro(patch->mod, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
arch_klp_init_object_loaded(patch, obj);
|
||||
module_enable_ro(patch->mod, true);
|
||||
|
||||
klp_for_each_func(obj, func) {
|
||||
ret = klp_find_object_symbol(obj->name, func->old_name,
|
||||
|
|
|
@ -1149,6 +1149,8 @@ static size_t module_flags_taint(struct module *mod, char *buf)
|
|||
buf[l++] = 'C';
|
||||
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
|
||||
buf[l++] = 'E';
|
||||
if (mod->taints & (1 << TAINT_LIVEPATCH))
|
||||
buf[l++] = 'K';
|
||||
/*
|
||||
* TAINT_FORCED_RMMOD: could be added.
|
||||
* TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
|
||||
|
@ -2792,14 +2794,17 @@ static int copy_chunked_from_user(void *dst, const void __user *usrc, unsigned l
|
|||
}
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
|
||||
static int check_modinfo_livepatch(struct module *mod, struct load_info *info)
|
||||
{
|
||||
mod->klp = get_modinfo(info, "livepatch") ? true : false;
|
||||
if (get_modinfo(info, "livepatch")) {
|
||||
mod->klp = true;
|
||||
add_taint_module(mod, TAINT_LIVEPATCH, LOCKDEP_STILL_OK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !CONFIG_LIVEPATCH */
|
||||
static int find_livepatch_modinfo(struct module *mod, struct load_info *info)
|
||||
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",
|
||||
|
@ -2969,7 +2974,7 @@ static int check_modinfo(struct module *mod, struct load_info *info, int flags)
|
|||
"is unknown, you have been warned.\n", mod->name);
|
||||
}
|
||||
|
||||
err = find_livepatch_modinfo(mod, info);
|
||||
err = check_modinfo_livepatch(mod, info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
Loading…
Reference in New Issue