summaryrefslogtreecommitdiff
path: root/rts/linker/Elf.c
diff options
context:
space:
mode:
authorZejun Wu <watashi@watashi.ws>2018-10-01 15:12:29 +0200
committerKrzysztof Gogolewski <krz.gogolewski@gmail.com>2018-10-01 15:12:29 +0200
commite44c992ff62ae8d55b297db9f721ee7a40357a76 (patch)
tree8a8fc3e4f9ca39911d94b67bb803ddabf52a5982 /rts/linker/Elf.c
parentdf67f95b2fc1c8b7200d98643e76c5feab4ed876 (diff)
downloadhaskell-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.c126
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;
}