Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/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
  • Loading branch information
torvalds committed Oct 7, 2016
2 parents bc75450 + 2992ef2 commit ddc4e6d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 14 deletions.
20 changes: 16 additions & 4 deletions Documentation/livepatch/module-elf-format.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.

Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
65 changes: 65 additions & 0 deletions arch/x86/kernel/livepatch.c
Original file line number Diff line number Diff line change
@@ -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);
}
}
3 changes: 3 additions & 0 deletions include/linux/livepatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 13 additions & 6 deletions kernel/livepatch/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -309,7 +308,6 @@ static int klp_write_object_relocations(struct module *pmod,
break;
}

module_enable_ro(pmod, true);
return ret;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -763,16 +758,28 @@ 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)
{
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,
Expand Down
13 changes: 9 additions & 4 deletions kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit ddc4e6d

Please sign in to comment.