Commit 861667dc authored by Ralf Baechle's avatar Ralf Baechle

MIPS: Fix race condition in module relocation code.

The relocation code was essentially taken from the 2.4 modutils which
perform relocation in userspace.  In 2.6 relocation of multiple modules
may be performed in parallel by the in-kernel loader so the global
variable mips_hi16_list won't fly anymore.  Fix race by moving it into
mod_arch_specific.

[ralf@linux-mips.org: folded in Tony's followup fix.  Thanks Tony!]
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
Signed-off-by: default avatarTony Wu <tung7970@gmail.com>
Cc:  linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/4189/
parent d3cac35c
...@@ -10,6 +10,7 @@ struct mod_arch_specific { ...@@ -10,6 +10,7 @@ struct mod_arch_specific {
struct list_head dbe_list; struct list_head dbe_list;
const struct exception_table_entry *dbe_start; const struct exception_table_entry *dbe_start;
const struct exception_table_entry *dbe_end; const struct exception_table_entry *dbe_end;
struct mips_hi16 *r_mips_hi16_list;
}; };
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */ typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
......
...@@ -39,8 +39,6 @@ struct mips_hi16 { ...@@ -39,8 +39,6 @@ struct mips_hi16 {
Elf_Addr value; Elf_Addr value;
}; };
static struct mips_hi16 *mips_hi16_list;
static LIST_HEAD(dbe_list); static LIST_HEAD(dbe_list);
static DEFINE_SPINLOCK(dbe_lock); static DEFINE_SPINLOCK(dbe_lock);
...@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v) ...@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
n->addr = (Elf_Addr *)location; n->addr = (Elf_Addr *)location;
n->value = v; n->value = v;
n->next = mips_hi16_list; n->next = me->arch.r_mips_hi16_list;
mips_hi16_list = n; me->arch.r_mips_hi16_list = n;
return 0; return 0;
} }
...@@ -151,9 +149,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) ...@@ -151,9 +149,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
/* Sign extend the addend we extract from the lo insn. */ /* Sign extend the addend we extract from the lo insn. */
vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
if (mips_hi16_list != NULL) { if (me->arch.r_mips_hi16_list != NULL) {
l = mips_hi16_list; l = me->arch.r_mips_hi16_list;
while (l != NULL) { while (l != NULL) {
unsigned long insn; unsigned long insn;
...@@ -187,7 +185,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v) ...@@ -187,7 +185,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
l = next; l = next;
} }
mips_hi16_list = NULL; me->arch.r_mips_hi16_list = NULL;
} }
/* /*
...@@ -278,6 +276,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab, ...@@ -278,6 +276,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
pr_debug("Applying relocate section %u to %u\n", relsec, pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info); sechdrs[relsec].sh_info);
me->arch.r_mips_hi16_list = NULL;
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
/* This is where to make the change */ /* This is where to make the change */
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment