[llvm] r248357 - Android support for SafeStack.
Evgeniy Stepanov via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 18:03:52 PDT 2015
Author: eugenis
Date: Tue Sep 22 20:03:51 2015
New Revision: 248357
URL: http://llvm.org/viewvc/llvm-project?rev=248357&view=rev
Log:
Android support for SafeStack.
Add two new ways of accessing the unsafe stack pointer:
* At a fixed offset from the thread TLS base. This is very similar to
StackProtector cookies, but we plan to extend it to other backends
(ARM in particular) soon. Bionic-side implementation here:
https://android-review.googlesource.com/170988.
* Via a function call, as a fallback for platforms that provide
neither a fixed TLS slot, nor a reasonable TLS implementation (i.e.
not emutls).
Added:
llvm/trunk/test/Transforms/SafeStack/abi.ll
Modified:
llvm/trunk/include/llvm/Target/TargetLowering.h
llvm/trunk/include/llvm/Transforms/Instrumentation.h
llvm/trunk/lib/CodeGen/Passes.cpp
llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
llvm/trunk/lib/Target/X86/X86ISelLowering.h
llvm/trunk/lib/Target/X86/X86Subtarget.h
llvm/trunk/lib/Transforms/Instrumentation/SafeStack.cpp
Modified: llvm/trunk/include/llvm/Target/TargetLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetLowering.h?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Target/TargetLowering.h (original)
+++ llvm/trunk/include/llvm/Target/TargetLowering.h Tue Sep 22 20:03:51 2015
@@ -995,6 +995,14 @@ public:
return false;
}
+ /// Return true if the target stores SafeStack pointer at a fixed offset in
+ /// some non-standard address space, and populates the address space and
+ /// offset as appropriate.
+ virtual bool getSafeStackPointerLocation(unsigned & /*AddressSpace*/,
+ unsigned & /*Offset*/) const {
+ return false;
+ }
+
/// Returns true if a cast between SrcAS and DestAS is a noop.
virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const {
return false;
Modified: llvm/trunk/include/llvm/Transforms/Instrumentation.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Instrumentation.h?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Instrumentation.h (original)
+++ llvm/trunk/include/llvm/Transforms/Instrumentation.h Tue Sep 22 20:03:51 2015
@@ -34,6 +34,8 @@ inline void *getDFSanRetValTLSPtrForJIT(
namespace llvm {
+class TargetMachine;
+
/// Instrumentation passes often insert conditional checks into entry blocks.
/// Call this function before splitting the entry block to move instructions
/// that must remain in the entry block up before the split point. Static
@@ -143,7 +145,7 @@ FunctionPass *createBoundsCheckingPass()
/// \brief This pass splits the stack into a safe stack and an unsafe stack to
/// protect against stack-based overflow vulnerabilities.
-FunctionPass *createSafeStackPass();
+FunctionPass *createSafeStackPass(const TargetMachine *TM = nullptr);
} // End llvm namespace
Modified: llvm/trunk/lib/CodeGen/Passes.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/Passes.cpp?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/Passes.cpp (original)
+++ llvm/trunk/lib/CodeGen/Passes.cpp Tue Sep 22 20:03:51 2015
@@ -466,7 +466,7 @@ void TargetPassConfig::addISelPrepare()
// Add both the safe stack and the stack protection passes: each of them will
// only protect functions that have corresponding attributes.
- addPass(createSafeStackPass());
+ addPass(createSafeStackPass(TM));
addPass(createStackProtectorPass(TM));
if (PrintISelInput)
Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.cpp?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp Tue Sep 22 20:03:51 2015
@@ -2079,6 +2079,29 @@ bool X86TargetLowering::getStackCookieLo
return true;
}
+/// Android provides a fixed TLS slot for the SafeStack pointer.
+/// See the definition of TLS_SLOT_SAFESTACK in
+/// https://android.googlesource.com/platform/bionic/+/master/libc/private/bionic_tls.h
+bool X86TargetLowering::getSafeStackPointerLocation(unsigned &AddressSpace,
+ unsigned &Offset) const {
+ if (!Subtarget->isTargetAndroid())
+ return false;
+
+ if (Subtarget->is64Bit()) {
+ // %fs:0x48, unless we're using a Kernel code model, in which case it's %gs:
+ Offset = 0x48;
+ if (getTargetMachine().getCodeModel() == CodeModel::Kernel)
+ AddressSpace = 256;
+ else
+ AddressSpace = 257;
+ } else {
+ // %gs:0x24 on i386
+ Offset = 0x24;
+ AddressSpace = 256;
+ }
+ return true;
+}
+
bool X86TargetLowering::isNoopAddrSpaceCast(unsigned SrcAS,
unsigned DestAS) const {
assert(SrcAS != DestAS && "Expected different address spaces!");
Modified: llvm/trunk/lib/Target/X86/X86ISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86ISelLowering.h?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86ISelLowering.h (original)
+++ llvm/trunk/lib/Target/X86/X86ISelLowering.h Tue Sep 22 20:03:51 2015
@@ -891,6 +891,12 @@ namespace llvm {
bool getStackCookieLocation(unsigned &AddressSpace,
unsigned &Offset) const override;
+ /// Return true if the target stores SafeStack pointer at a fixed offset in
+ /// some non-standard address space, and populates the address space and
+ /// offset as appropriate.
+ bool getSafeStackPointerLocation(unsigned &AddressSpace,
+ unsigned &Offset) const override;
+
SDValue BuildFILD(SDValue Op, EVT SrcVT, SDValue Chain, SDValue StackSlot,
SelectionDAG &DAG) const;
Modified: llvm/trunk/lib/Target/X86/X86Subtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Subtarget.h?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86Subtarget.h (original)
+++ llvm/trunk/lib/Target/X86/X86Subtarget.h Tue Sep 22 20:03:51 2015
@@ -394,6 +394,9 @@ public:
bool isTargetMachO() const { return TargetTriple.isOSBinFormatMachO(); }
bool isTargetLinux() const { return TargetTriple.isOSLinux(); }
+ bool isTargetAndroid() const {
+ return TargetTriple.getEnvironment() == Triple::Android;
+ }
bool isTargetNaCl() const { return TargetTriple.isOSNaCl(); }
bool isTargetNaCl32() const { return isTargetNaCl() && !is64Bit(); }
bool isTargetNaCl64() const { return isTargetNaCl() && is64Bit(); }
Modified: llvm/trunk/lib/Transforms/Instrumentation/SafeStack.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/SafeStack.cpp?rev=248357&r1=248356&r2=248357&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/SafeStack.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/SafeStack.cpp Tue Sep 22 20:03:51 2015
@@ -19,6 +19,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/AliasAnalysis.h"
+#include "llvm/CodeGen/Passes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
@@ -36,6 +37,8 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Target/TargetLowering.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/ModuleUtils.h"
@@ -43,6 +46,9 @@ using namespace llvm;
#define DEBUG_TYPE "safestack"
+static const char *const kUnsafeStackPtrVar = "__safestack_unsafe_stack_ptr";
+static const char *const kUnsafeStackPtrAddrFn = "__safestack_pointer_address";
+
namespace llvm {
STATISTIC(NumFunctions, "Total number of functions");
@@ -157,6 +163,8 @@ bool IsSafeStackAlloca(const AllocaInst
/// (as determined statically), and the unsafe stack, which contains all
/// local variables that are accessed in unsafe ways.
class SafeStack : public FunctionPass {
+ const TargetMachine *TM;
+ const TargetLoweringBase *TLI;
const DataLayout *DL;
Type *StackPtrTy;
@@ -164,7 +172,7 @@ class SafeStack : public FunctionPass {
Type *Int32Ty;
Type *Int8Ty;
- Constant *UnsafeStackPtr = nullptr;
+ Value *UnsafeStackPtr = nullptr;
/// Unsafe stack alignment. Each stack frame must ensure that the stack is
/// aligned to this value. We need to re-align the unsafe stack if the
@@ -176,7 +184,7 @@ class SafeStack : public FunctionPass {
/// \brief Build a constant representing a pointer to the unsafe stack
/// pointer.
- Constant *getOrCreateUnsafeStackPtr(Module &M);
+ Value *getOrCreateUnsafeStackPtr(IRBuilder<> &IRB, Function &F);
/// \brief Find all static allocas, dynamic allocas, return instructions and
/// stack restore points (exception unwind blocks and setjmp calls) in the
@@ -192,7 +200,7 @@ class SafeStack : public FunctionPass {
///
/// \returns A pointer to the top of the unsafe stack after all unsafe static
/// allocas are allocated.
- Value *moveStaticAllocasToUnsafeStack(Function &F,
+ Value *moveStaticAllocasToUnsafeStack(IRBuilder<> &IRB, Function &F,
ArrayRef<AllocaInst *> StaticAllocas,
ArrayRef<ReturnInst *> Returns);
@@ -215,9 +223,11 @@ class SafeStack : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid.
- SafeStack() : FunctionPass(ID), DL(nullptr) {
+ SafeStack(const TargetMachine *TM)
+ : FunctionPass(ID), TM(TM), TLI(nullptr), DL(nullptr) {
initializeSafeStackPass(*PassRegistry::getPassRegistry());
}
+ SafeStack() : SafeStack(nullptr) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<AAResultsWrapperPass>();
@@ -237,35 +247,53 @@ public:
bool runOnFunction(Function &F) override;
}; // class SafeStack
-Constant *SafeStack::getOrCreateUnsafeStackPtr(Module &M) {
- // The unsafe stack pointer is stored in a global variable with a magic name.
- const char *kUnsafeStackPtrVar = "__safestack_unsafe_stack_ptr";
-
- auto UnsafeStackPtr =
- dyn_cast_or_null<GlobalVariable>(M.getNamedValue(kUnsafeStackPtrVar));
-
- if (!UnsafeStackPtr) {
- // The global variable is not defined yet, define it ourselves.
- // We use the initial-exec TLS model because we do not support the variable
- // living anywhere other than in the main executable.
- UnsafeStackPtr = new GlobalVariable(
- /*Module=*/M, /*Type=*/StackPtrTy,
- /*isConstant=*/false, /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Initializer=*/0, /*Name=*/kUnsafeStackPtrVar,
- /*InsertBefore=*/nullptr,
- /*ThreadLocalMode=*/GlobalValue::InitialExecTLSModel);
+Value *SafeStack::getOrCreateUnsafeStackPtr(IRBuilder<> &IRB, Function &F) {
+ Module &M = *F.getParent();
+ Triple TargetTriple(M.getTargetTriple());
+
+ unsigned Offset;
+ unsigned AddressSpace;
+ // Check if the target keeps the unsafe stack pointer at a fixed offset.
+ if (TLI->getSafeStackPointerLocation(Offset, AddressSpace)) {
+ Constant *OffsetVal =
+ ConstantInt::get(Type::getInt32Ty(F.getContext()), Offset);
+ return ConstantExpr::getIntToPtr(OffsetVal,
+ StackPtrTy->getPointerTo(AddressSpace));
+ }
+
+ // Android provides a libc function that returns the stack pointer address.
+ if (TargetTriple.getEnvironment() == llvm::Triple::Android) {
+ Value *Fn = M.getOrInsertFunction(kUnsafeStackPtrAddrFn,
+ StackPtrTy->getPointerTo(0), nullptr);
+ return IRB.CreateCall(Fn);
} else {
- // The variable exists, check its type and attributes.
- if (UnsafeStackPtr->getValueType() != StackPtrTy) {
- report_fatal_error(Twine(kUnsafeStackPtrVar) + " must have void* type");
- }
+ // Otherwise, declare a thread-local variable with a magic name.
+ auto UnsafeStackPtr =
+ dyn_cast_or_null<GlobalVariable>(M.getNamedValue(kUnsafeStackPtrVar));
+
+ if (!UnsafeStackPtr) {
+ // The global variable is not defined yet, define it ourselves.
+ // We use the initial-exec TLS model because we do not support the
+ // variable
+ // living anywhere other than in the main executable.
+ UnsafeStackPtr = new GlobalVariable(
+ /*Module=*/M, /*Type=*/StackPtrTy,
+ /*isConstant=*/false, /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Initializer=*/0, /*Name=*/kUnsafeStackPtrVar,
+ /*InsertBefore=*/nullptr,
+ /*ThreadLocalMode=*/GlobalValue::InitialExecTLSModel);
+ } else {
+ // The variable exists, check its type and attributes.
+ if (UnsafeStackPtr->getValueType() != StackPtrTy) {
+ report_fatal_error(Twine(kUnsafeStackPtrVar) + " must have void* type");
+ }
- if (!UnsafeStackPtr->isThreadLocal()) {
- report_fatal_error(Twine(kUnsafeStackPtrVar) + " must be thread-local");
+ if (!UnsafeStackPtr->isThreadLocal()) {
+ report_fatal_error(Twine(kUnsafeStackPtrVar) + " must be thread-local");
+ }
}
+ return UnsafeStackPtr;
}
-
- return UnsafeStackPtr;
}
void SafeStack::findInsts(Function &F,
@@ -349,13 +377,12 @@ SafeStack::createStackRestorePoints(Func
}
Value *
-SafeStack::moveStaticAllocasToUnsafeStack(Function &F,
+SafeStack::moveStaticAllocasToUnsafeStack(IRBuilder<> &IRB, Function &F,
ArrayRef<AllocaInst *> StaticAllocas,
ArrayRef<ReturnInst *> Returns) {
if (StaticAllocas.empty())
return nullptr;
- IRBuilder<> IRB(F.getEntryBlock().getFirstInsertionPt());
DIBuilder DIB(*F.getParent());
// We explicitly compute and set the unsafe stack layout for all unsafe
@@ -513,6 +540,8 @@ void SafeStack::moveDynamicAllocasToUnsa
bool SafeStack::runOnFunction(Function &F) {
auto AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
+ TLI = TM->getSubtargetImpl(F)->getTargetLowering();
+
DEBUG(dbgs() << "[SafeStack] Function: " << F.getName() << "\n");
if (!F.hasFnAttribute(Attribute::SafeStack)) {
@@ -572,11 +601,11 @@ bool SafeStack::runOnFunction(Function &
if (!StackRestorePoints.empty())
++NumUnsafeStackRestorePointsFunctions;
- if (!UnsafeStackPtr)
- UnsafeStackPtr = getOrCreateUnsafeStackPtr(*F.getParent());
+ IRBuilder<> IRB(F.begin()->getFirstInsertionPt());
+ UnsafeStackPtr = getOrCreateUnsafeStackPtr(IRB, F);
// The top of the unsafe stack after all unsafe static allocas are allocated.
- Value *StaticTop = moveStaticAllocasToUnsafeStack(F, StaticAllocas, Returns);
+ Value *StaticTop = moveStaticAllocasToUnsafeStack(IRB, F, StaticAllocas, Returns);
// Safe stack object that stores the current unsafe stack top. It is updated
// as unsafe dynamic (non-constant-sized) allocas are allocated and freed.
@@ -598,9 +627,11 @@ bool SafeStack::runOnFunction(Function &
} // end anonymous namespace
char SafeStack::ID = 0;
-INITIALIZE_PASS_BEGIN(SafeStack, "safe-stack",
- "Safe Stack instrumentation pass", false, false)
-INITIALIZE_PASS_END(SafeStack, "safe-stack", "Safe Stack instrumentation pass",
- false, false)
+INITIALIZE_TM_PASS_BEGIN(SafeStack, "safe-stack",
+ "Safe Stack instrumentation pass", false, false)
+INITIALIZE_TM_PASS_END(SafeStack, "safe-stack",
+ "Safe Stack instrumentation pass", false, false)
-FunctionPass *llvm::createSafeStackPass() { return new SafeStack(); }
+FunctionPass *llvm::createSafeStackPass(const llvm::TargetMachine *TM) {
+ return new SafeStack(TM);
+}
Added: llvm/trunk/test/Transforms/SafeStack/abi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SafeStack/abi.ll?rev=248357&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/SafeStack/abi.ll (added)
+++ llvm/trunk/test/Transforms/SafeStack/abi.ll Tue Sep 22 20:03:51 2015
@@ -0,0 +1,38 @@
+; RUN: opt -safe-stack -S -mtriple=i386-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=x86_64-pc-linux-gnu < %s -o - | FileCheck %s --check-prefix=TLS
+; RUN: opt -safe-stack -S -mtriple=i686-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS32
+; RUN: opt -safe-stack -S -mtriple=x86_64-linux-android < %s -o - | FileCheck %s --check-prefix=DIRECT-TLS64
+; RUN: opt -safe-stack -S -mtriple=arm-linux-android < %s -o - | FileCheck %s --check-prefix=CALL
+; RUN: opt -safe-stack -S -mtriple=aarch64-linux-android < %s -o - | FileCheck %s --check-prefix=CALL
+
+
+define void @foo() nounwind uwtable safestack {
+entry:
+; TLS: %[[USP:.*]] = load i8*, i8** @__safestack_unsafe_stack_ptr
+; TLS: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; TLS: store i8* %[[USST]], i8** @__safestack_unsafe_stack_ptr
+
+; DIRECT-TLS32: %[[USP:.*]] = load i8*, i8* addrspace(36)* inttoptr (i32 256 to i8* addrspace(36)*)
+; DIRECT-TLS32: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS32: store i8* %[[USST]], i8* addrspace(36)* inttoptr (i32 256 to i8* addrspace(36)*)
+
+; DIRECT-TLS64: %[[USP:.*]] = load i8*, i8* addrspace(72)* inttoptr (i32 257 to i8* addrspace(72)*)
+; DIRECT-TLS64: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; DIRECT-TLS64: store i8* %[[USST]], i8* addrspace(72)* inttoptr (i32 257 to i8* addrspace(72)*)
+
+; CALL: %[[SPA:.*]] = call i8** @__safestack_pointer_address()
+; CALL: %[[USP:.*]] = load i8*, i8** %[[SPA]]
+; CALL: %[[USST:.*]] = getelementptr i8, i8* %[[USP]], i32 -16
+; CALL: store i8* %[[USST]], i8** %[[SPA]]
+
+ %a = alloca i8, align 8
+ call void @Capture(i8* %a)
+
+; TLS: store i8* %[[USP]], i8** @__safestack_unsafe_stack_ptr
+; DIRECT-TLS32: store i8* %[[USP]], i8* addrspace(36)* inttoptr (i32 256 to i8* addrspace(36)*)
+; DIRECT-TLS64: store i8* %[[USP]], i8* addrspace(72)* inttoptr (i32 257 to i8* addrspace(72)*)
+; CALL: store i8* %[[USP]], i8** %[[SPA]]
+ ret void
+}
+
+declare void @Capture(i8*)
More information about the llvm-commits
mailing list