aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/module.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2012-08-13 18:34:18 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-08-17 04:57:28 -0400
commitc54de490a2e4e74164f747925ff05c00dfa153cd (patch)
tree8a9a2d3717725661a0430966db5bd674db4d4dfb /arch/mips/kernel/module.c
parent861667dc82f561e65336ea67f73021b782b4ff74 (diff)
MIPS: Module: Deal with malformed HI16/LO16 relocation sequences.
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>
Diffstat (limited to 'arch/mips/kernel/module.c')
-rw-r--r--arch/mips/kernel/module.c35
1 files changed, 28 insertions, 7 deletions
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
index 8e1fb802c3e..4f8c3cba8c0 100644
--- a/arch/mips/kernel/module.c
+++ b/arch/mips/kernel/module.c
@@ -140,19 +140,30 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
140 return 0; 140 return 0;
141} 141}
142 142
143static void free_relocation_chain(struct mips_hi16 *l)
144{
145 struct mips_hi16 *next;
146
147 while (l) {
148 next = l->next;
149 kfree(l);
150 l = next;
151 }
152}
153
143static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) 154static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
144{ 155{
145 unsigned long insnlo = *location; 156 unsigned long insnlo = *location;
157 struct mips_hi16 *l;
146 Elf_Addr val, vallo; 158 Elf_Addr val, vallo;
147 struct mips_hi16 *l, *next;
148 159
149 /* Sign extend the addend we extract from the lo insn. */ 160 /* Sign extend the addend we extract from the lo insn. */
150 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; 161 vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
151 162
152 if (me->arch.r_mips_hi16_list != NULL) { 163 if (me->arch.r_mips_hi16_list != NULL) {
153
154 l = me->arch.r_mips_hi16_list; 164 l = me->arch.r_mips_hi16_list;
155 while (l != NULL) { 165 while (l != NULL) {
166 struct mips_hi16 *next;
156 unsigned long insn; 167 unsigned long insn;
157 168
158 /* 169 /*
@@ -198,11 +209,8 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
198 return 0; 209 return 0;
199 210
200out_danger: 211out_danger:
201 while (l) { 212 free_relocation_chain(l);
202 next = l->next; 213 me->arch.r_mips_hi16_list = NULL;
203 kfree(l);
204 l = next;
205 }
206 214
207 pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name); 215 pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
208 216
@@ -300,6 +308,19 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
300 return res; 308 return res;
301 } 309 }
302 310
311 /*
312 * Normally the hi16 list should be deallocated at this point. A
313 * malformed binary however could contain a series of R_MIPS_HI16
314 * relocations not followed by a R_MIPS_LO16 relocation. In that
315 * case, free up the list and return an error.
316 */
317 if (me->arch.r_mips_hi16_list) {
318 free_relocation_chain(me->arch.r_mips_hi16_list);
319 me->arch.r_mips_hi16_list = NULL;
320
321 return -ENOEXEC;
322 }
323
303 return 0; 324 return 0;
304} 325}
305 326