[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