livepatch: Prevent module-specific KLP rela sections from referencing vmlinux symbols
authorJosh Poimboeuf <jpoimboe@redhat.com>
Wed, 29 Apr 2020 15:24:46 +0000 (10:24 -0500)
committerJiri Kosina <jkosina@suse.cz>
Thu, 7 May 2020 22:12:42 +0000 (00:12 +0200)
Prevent module-specific KLP rela sections from referencing vmlinux
symbols.  This helps prevent ordering issues with module special section
initializations.  Presumably such symbols are exported and normal relas
can be used instead.

Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
Acked-by: Miroslav Benes <mbenes@suse.cz>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
kernel/livepatch/core.c

index 16632e7..f9ebb54 100644 (file)
@@ -192,17 +192,20 @@ static int klp_find_object_symbol(const char *objname, const char *name,
 }
 
 static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab,
-                              unsigned int symndx, Elf_Shdr *relasec)
+                              unsigned int symndx, Elf_Shdr *relasec,
+                              const char *sec_objname)
 {
-       int i, cnt, vmlinux, ret;
-       char objname[MODULE_NAME_LEN];
-       char symname[KSYM_NAME_LEN];
+       int i, cnt, ret;
+       char sym_objname[MODULE_NAME_LEN];
+       char sym_name[KSYM_NAME_LEN];
        Elf_Rela *relas;
        Elf_Sym *sym;
        unsigned long sympos, addr;
+       bool sym_vmlinux;
+       bool sec_vmlinux = !strcmp(sec_objname, "vmlinux");
 
        /*
-        * Since the field widths for objname and symname in the sscanf()
+        * Since the field widths for sym_objname and sym_name in the sscanf()
         * call are hard-coded and correspond to MODULE_NAME_LEN and
         * KSYM_NAME_LEN respectively, we must make sure that MODULE_NAME_LEN
         * and KSYM_NAME_LEN have the values we expect them to have.
@@ -223,20 +226,33 @@ static int klp_resolve_symbols(Elf64_Shdr *sechdrs, const char *strtab,
                        return -EINVAL;
                }
 
-               /* Format: .klp.sym.objname.symname,sympos */
+               /* Format: .klp.sym.sym_objname.sym_name,sympos */
                cnt = sscanf(strtab + sym->st_name,
                             ".klp.sym.%55[^.].%127[^,],%lu",
-                            objname, symname, &sympos);
+                            sym_objname, sym_name, &sympos);
                if (cnt != 3) {
                        pr_err("symbol %s has an incorrectly formatted name\n",
                               strtab + sym->st_name);
                        return -EINVAL;
                }
 
+               sym_vmlinux = !strcmp(sym_objname, "vmlinux");
+
+               /*
+                * Prevent module-specific KLP rela sections from referencing
+                * vmlinux symbols.  This helps prevent ordering issues with
+                * module special section initializations.  Presumably such
+                * symbols are exported and normal relas can be used instead.
+                */
+               if (!sec_vmlinux && sym_vmlinux) {
+                       pr_err("invalid access to vmlinux symbol '%s' from module-specific livepatch relocation section",
+                              sym_name);
+                       return -EINVAL;
+               }
+
                /* klp_find_object_symbol() treats a NULL objname as vmlinux */
-               vmlinux = !strcmp(objname, "vmlinux");
-               ret = klp_find_object_symbol(vmlinux ? NULL : objname,
-                                            symname, sympos, &addr);
+               ret = klp_find_object_symbol(sym_vmlinux ? NULL : sym_objname,
+                                            sym_name, sympos, &addr);
                if (ret)
                        return ret;
 
@@ -294,7 +310,7 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
        if (strcmp(objname ? objname : "vmlinux", sec_objname))
                return 0;
 
-       ret = klp_resolve_symbols(sechdrs, strtab, symndx, sec);
+       ret = klp_resolve_symbols(sechdrs, strtab, symndx, sec, sec_objname);
        if (ret)
                return ret;