linux_shadow_stacks.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 12static const int kMaxShadowIndex = 2048; 13static const char kOverflowMessage[] = "Shadow stack overflow\n"; 14 15// Thread-local vars. 16__thread 17int shadow_index = -1; 18__thread 19void *shadow_ip_stack[kMaxShadowIndex]; 20__thread 21void *shadow_sp_stack[kMaxShadowIndex]; 22 23enum Status {UNINITIALIZED = -1, DISABLED, ENABLED}; 24Status status = UNINITIALIZED; 25 26void init() { 27 if (!getenv("KEEP_SHADOW_STACKS")) { 28 status = DISABLED; 29 return; 30 } 31 status = ENABLED; 32} 33 34void __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 115void __cyg_profile_func_exit(void *this_fn, void *call_site) { 116 if (status == DISABLED) return; 117 shadow_index--; 118} 119 120void *get_shadow_ip_stack(int *index /*OUT*/) { 121 *index = shadow_index; 122 return shadow_ip_stack; 123} 124 125void *get_shadow_sp_stack(int *index /*OUT*/) { 126 *index = shadow_index; 127 return shadow_sp_stack; 128} 129