diff mbox

arm: module: handle negative R_ARM_PREL31 addends correctly

Message ID 1484907663-32322-1-git-send-email-ard.biesheuvel@linaro.org
State Superseded
Headers show

Commit Message

Ard Biesheuvel Jan. 20, 2017, 10:21 a.m. UTC
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>

---
This is something I spotted while looking into adding support for
R_ARM_REL32 relocations. Feel free to ignore if it is guaranteed in some
way that these relocations can never be emitted with negative addends.

 arch/arm/kernel/module.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Comments

Russell King (Oracle) Jan. 30, 2017, 12:39 p.m. UTC | #1
On Fri, Jan 20, 2017 at 10:21:03AM +0000, Ard Biesheuvel wrote:
> 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>

> ---

> This is something I spotted while looking into adding support for

> R_ARM_REL32 relocations. Feel free to ignore if it is guaranteed in some

> way that these relocations can never be emitted with negative addends.


I still think this is a good thing to have, even if we should never
see them - it avoids updating the relocation with an incorrect value.
Any relocations we perform should be guaranteed to be correct, or
we should fail.

Please put it in the patch system, thanks.

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Ard Biesheuvel Jan. 30, 2017, 3:08 p.m. UTC | #2
On 30 January 2017 at 12:39, Russell King - ARM Linux
<linux@armlinux.org.uk> wrote:
> On Fri, Jan 20, 2017 at 10:21:03AM +0000, Ard Biesheuvel wrote:

>> 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>

>> ---

>> This is something I spotted while looking into adding support for

>> R_ARM_REL32 relocations. Feel free to ignore if it is guaranteed in some

>> way that these relocations can never be emitted with negative addends.

>

> I still think this is a good thing to have, even if we should never

> see them - it avoids updating the relocation with an incorrect value.

> Any relocations we perform should be guaranteed to be correct, or

> we should fail.

>


Agreed.

> Please put it in the patch system, thanks.

>


Actually, I think it may still be incorrect: it seems to me that we
should preserve bit 31 rather than clear it. From the EHABI

"""
Bit 31 of the relocated word does not participate in the relocation
and may be used as data.
"""
(IHI0038B page 13)

and

"""
... The landing pad word contains a prel31 offset to a landing pad,
with bit 31 set if the catch handler catches a reference type and bit
31 clear otherwise. ...
"""
(IHI0038B page 39)

which suggests to me that bit 31 could legally assume either truth
value, and should not be touched by the relocation machinery.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox

Patch

diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 29629fe02ce5..20d8374711e2 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -155,7 +155,15 @@  apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
 		       break;
 
 		case R_ARM_PREL31:
-			offset = *(u32 *)loc + sym->st_value - loc;
+			offset = (*(s32 *)loc << 1) >> 1; /* sign extend */
+			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 = offset & 0x7fffffff;
 			break;