Merge remote-tracking branch 'livepatching/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 03:24:55 +0000 (13:24 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 03:24:55 +0000 (13:24 +1000)
Documentation/livepatch/module-elf-format.txt
arch/x86/kernel/Makefile
arch/x86/kernel/livepatch.c [new file with mode: 0644]
include/linux/livepatch.h
kernel/livepatch/core.c
kernel/module.c

index eedbdcf8ba50c0819fa3eedafebd783a1a5e50df..f21a5289a09c5142c77e801493f2227fe47327b2 100644 (file)
@@ -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.
 
index d3f49c3d5aca378747662b55bf0a8274c816f8cd..92fd50c77875ad0257685432e4c55f60b02db7aa 100644 (file)
@@ -81,6 +81,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
diff --git a/arch/x86/kernel/livepatch.c b/arch/x86/kernel/livepatch.c
new file mode 100644 (file)
index 0000000..e9d252d
--- /dev/null
@@ -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);
+       }
+}
index a93a0b23dc8ddd180ea3d1357bbf9869b111b7ab..9072f04db616ee2467333411fdd287a0fe6b3d84 100644 (file)
@@ -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);
index 8bbe50704621cb3e1b4e3b750f6e18a7674005f7..af4643873e7179c0e750d3d69a665844d06f4725 100644 (file)
@@ -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,
index 529efae9f481e6e071d084735bd54ad5e024b153..f57dd63186e63c647e4566c828b1258fbcdb8724 100644 (file)
@@ -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;
 
This page took 0.034393 seconds and 5 git commands to generate.