diff options
author | Zejun Wu <watashi@watashi.ws> | 2018-10-01 15:12:29 +0200 |
---|---|---|
committer | Krzysztof Gogolewski <krz.gogolewski@gmail.com> | 2018-10-01 15:12:29 +0200 |
commit | e44c992ff62ae8d55b297db9f721ee7a40357a76 (patch) | |
tree | 8a8fc3e4f9ca39911d94b67bb803ddabf52a5982 /rts/linker/Elf.c | |
parent | df67f95b2fc1c8b7200d98643e76c5feab4ed876 (diff) | |
download | haskell-e44c992ff62ae8d55b297db9f721ee7a40357a76.tar.gz |
Always check the relocation value for x86_64
Summary:
Always check that no overflow happens during relocation for x86_64.
It's not safe to assume the result returned by `ocAllocateSymbolExtras` is
always valid if we allocate it neither in lower 2G nor in a contiguous range
with the image.
There are also some minor fixes in this diff:
* `off >= 0x7fffffffL` should be `>`
* use of unaligned pointer is undefined behavior, use `memcpy` instead, gcc
will be able to optimize it to `mov %edx, (%rax)`.
Test Plan:
build ghci with:
```
DYNAMIC_GHC_PROGRAMS = NO
DYNAMIC_BY_DEFAULT = NO
```
and play with it.
./validate
Reviewers: simonmar, austin, bgamari, erikd
Reviewed By: simonmar
Subscribers: alpmestan, rwbarton, carter
Differential Revision: https://phabricator.haskell.org/D5168
Diffstat (limited to 'rts/linker/Elf.c')
-rw-r--r-- | rts/linker/Elf.c | 126 |
1 files changed, 79 insertions, 47 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c index f2fd88f750..fd24a92630 100644 --- a/rts/linker/Elf.c +++ b/rts/linker/Elf.c @@ -1576,8 +1576,11 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, break; case COMPAT_R_X86_64_64: - *(Elf64_Xword *)P = value; + { + Elf64_Xword payload = value; + memcpy((void*)P, &payload, sizeof(payload)); break; + } case COMPAT_R_X86_64_PC32: { @@ -1585,79 +1588,93 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, barf("R_X86_64_PC32 relocation, but ALWAYS_PIC."); #else StgInt64 off = value - P; - if (off >= 0x7fffffffL || off < -0x80000000L) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - off = pltAddress + A - P; - } else { - errorBelch("R_X86_64_PC32 relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, off, oc->fileName ); - return 0; - } + if (off != (Elf64_Sword)off && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + off = pltAddress + A - P; + } + if (off != (Elf64_Sword)off) { + errorBelch( + "R_X86_64_PC32 relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, off, oc->fileName); + return 0; } - *(Elf64_Word *)P = (Elf64_Word)off; + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } case COMPAT_R_X86_64_PC64: { - StgInt64 off = value - P; - *(Elf64_Word *)P = (Elf64_Word)off; + Elf64_Sxword payload = value - P; + memcpy((void*)P, &payload, sizeof(payload)); break; } case COMPAT_R_X86_64_32: + { #if defined(ALWAYS_PIC) barf("R_X86_64_32 relocation, but ALWAYS_PIC."); #else - if (value >= 0x7fffffffL) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - value = pltAddress + A; - } else { - errorBelch("R_X86_64_32 relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, value, oc->fileName ); - return 0; - } + if (value != (Elf64_Word)value && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; + } + if (value != (Elf64_Word)value) { + errorBelch( + "R_X86_64_32 relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, value, oc->fileName); + return 0; } - *(Elf64_Word *)P = (Elf64_Word)value; + Elf64_Word payload = value; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; + } case COMPAT_R_X86_64_32S: + { #if defined(ALWAYS_PIC) barf("R_X86_64_32S relocation, but ALWAYS_PIC."); #else - if ((StgInt64)value > 0x7fffffffL || (StgInt64)value < -0x80000000L) { - if (X86_64_ELF_NONPIC_HACK) { - StgInt64 pltAddress = - (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) - -> jumpIsland; - value = pltAddress + A; - } else { - errorBelch("R_X86_64_32S relocation out of range: %s = %" - PRId64 "d\nRecompile %s with -fPIC.", - symbol, value, oc->fileName ); - return 0; - } + if ((StgInt64)value != (Elf64_Sword)value && X86_64_ELF_NONPIC_HACK) { + StgInt64 pltAddress = + (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) + -> jumpIsland; + value = pltAddress + A; + } + if ((StgInt64)value != (Elf64_Sword)value) { + errorBelch( + "R_X86_64_32S relocation out of range: %s = %" PRIx64 + "\nRecompile %s with -fPIC -fexternal-dynamic-refs.", + symbol, value, oc->fileName); + return 0; } - *(Elf64_Sword *)P = (Elf64_Sword)value; + Elf64_Sword payload = value; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; + } case COMPAT_R_X86_64_REX_GOTPCRELX: case COMPAT_R_X86_64_GOTPCRELX: case COMPAT_R_X86_64_GOTPCREL: { StgInt64 gotAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S)->addr; StgInt64 off = gotAddress + A - P; - *(Elf64_Word *)P = (Elf64_Word)off; + if (off != (Elf64_Sword)off) { + barf( + "COMPAT_R_X86_64_GOTPCREL relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); break; } #if defined(dragonfly_HOST_OS) @@ -1674,7 +1691,15 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, /* make entry in GOT that contains said offset */ StgInt64 gotEntry = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), (S - (Elf64_Addr)(ti.base)))->addr; - *(Elf64_Word *)P = gotEntry + A - P; + StgInt64 off = gotEntry + A - P; + if (off != (Elf64_Sword)off) { + barf( + "COMPAT_R_X86_64_GOTTPOFF relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_SWord payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } @@ -1686,19 +1711,26 @@ do_Elf_Rela_relocations ( ObjectCode* oc, char* ehdrC, barf("R_X86_64_PLT32 relocation, but ALWAYS_PIC."); #else StgInt64 off = value - P; - if (off >= 0x7fffffffL || off < -0x80000000L) { + if (off != (Elf64_Sword)off) { StgInt64 pltAddress = (StgInt64) &makeSymbolExtra(oc, ELF_R_SYM(info), S) -> jumpIsland; off = pltAddress + A - P; } - *(Elf64_Word *)P = (Elf64_Word)off; + if (off != (Elf64_Sword)off) { + barf( + "R_X86_64_PLT32 relocation out of range: " + "%s = %" PRIx64 " in %s.", + symbol, off, oc->fileName); + } + Elf64_Sword payload = off; + memcpy((void*)P, &payload, sizeof(payload)); #endif break; } #endif default: - errorBelch("%s: unhandled ELF relocation(RelA) type %" FMT_Word "\n", + barf("%s: unhandled ELF relocation(RelA) type %" FMT_Word "\n", oc->fileName, (W_)ELF_R_TYPE(info)); return 0; } |