OLD | NEW |
(Empty) | |
| 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 } |
OLD | NEW |