blob: a060b54eeb9b20a0fe2c5546c7455a0e1adf6d0d [file] [log] [blame]
// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "linux_shadow_stacks.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const int kMaxShadowIndex = 2048;
static const char kOverflowMessage[] = "Shadow stack overflow\n";
// Thread-local vars.
__thread
int shadow_index = -1;
__thread
void *shadow_ip_stack[kMaxShadowIndex];
__thread
void *shadow_sp_stack[kMaxShadowIndex];
enum Status {UNINITIALIZED = -1, DISABLED, ENABLED};
Status status = UNINITIALIZED;
void init() {
if (!getenv("KEEP_SHADOW_STACKS")) {
status = DISABLED;
return;
}
status = ENABLED;
}
void __cyg_profile_func_enter(void *this_fn, void *call_site) {
if (status == DISABLED) return;
if (status == UNINITIALIZED) {
init();
if (status == DISABLED) return;
}
shadow_index++;
if (shadow_index > kMaxShadowIndex) {
// Avoid memory allocation when reporting an error.
write(2, kOverflowMessage, sizeof(kOverflowMessage));
int a = 0;
a = a / a;
}
// Update the shadow IP stack
shadow_ip_stack[shadow_index] = this_fn;
// Update the shadow SP stack. The code for obtaining the frame address was
// borrowed from Google Perftools, http://code.google.com/p/google-perftools/
//
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
void **sp;
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
// It's always correct on llvm, and the techniques below aren't (in
// particular, llvm-gcc will make a copy of this_fn, so it's not in sp[2]),
// so we also prefer __builtin_frame_address when running under llvm.
sp = reinterpret_cast<void**>(__builtin_frame_address(0));
#elif defined(__i386__)
// Stack frame format:
// sp[0] pointer to previous frame
// sp[1] caller address
// sp[2] first argument
// ...
// NOTE: This will break under llvm, since result is a copy and not in sp[2]
sp = (void **)&this_fn - 2;
#elif defined(__x86_64__)
unsigned long rbp;
// Move the value of the register %rbp into the local variable rbp.
// We need 'volatile' to prevent this instruction from getting moved
// around during optimization to before function prologue is done.
// An alternative way to achieve this
// would be (before this __asm__ instruction) to call Noop() defined as
// static void Noop() __attribute__ ((noinline)); // prevent inlining
// static void Noop() { asm(""); } // prevent optimizing-away
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
// Arguments are passed in registers on x86-64, so we can't just
// offset from &result
sp = (void **) rbp;
#else
# error Cannot obtain SP (possibly compiling on a non x86 architecture)
#endif
shadow_sp_stack[shadow_index] = (void*)sp;
return;
}
void __cyg_profile_func_exit(void *this_fn, void *call_site) {
if (status == DISABLED) return;
shadow_index--;
}
void *get_shadow_ip_stack(int *index /*OUT*/) {
*index = shadow_index;
return shadow_ip_stack;
}
void *get_shadow_sp_stack(int *index /*OUT*/) {
*index = shadow_index;
return shadow_sp_stack;
}