Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "linux_shadow_stacks.h"
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <unistd.h>
     11 
     12 static const int kMaxShadowIndex = 2048;
     13 static const char kOverflowMessage[] = "Shadow stack overflow\n";
     14 
     15 // Thread-local vars.
     16 __thread
     17 int shadow_index = -1;
     18 __thread
     19 void *shadow_ip_stack[kMaxShadowIndex];
     20 __thread
     21 void *shadow_sp_stack[kMaxShadowIndex];
     22 
     23 enum Status {UNINITIALIZED = -1, DISABLED, ENABLED};
     24 Status status = UNINITIALIZED;
     25 
     26 void init() {
     27   if (!getenv("KEEP_SHADOW_STACKS")) {
     28     status = DISABLED;
     29     return;
     30   }
     31   status = ENABLED;
     32 }
     33 
     34 void __cyg_profile_func_enter(void *this_fn, void *call_site) {
     35   if (status == DISABLED) return;
     36   if (status == UNINITIALIZED) {
     37     init();
     38     if (status == DISABLED) return;
     39   }
     40   shadow_index++;
     41   if (shadow_index > kMaxShadowIndex) {
     42     // Avoid memory allocation when reporting an error.
     43     write(2, kOverflowMessage, sizeof(kOverflowMessage));
     44     int a = 0;
     45     a = a / a;
     46   }
     47   // Update the shadow IP stack
     48   shadow_ip_stack[shadow_index] = this_fn;
     49   // Update the shadow SP stack. The code for obtaining the frame address was
     50   // borrowed from Google Perftools, http://code.google.com/p/google-perftools/
     51   //
     52   // Copyright (c) 2005, Google Inc.
     53   // All rights reserved.
     54   //
     55   // Redistribution and use in source and binary forms, with or without
     56   // modification, are permitted provided that the following conditions are
     57   // met:
     58   //
     59   //     * Redistributions of source code must retain the above copyright
     60   // notice, this list of conditions and the following disclaimer.
     61   //     * Redistributions in binary form must reproduce the above
     62   // copyright notice, this list of conditions and the following disclaimer
     63   // in the documentation and/or other materials provided with the
     64   // distribution.
     65   //     * Neither the name of Google Inc. nor the names of its
     66   // contributors may be used to endorse or promote products derived from
     67   // this software without specific prior written permission.
     68   //
     69   // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     70   // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     71   // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     72   // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     73   // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     74   // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     75   // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     76   // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     77   // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     78   // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     79   // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     80   void **sp;
     81 #if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
     82   // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
     83   // It's always correct on llvm, and the techniques below aren't (in
     84   // particular, llvm-gcc will make a copy of this_fn, so it's not in sp[2]),
     85   // so we also prefer __builtin_frame_address when running under llvm.
     86   sp = reinterpret_cast<void**>(__builtin_frame_address(0));
     87 #elif defined(__i386__)
     88   // Stack frame format:
     89   //    sp[0]   pointer to previous frame
     90   //    sp[1]   caller address
     91   //    sp[2]   first argument
     92   //    ...
     93   // NOTE: This will break under llvm, since result is a copy and not in sp[2]
     94   sp = (void **)&this_fn - 2;
     95 #elif defined(__x86_64__)
     96   unsigned long rbp;
     97   // Move the value of the register %rbp into the local variable rbp.
     98   // We need 'volatile' to prevent this instruction from getting moved
     99   // around during optimization to before function prologue is done.
    100   // An alternative way to achieve this
    101   // would be (before this __asm__ instruction) to call Noop() defined as
    102   //   static void Noop() __attribute__ ((noinline));  // prevent inlining
    103   //   static void Noop() { asm(""); }  // prevent optimizing-away
    104   __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
    105   // Arguments are passed in registers on x86-64, so we can't just
    106   // offset from &result
    107   sp = (void **) rbp;
    108 #else
    109 # error Cannot obtain SP (possibly compiling on a non x86 architecture)
    110 #endif
    111   shadow_sp_stack[shadow_index] = (void*)sp;
    112   return;
    113 }
    114 
    115 void __cyg_profile_func_exit(void *this_fn, void *call_site) {
    116   if (status == DISABLED) return;
    117   shadow_index--;
    118 }
    119 
    120 void *get_shadow_ip_stack(int *index /*OUT*/) {
    121   *index = shadow_index;
    122   return shadow_ip_stack;
    123 }
    124 
    125 void *get_shadow_sp_stack(int *index /*OUT*/) {
    126   *index = shadow_index;
    127   return shadow_sp_stack;
    128 }
    129