Index: include/llvm/LinkAllPasses.h =================================================================== --- include/llvm/LinkAllPasses.h +++ include/llvm/LinkAllPasses.h @@ -133,7 +133,7 @@ (void) llvm::createRegionPrinterPass(); (void) llvm::createRegionViewerPass(); (void) llvm::createSCCPPass(); - (void) llvm::createSafeStackPass(); + (void) llvm::createSafeStackPass(nullptr); (void) llvm::createScalarReplAggregatesPass(); (void) llvm::createSingleLoopExtractorPass(); (void) llvm::createStripSymbolsPass(); Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -995,6 +995,14 @@ 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; Index: include/llvm/Transforms/Instrumentation.h =================================================================== --- include/llvm/Transforms/Instrumentation.h +++ include/llvm/Transforms/Instrumentation.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/IR/BasicBlock.h" +#include "llvm/Target/TargetMachine.h" #include #if defined(__GNUC__) && defined(__linux__) && !defined(ANDROID) @@ -143,7 +144,7 @@ /// \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(TargetMachine *TM); } // End llvm namespace Index: lib/CodeGen/Passes.cpp =================================================================== --- lib/CodeGen/Passes.cpp +++ lib/CodeGen/Passes.cpp @@ -466,7 +466,7 @@ // 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) Index: lib/Target/X86/X86ISelLowering.h =================================================================== --- lib/Target/X86/X86ISelLowering.h +++ lib/Target/X86/X86ISelLowering.h @@ -897,6 +897,12 @@ 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; Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2060,6 +2060,26 @@ return true; } +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!"); Index: lib/Target/X86/X86Subtarget.h =================================================================== --- lib/Target/X86/X86Subtarget.h +++ lib/Target/X86/X86Subtarget.h @@ -394,6 +394,9 @@ 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(); } Index: lib/Transforms/Instrumentation/SafeStack.cpp =================================================================== --- lib/Transforms/Instrumentation/SafeStack.cpp +++ lib/Transforms/Instrumentation/SafeStack.cpp @@ -19,7 +19,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -37,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" @@ -44,6 +46,9 @@ #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"); @@ -158,6 +163,8 @@ /// (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; @@ -165,7 +172,7 @@ 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 @@ -177,7 +184,7 @@ /// \brief Build a constant representing a pointer to the unsafe stack /// pointer. - Constant *getOrCreateUnsafeStackPtr(Module &M); + Value *getOrCreateUnsafeStackPtr(Function &F); /// \brief Find all static allocas, dynamic allocas, return instructions and /// stack restore points (exception unwind blocks and setjmp calls) in the @@ -216,9 +223,11 @@ public: static char ID; // Pass identification, replacement for typeid. - SafeStack() : FunctionPass(ID), DL(nullptr) { + SafeStack(TargetMachine *TM) + : FunctionPass(ID), TM(TM), TLI(nullptr), DL(nullptr) { initializeSafeStackPass(*PassRegistry::getPassRegistry()); } + SafeStack() : SafeStack(nullptr) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); @@ -238,35 +247,54 @@ 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(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(Function &F) { + Module &M = *F.getParent(); + Triple TargetTriple(M.getTargetTriple()); + + unsigned Offset; + unsigned AddressSpace; + if (TLI->getSafeStackPointerLocation(Offset, AddressSpace)) { + Constant *OffsetVal = + ConstantInt::get(Type::getInt32Ty(F.getContext()), Offset); + return ConstantExpr::getIntToPtr(OffsetVal, + StackPtrTy->getPointerTo(AddressSpace)); + } + + if (TargetTriple.getEnvironment() == llvm::Triple::Android) { + Value *Fn = M.getOrInsertFunction(kUnsafeStackPtrAddrFn, + StackPtrTy->getPointerTo(0), nullptr); + IRBuilder<> IRB(F.begin()->getFirstInsertionPt()); + Value *V = IRB.CreateCall(Fn); + return V; } else { - // The variable exists, check its type and attributes. - if (UnsafeStackPtr->getValueType() != StackPtrTy) { - report_fatal_error(Twine(kUnsafeStackPtrVar) + " must have void* type"); - } + // The unsafe stack pointer is stored in a global variable with a magic + // name. + auto UnsafeStackPtr = + dyn_cast_or_null(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, @@ -356,7 +384,10 @@ if (StaticAllocas.empty()) return nullptr; - IRBuilder<> IRB(F.getEntryBlock().getFirstInsertionPt()); + IRBuilder<> IRB( + isa(UnsafeStackPtr) + ? cast(UnsafeStackPtr)->getNextNode() + : cast(F.getEntryBlock().getFirstInsertionPt())); DIBuilder DIB(*F.getParent()); // We explicitly compute and set the unsafe stack layout for all unsafe @@ -514,6 +545,8 @@ bool SafeStack::runOnFunction(Function &F) { auto AA = &getAnalysis().getAAResults(); + TLI = TM->getSubtargetImpl(F)->getTargetLowering(); + DEBUG(dbgs() << "[SafeStack] Function: " << F.getName() << "\n"); if (!F.hasFnAttribute(Attribute::SafeStack)) { @@ -573,8 +606,7 @@ if (!StackRestorePoints.empty()) ++NumUnsafeStackRestorePointsFunctions; - if (!UnsafeStackPtr) - UnsafeStackPtr = getOrCreateUnsafeStackPtr(*F.getParent()); + UnsafeStackPtr = getOrCreateUnsafeStackPtr(F); // The top of the unsafe stack after all unsafe static allocas are allocated. Value *StaticTop = moveStaticAllocasToUnsafeStack(F, StaticAllocas, Returns); @@ -599,10 +631,9 @@ } // end anonymous namespace char SafeStack::ID = 0; -INITIALIZE_PASS_BEGIN(SafeStack, "safe-stack", +INITIALIZE_TM_PASS_BEGIN(SafeStack, "safe-stack", "Safe Stack instrumentation pass", false, false) -INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) -INITIALIZE_PASS_END(SafeStack, "safe-stack", "Safe Stack instrumentation pass", +INITIALIZE_TM_PASS_END(SafeStack, "safe-stack", "Safe Stack instrumentation pass", false, false) -FunctionPass *llvm::createSafeStackPass() { return new SafeStack(); } +FunctionPass *llvm::createSafeStackPass(llvm::TargetMachine *TM) { return new SafeStack(TM); } Index: test/Transforms/SafeStack/abi.ll =================================================================== --- /dev/null +++ test/Transforms/SafeStack/abi.ll @@ -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*)