ARM: 8650/1: module: handle negative R_ARM_PREL31 addends correctly

According to the spec 'ELF for the ARM Architecture' (IHI 0044E),
addends for R_ARM_PREL31 relocations are 31-bit signed quantities,
so we need to sign extend the value to 32 bits before it can be used
as an offset in the calculation of the relocated value.

We have not been bitten by this because these relocations are usually
emitted against the start of a section, which means the addends never
assume negative values in practice. But it is a bug nonetheless, so fix
it.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
Ard Biesheuvel 2017-01-30 18:29:28 +01:00 committed by Russell King
parent ad475117d2
commit 050d18d1c6
1 changed files with 11 additions and 2 deletions

View File

@ -155,8 +155,17 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
break; break;
case R_ARM_PREL31: case R_ARM_PREL31:
offset = *(u32 *)loc + sym->st_value - loc; offset = (*(s32 *)loc << 1) >> 1; /* sign extend */
*(u32 *)loc = offset & 0x7fffffff; offset += sym->st_value - loc;
if (offset >= 0x40000000 || offset < -0x40000000) {
pr_err("%s: section %u reloc %u sym '%s': relocation %u out of range (%#lx -> %#x)\n",
module->name, relindex, i, symname,
ELF32_R_TYPE(rel->r_info), loc,
sym->st_value);
return -ENOEXEC;
}
*(u32 *)loc &= 0x80000000;
*(u32 *)loc |= offset & 0x7fffffff;
break; break;
case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_ABS_NC: