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.2 Required name format
|
||||||
3.3.3 Example livepatch symbol names
|
3.3.3 Example livepatch symbol names
|
||||||
3.3.4 Example `readelf --symbols` output
|
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
|
0. Background and motivation
|
||||||
|
@ -46,7 +47,7 @@ architecture.
|
||||||
|
|
||||||
Since apply_relocate_add() requires access to a module's section header
|
Since apply_relocate_add() requires access to a module's section header
|
||||||
table, symbol table, and relocation section indices, Elf information is
|
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
|
relocation sections and symbols, which are described in this document. The
|
||||||
Elf constants used to mark livepatch symbols and relocation sections were
|
Elf constants used to mark livepatch symbols and relocation sections were
|
||||||
selected from OS-specific ranges according to the definitions from glibc.
|
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
|
sections, as in the case of the sample livepatch module (see
|
||||||
samples/livepatch).
|
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
|
livepatch relocation section can be applied simply by passing in the
|
||||||
appropriate section index to apply_relocate_add(), which then uses it to
|
appropriate section index to apply_relocate_add(), which then uses it to
|
||||||
access the relocation section and apply the relocations.
|
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).
|
[*] Note that the 'Ndx' (Section index) for these symbols is SHN_LIVEPATCH (0xff20).
|
||||||
"OS" means OS-specific.
|
"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.
|
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-y += apic/
|
||||||
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
|
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups_32.o
|
||||||
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
|
||||||
|
obj-$(CONFIG_LIVEPATCH) += livepatch.o
|
||||||
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
|
||||||
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
|
obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
|
||||||
obj-$(CONFIG_X86_TSC) += trace_clock.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_enable_patch(struct klp_patch *);
|
||||||
int klp_disable_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 */
|
/* Called from the module loader during module coming/going states */
|
||||||
int klp_module_coming(struct module *mod);
|
int klp_module_coming(struct module *mod);
|
||||||
void klp_module_going(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";
|
objname = klp_is_module(obj) ? obj->name : "vmlinux";
|
||||||
|
|
||||||
module_disable_ro(pmod);
|
|
||||||
/* For each klp relocation section */
|
/* For each klp relocation section */
|
||||||
for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
|
for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
|
||||||
sec = pmod->klp_info->sechdrs + i;
|
sec = pmod->klp_info->sechdrs + i;
|
||||||
|
@ -309,7 +308,6 @@ static int klp_write_object_relocations(struct module *pmod,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_enable_ro(pmod, true);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,9 +545,6 @@ static int __klp_enable_patch(struct klp_patch *patch)
|
||||||
list_prev_entry(patch, list)->state == KLP_DISABLED)
|
list_prev_entry(patch, list)->state == KLP_DISABLED)
|
||||||
return -EBUSY;
|
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);
|
pr_notice("enabling patch '%s'\n", patch->mod->name);
|
||||||
|
|
||||||
klp_for_each_object(patch, obj) {
|
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);
|
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 */
|
/* parts of the initialization that is done only when the object is loaded */
|
||||||
static int klp_init_object_loaded(struct klp_patch *patch,
|
static int klp_init_object_loaded(struct klp_patch *patch,
|
||||||
struct klp_object *obj)
|
struct klp_object *obj)
|
||||||
|
@ -770,9 +771,15 @@ static int klp_init_object_loaded(struct klp_patch *patch,
|
||||||
struct klp_func *func;
|
struct klp_func *func;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
module_disable_ro(patch->mod);
|
||||||
ret = klp_write_object_relocations(patch->mod, obj);
|
ret = klp_write_object_relocations(patch->mod, obj);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
module_enable_ro(patch->mod, true);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_klp_init_object_loaded(patch, obj);
|
||||||
|
module_enable_ro(patch->mod, true);
|
||||||
|
|
||||||
klp_for_each_func(obj, func) {
|
klp_for_each_func(obj, func) {
|
||||||
ret = klp_find_object_symbol(obj->name, func->old_name,
|
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';
|
buf[l++] = 'C';
|
||||||
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
|
if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
|
||||||
buf[l++] = 'E';
|
buf[l++] = 'E';
|
||||||
|
if (mod->taints & (1 << TAINT_LIVEPATCH))
|
||||||
|
buf[l++] = 'K';
|
||||||
/*
|
/*
|
||||||
* TAINT_FORCED_RMMOD: could be added.
|
* TAINT_FORCED_RMMOD: could be added.
|
||||||
* TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
|
* 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
|
#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;
|
return 0;
|
||||||
}
|
}
|
||||||
#else /* !CONFIG_LIVEPATCH */
|
#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")) {
|
if (get_modinfo(info, "livepatch")) {
|
||||||
pr_err("%s: module is marked as livepatch module, but livepatch support is disabled",
|
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);
|
"is unknown, you have been warned.\n", mod->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = find_livepatch_modinfo(mod, info);
|
err = check_modinfo_livepatch(mod, info);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue