[commit: ghc] master: Always check the relocation value for x86_64 (e44c992)
git at git.haskell.org
git at git.haskell.org
Mon Oct 1 14:23:42 UTC 2018
Repository : ssh://git@git.haskell.org/ghc
On branch : master
Link : http://ghc.haskell.org/trac/ghc/changeset/e44c992ff62ae8d55b297db9f721ee7a40357a76/ghc
>---------------------------------------------------------------
commit e44c992ff62ae8d55b297db9f721ee7a40357a76
Author: Zejun Wu <watashi at watashi.ws>
Date: Mon Oct 1 15:12:29 2018 +0200
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
>---------------------------------------------------------------
e44c992ff62ae8d55b297db9f721ee7a40357a76
rts/linker/Elf.c | 126 ++++++++++++++++++++++++++++++++++---------------------
1 file changed, 79 insertions(+), 47 deletions(-)
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index f2fd88f..fd24a92 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;
}
More information about the ghc-commits
mailing list