MIPS: Module: Deal with malformed HI16/LO16 relocation sequences.
authorRalf Baechle <ralf@linux-mips.org>
Mon, 13 Aug 2012 22:34:18 +0000 (00:34 +0200)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 17 Aug 2012 08:57:28 +0000 (10:57 +0200)
In case a series of R_MIPS_HI16 relocations was not followed by an
R_MIPS_LO16 relocation we were leaking the hi16 relocation chain.
Handle that error and return an error.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/module.c

index 8e1fb802c3e2e802f3e0f2780dbd3c7030f3d7c0..4f8c3cba8c0c45180cdabe08ac05aa43e652395f 100644 (file)
@@ -140,19 +140,30 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
        return 0;
 }
 
+static void free_relocation_chain(struct mips_hi16 *l)
+{
+       struct mips_hi16 *next;
+
+       while (l) {
+               next = l->next;
+               kfree(l);
+               l = next;
+       }
+}
+
 static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 {
        unsigned long insnlo = *location;
+       struct mips_hi16 *l;
        Elf_Addr val, vallo;
-       struct mips_hi16 *l, *next;
 
        /* Sign extend the addend we extract from the lo insn.  */
        vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
 
        if (me->arch.r_mips_hi16_list != NULL) {
-
                l = me->arch.r_mips_hi16_list;
                while (l != NULL) {
+                       struct mips_hi16 *next;
                        unsigned long insn;
 
                        /*
@@ -198,11 +209,8 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
        return 0;
 
 out_danger:
-       while (l) {
-               next = l->next;
-               kfree(l);
-               l = next;
-       }
+       free_relocation_chain(l);
+       me->arch.r_mips_hi16_list = NULL;
 
        pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
 
@@ -300,6 +308,19 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
                        return res;
        }
 
+       /*
+        * Normally the hi16 list should be deallocated at this point.  A
+        * malformed binary however could contain a series of R_MIPS_HI16
+        * relocations not followed by a R_MIPS_LO16 relocation.  In that
+        * case, free up the list and return an error.
+        */
+       if (me->arch.r_mips_hi16_list) {
+               free_relocation_chain(me->arch.r_mips_hi16_list);
+               me->arch.r_mips_hi16_list = NULL;
+
+               return -ENOEXEC;
+       }
+
        return 0;
 }