MIPS: Bail on unsupported module relocs
authorPaul Burton <paul.burton@imgtec.com>
Thu, 4 Feb 2016 13:05:02 +0000 (13:05 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Sun, 3 Apr 2016 10:32:10 +0000 (12:32 +0200)
When an unsupported reloc is encountered in a module, we currently
blindly branch to whatever would be at its entry in the reloc handler
function pointer arrays. This may be NULL, or if the unsupported reloc
has a type greater than that of the supported reloc with the highest
type then we'll dereference some value after the function pointer array
& branch to that. The result is at best a kernel oops.

Fix this by checking that the reloc type has an entry in the function
pointer array (ie. is less than the number of items in the array) and
that the handler is non-NULL, returning an error code to fail the module
load if no handler is found.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: James Hogan <james.hogan@imgtec.com>
Cc: Steven J. Hill <Steven.Hill@imgtec.com>
Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/12432/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/module-rela.c
arch/mips/kernel/module.c

index 2b70723071c322018dbb616a0b158bae4da85d0e..9083d63b765cf9532f3a7e42f892a3b90b50811a 100644 (file)
@@ -109,9 +109,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
                       struct module *me)
 {
        Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
+       int (*handler)(struct module *me, u32 *location, Elf_Addr v);
        Elf_Sym *sym;
        u32 *location;
-       unsigned int i;
+       unsigned int i, type;
        Elf_Addr v;
        int res;
 
@@ -134,9 +135,21 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
                        return -ENOENT;
                }
 
-               v = sym->st_value + rel[i].r_addend;
+               type = ELF_MIPS_R_TYPE(rel[i]);
+
+               if (type < ARRAY_SIZE(reloc_handlers_rela))
+                       handler = reloc_handlers_rela[type];
+               else
+                       handler = NULL;
 
-               res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
+               if (!handler) {
+                       pr_err("%s: Unknown relocation type %u\n",
+                              me->name, type);
+                       return -EINVAL;
+               }
+
+               v = sym->st_value + rel[i].r_addend;
+               res = handler(me, location, v);
                if (res)
                        return res;
        }
index 1833f5171ccda092a74f6ac6a902d30e397fc985..f9b2936d598def20f5f9be027a4b1e1a8af758c4 100644 (file)
@@ -197,9 +197,10 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
                   struct module *me)
 {
        Elf_Mips_Rel *rel = (void *) sechdrs[relsec].sh_addr;
+       int (*handler)(struct module *me, u32 *location, Elf_Addr v);
        Elf_Sym *sym;
        u32 *location;
-       unsigned int i;
+       unsigned int i, type;
        Elf_Addr v;
        int res;
 
@@ -223,9 +224,21 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
                        return -ENOENT;
                }
 
-               v = sym->st_value;
+               type = ELF_MIPS_R_TYPE(rel[i]);
+
+               if (type < ARRAY_SIZE(reloc_handlers_rel))
+                       handler = reloc_handlers_rel[type];
+               else
+                       handler = NULL;
 
-               res = reloc_handlers_rel[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
+               if (!handler) {
+                       pr_err("%s: Unknown relocation type %u\n",
+                              me->name, type);
+                       return -EINVAL;
+               }
+
+               v = sym->st_value;
+               res = handler(me, location, v);
                if (res)
                        return res;
        }