Home | History | Annotate | Download | only in testsuite
      1 // relro_test.cc -- test -z relro for gold
      2 
      3 // Copyright (C) 2008-2016 Free Software Foundation, Inc.
      4 // Written by Ian Lance Taylor <iant (at) google.com>.
      5 
      6 // This file is part of gold.
      7 
      8 // This program is free software; you can redistribute it and/or modify
      9 // it under the terms of the GNU General Public License as published by
     10 // the Free Software Foundation; either version 3 of the License, or
     11 // (at your option) any later version.
     12 
     13 // This program is distributed in the hope that it will be useful,
     14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 // GNU General Public License for more details.
     17 
     18 // You should have received a copy of the GNU General Public License
     19 // along with this program; if not, write to the Free Software
     20 // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21 // MA 02110-1301, USA.
     22 
     23 #include <cassert>
     24 #include <csignal>
     25 #include <cstdio>
     26 #include <cstdlib>
     27 #include <exception>
     28 #include <stdint.h>
     29 #include <unistd.h>
     30 
     31 // This tests we were linked with a script.  If we were linked with a
     32 // script, relro currently does not work.
     33 
     34 extern char using_script[] __attribute__ ((weak));
     35 
     36 // This code is put into a shared library linked with -z relro.
     37 
     38 // i1 and i2 are not relro variables.
     39 int i1 = 1;
     40 static int i2 = 2;
     41 
     42 // P1 is a global relro variable.
     43 int* const p1 __attribute__ ((aligned(64))) = &i1;
     44 
     45 // P2 is a local relro variable.
     46 int* const p2 __attribute__ ((aligned(64))) = &i2;
     47 
     48 // Add a TLS variable to make sure -z relro works correctly with TLS.
     49 __thread int i3 = 1;
     50 
     51 // Test symbol addresses.
     52 
     53 bool
     54 t1()
     55 {
     56   if (using_script)
     57     return true;
     58 
     59   void* i1addr = static_cast<void*>(&i1);
     60   void* i2addr = static_cast<void*>(&i2);
     61   const void* p1addr = static_cast<const void*>(&p1);
     62   const void* p2addr = static_cast<const void*>(&p2);
     63 
     64   // The relro variables should precede the non-relro variables in the
     65   // memory image.
     66   assert(i1addr > p1addr);
     67   assert(i1addr > p2addr);
     68   assert(i2addr > p1addr);
     69   assert(i2addr > p2addr);
     70 
     71   // The relro variables should not be on the same page as the
     72   // non-relro variables.
     73   const size_t page_size = getpagesize();
     74   uintptr_t i1page = reinterpret_cast<uintptr_t>(i1addr) & ~ (page_size - 1);
     75   uintptr_t i2page = reinterpret_cast<uintptr_t>(i2addr) & ~ (page_size - 1);
     76   uintptr_t p1page = reinterpret_cast<uintptr_t>(p1addr) & ~ (page_size - 1);
     77   uintptr_t p2page = reinterpret_cast<uintptr_t>(p2addr) & ~ (page_size - 1);
     78   assert(i1page != p1page);
     79   assert(i1page != p2page);
     80   assert(i2page != p1page);
     81   assert(i2page != p2page);
     82   assert(i3 == 1);
     83 
     84   return true;
     85 }
     86 
     87 // Tell terminate handler that we are throwing from a signal handler.
     88 
     89 static bool throwing;
     90 
     91 // A signal handler for SIGSEGV.
     92 
     93 extern "C"
     94 void
     95 sigsegv_handler(int)
     96 {
     97   throwing = true;
     98   throw 0;
     99 }
    100 
    101 // The original terminate handler.
    102 
    103 std::terminate_handler orig_terminate;
    104 
    105 // Throwing an exception out of a signal handler doesn't always work
    106 // reliably.  When that happens the program will call terminate.  We
    107 // set a terminate handler to indicate that the test probably passed.
    108 
    109 void
    110 terminate_handler()
    111 {
    112   if (!throwing)
    113     {
    114       orig_terminate();
    115       ::exit(EXIT_FAILURE);
    116     }
    117   fprintf(stderr,
    118 	  "relro_test: terminate called due to failure to throw through signal handler\n");
    119   fprintf(stderr, "relro_test: assuming test succeeded\n");
    120   ::exit(EXIT_SUCCESS);
    121 }
    122 
    123 // Use a separate function to throw the exception, so that we don't
    124 // need to use -fnon-call-exceptions.
    125 
    126 void f2() __attribute__ ((noinline));
    127 void
    128 f2()
    129 {
    130   int** pp1 = const_cast<int**>(&p1);
    131   *pp1 = &i2;
    132 
    133   // We shouldn't get here--the assignment to *pp1 should write to
    134   // memory which the dynamic linker marked as read-only, giving us a
    135   // SIGSEGV, causing sigsegv_handler to be invoked, to throw past us.
    136   assert(0);
    137 }
    138 
    139 // Changing a relro variable should give us a SIGSEGV.
    140 
    141 bool
    142 t2()
    143 {
    144   if (using_script)
    145     return true;
    146 
    147   signal(SIGSEGV, sigsegv_handler);
    148   orig_terminate = std::set_terminate(terminate_handler);
    149 
    150   try
    151     {
    152       f2();
    153       return false;
    154     }
    155   catch (int i)
    156     {
    157       assert(i == 0);
    158       return true;
    159     }
    160 }
    161