]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
x86/module: Use text_poke() for late relocations
authorPeter Zijlstra <peterz@infradead.org>
Wed, 29 Apr 2020 15:24:49 +0000 (10:24 -0500)
committerJiri Kosina <jkosina@suse.cz>
Thu, 7 May 2020 22:12:43 +0000 (00:12 +0200)
Because of late module patching, a livepatch module needs to be able to
apply some of its relocations well after it has been loaded.  Instead of
playing games with module_{dis,en}able_ro(), use existing text poking
mechanisms to apply relocations after module loading.

So far only x86, s390 and Power have HAVE_LIVEPATCH but only the first
two also have STRICT_MODULE_RWX.

This will allow removal of the last module_disable_ro() usage in
livepatch.  The ultimate goal is to completely disallow making
executable mappings writable.

[ jpoimboe: Split up patches.  Use mod state to determine whether
    memcpy() can be used.  Implement text_poke() for UML. ]

Cc: x86@kernel.org
Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <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>
arch/um/kernel/um_arch.c
arch/x86/kernel/module.c

index 0f40eccbd7590850d0dd4bb58e82b6900c9a844d..375ab720e4aa251cb388a36fcf4ee9559020a7d0 100644 (file)
@@ -362,3 +362,19 @@ void __init check_bugs(void)
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
 {
 }
+
+void *text_poke(void *addr, const void *opcode, size_t len)
+{
+       /*
+        * In UML, the only reference to this function is in
+        * apply_relocate_add(), which shouldn't ever actually call this
+        * because UML doesn't have live patching.
+        */
+       WARN_ON(1);
+
+       return memcpy(addr, opcode, len);
+}
+
+void text_poke_sync(void)
+{
+}
index d5c72cb877b31648b51d2f04a2fdd4a31005426c..7614f478fd7affcc88c8842901966e0c24f2d2e4 100644 (file)
@@ -126,11 +126,12 @@ int apply_relocate(Elf32_Shdr *sechdrs,
        return 0;
 }
 #else /*X86_64*/
-int apply_relocate_add(Elf64_Shdr *sechdrs,
+static int __apply_relocate_add(Elf64_Shdr *sechdrs,
                   const char *strtab,
                   unsigned int symindex,
                   unsigned int relsec,
-                  struct module *me)
+                  struct module *me,
+                  void *(*write)(void *dest, const void *src, size_t len))
 {
        unsigned int i;
        Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
@@ -162,19 +163,19 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                case R_X86_64_64:
                        if (*(u64 *)loc != 0)
                                goto invalid_relocation;
-                       *(u64 *)loc = val;
+                       write(loc, &val, 8);
                        break;
                case R_X86_64_32:
                        if (*(u32 *)loc != 0)
                                goto invalid_relocation;
-                       *(u32 *)loc = val;
+                       write(loc, &val, 4);
                        if (val != *(u32 *)loc)
                                goto overflow;
                        break;
                case R_X86_64_32S:
                        if (*(s32 *)loc != 0)
                                goto invalid_relocation;
-                       *(s32 *)loc = val;
+                       write(loc, &val, 4);
                        if ((s64)val != *(s32 *)loc)
                                goto overflow;
                        break;
@@ -183,7 +184,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        if (*(u32 *)loc != 0)
                                goto invalid_relocation;
                        val -= (u64)loc;
-                       *(u32 *)loc = val;
+                       write(loc, &val, 4);
 #if 0
                        if ((s64)val != *(s32 *)loc)
                                goto overflow;
@@ -193,7 +194,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                        if (*(u64 *)loc != 0)
                                goto invalid_relocation;
                        val -= (u64)loc;
-                       *(u64 *)loc = val;
+                       write(loc, &val, 8);
                        break;
                default:
                        pr_err("%s: Unknown rela relocation: %llu\n",
@@ -215,6 +216,29 @@ overflow:
               me->name);
        return -ENOEXEC;
 }
+
+int apply_relocate_add(Elf64_Shdr *sechdrs,
+                  const char *strtab,
+                  unsigned int symindex,
+                  unsigned int relsec,
+                  struct module *me)
+{
+       int ret;
+       bool early = me->state == MODULE_STATE_UNFORMED;
+       void *(*write)(void *, const void *, size_t) = memcpy;
+
+       if (!early)
+               write = text_poke;
+
+       ret = __apply_relocate_add(sechdrs, strtab, symindex, relsec, me,
+                                  write);
+
+       if (!early)
+               text_poke_sync();
+
+       return ret;
+}
+
 #endif
 
 int module_finalize(const Elf_Ehdr *hdr,