#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Function.h"
-#include "llvm/Instructions.h"
-#include "llvm/Module.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/Dominators.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
-#include "llvm/ADT/APInt.h"
#include "llvm/Support/CommandLine.h"
-#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;
-// Enable stack protectors.
-static cl::opt<unsigned>
-SSPBufferSize("stack-protector-buffer-size", cl::init(8),
- cl::desc("The lower bound for a buffer to be considered for "
- "stack smashing protection."));
+STATISTIC(NumFunProtected, "Number of functions protected");
+STATISTIC(NumAddrTaken, "Number of local variables that have their address"
+ " taken.");
namespace {
- class VISIBILITY_HIDDEN StackProtector : public FunctionPass {
- /// Level - The level of stack protection.
- SSP::StackProtectorLevel Level;
+ class StackProtector : public FunctionPass {
+ const TargetMachine *TM;
/// TLI - Keep a pointer of a TargetLowering to consult for determining
/// target type sizes.
- const TargetLowering *TLI;
-
- /// FailBB - Holds the basic block to jump to when the stack protector check
- /// fails.
- BasicBlock *FailBB;
-
- /// StackProtFrameSlot - The place on the stack that the stack protector
- /// guard is kept.
- AllocaInst *StackProtFrameSlot;
-
- /// StackGuardVar - The global variable for the stack guard.
- GlobalVariable *StackGuardVar;
+ const TargetLoweringBase *TLI;
+ const Triple Trip;
Function *F;
Module *M;
- /// InsertStackProtectorPrologue - Insert code into the entry block that
- /// stores the __stack_chk_guard variable onto the stack.
- void InsertStackProtectorPrologue();
+ DominatorTree *DT;
- /// InsertStackProtectorEpilogue - Insert code before the return
- /// instructions checking the stack value that was stored in the
- /// prologue. If it isn't the same as the original value, then call a
- /// "failure" function.
- void InsertStackProtectorEpilogue();
+ /// VisitedPHIs - The set of PHI nodes visited when determining
+ /// if a variable's reference has been taken. This set
+ /// is maintained to ensure we don't visit the same PHI node multiple
+ /// times.
+ SmallPtrSet<const PHINode*, 16> VisitedPHIs;
+
+ /// InsertStackProtectors - Insert code into the prologue and epilogue of
+ /// the function.
+ ///
+ /// - The prologue code loads and stores the stack guard onto the stack.
+ /// - The epilogue checks the value stored in the prologue against the
+ /// original value. It calls __stack_chk_fail if they differ.
+ bool InsertStackProtectors();
/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
- void CreateFailBB();
+ BasicBlock *CreateFailBB();
+
+ /// ContainsProtectableArray - Check whether the type either is an array or
+ /// contains an array of sufficient size so that we need stack protectors
+ /// for it.
+ bool ContainsProtectableArray(Type *Ty, bool Strong = false,
+ bool InStruct = false) const;
+
+ /// \brief Check whether a stack allocation has its address taken.
+ bool HasAddressTaken(const Instruction *AI);
/// RequiresStackProtector - Check whether or not this function needs a
/// stack protector based upon the stack protector level.
- bool RequiresStackProtector() const;
+ bool RequiresStackProtector();
public:
static char ID; // Pass identification, replacement for typeid.
- StackProtector() : FunctionPass(&ID), Level(SSP::OFF), TLI(0), FailBB(0) {}
- StackProtector(SSP::StackProtectorLevel lvl, const TargetLowering *tli)
- : FunctionPass(&ID), Level(lvl), TLI(tli), FailBB(0) {}
+ StackProtector() : FunctionPass(ID), TM(0), TLI(0) {
+ initializeStackProtectorPass(*PassRegistry::getPassRegistry());
+ }
+ StackProtector(const TargetMachine *TM)
+ : FunctionPass(ID), TM(TM), TLI(0), Trip(TM->getTargetTriple()) {
+ initializeStackProtectorPass(*PassRegistry::getPassRegistry());
+ }
+
+ virtual void getAnalysisUsage(AnalysisUsage &AU) const {
+ AU.addPreserved<DominatorTree>();
+ }
virtual bool runOnFunction(Function &Fn);
};
} // end anonymous namespace
char StackProtector::ID = 0;
-static RegisterPass<StackProtector>
-X("stack-protector", "Insert stack protectors");
+INITIALIZE_PASS(StackProtector, "stack-protector",
+ "Insert stack protectors", false, false)
-FunctionPass *llvm::createStackProtectorPass(SSP::StackProtectorLevel lvl,
- const TargetLowering *tli) {
- return new StackProtector(lvl, tli);
+FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
+ return new StackProtector(TM);
}
bool StackProtector::runOnFunction(Function &Fn) {
F = &Fn;
M = F->getParent();
+ DT = getAnalysisIfAvailable<DominatorTree>();
+ TLI = TM->getTargetLowering();
if (!RequiresStackProtector()) return false;
-
- InsertStackProtectorPrologue();
- InsertStackProtectorEpilogue();
- // Cleanup.
- FailBB = 0;
- StackProtFrameSlot = 0;
- StackGuardVar = 0;
- return true;
+ ++NumFunProtected;
+ return InsertStackProtectors();
}
-/// InsertStackProtectorPrologue - Insert code into the entry block that stores
-/// the __stack_chk_guard variable onto the stack.
-void StackProtector::InsertStackProtectorPrologue() {
- BasicBlock &Entry = F->getEntryBlock();
- Instruction &InsertPt = Entry.front();
+/// ContainsProtectableArray - Check whether the type either is an array or
+/// contains a char array of sufficient size so that we need stack protectors
+/// for it.
+bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong,
+ bool InStruct) const {
+ if (!Ty) return false;
+ if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+ // In strong mode any array, regardless of type and size, triggers a
+ // protector
+ if (Strong)
+ return true;
+ const TargetMachine &TM = TLI->getTargetMachine();
+ if (!AT->getElementType()->isIntegerTy(8)) {
+ // If we're on a non-Darwin platform or we're inside of a structure, don't
+ // add stack protectors unless the array is a character array.
+ if (InStruct || !Trip.isOSDarwin())
+ return false;
+ }
+
+ // If an array has more than SSPBufferSize bytes of allocated space, then we
+ // emit stack protectors.
+ if (TM.Options.SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT))
+ return true;
+ }
- const char *StackGuardStr = "__stack_chk_guard";
- StackGuardVar = M->getNamedGlobal(StackGuardStr);
+ const StructType *ST = dyn_cast<StructType>(Ty);
+ if (!ST) return false;
- if (!StackGuardVar)
- StackGuardVar = new GlobalVariable(PointerType::getUnqual(Type::Int8Ty),
- false, GlobalValue::ExternalLinkage,
- 0, StackGuardStr, M);
+ for (StructType::element_iterator I = ST->element_begin(),
+ E = ST->element_end(); I != E; ++I)
+ if (ContainsProtectableArray(*I, Strong, true))
+ return true;
- StackProtFrameSlot = new AllocaInst(PointerType::getUnqual(Type::Int8Ty),
- "StackProt_Frame", &InsertPt);
- LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, &InsertPt);
- new StoreInst(LI, StackProtFrameSlot, false, &InsertPt);
+ return false;
}
-/// InsertStackProtectorEpilogue - Insert code before the return instructions
-/// checking the stack value that was stored in the prologue. If it isn't the
-/// same as the original value, then call a "failure" function.
-void StackProtector::InsertStackProtectorEpilogue() {
- // Create the basic block to jump to when the guard check fails.
- CreateFailBB();
-
- Function::iterator I = F->begin(), E = F->end();
- std::vector<BasicBlock*> ReturnBBs;
- ReturnBBs.reserve(F->size());
-
- for (; I != E; ++I)
- if (isa<ReturnInst>(I->getTerminator()))
- ReturnBBs.push_back(I);
-
- if (ReturnBBs.empty()) return; // Odd, but could happen. . .
-
- // Loop through the basic blocks that have return instructions. Convert this:
- //
- // return:
- // ...
- // ret ...
- //
- // into this:
- //
- // return:
- // ...
- // %1 = load __stack_chk_guard
- // %2 = load <stored stack guard>
- // %3 = cmp i1 %1, %2
- // br i1 %3, label %SPRet, label %CallStackCheckFailBlk
- //
- // SPRet:
- // ret ...
- //
- // CallStackCheckFailBlk:
- // call void @__stack_chk_fail()
- // unreachable
- //
- for (std::vector<BasicBlock*>::iterator
- II = ReturnBBs.begin(), IE = ReturnBBs.end(); II != IE; ++II) {
- BasicBlock *BB = *II;
- ReturnInst *RI = cast<ReturnInst>(BB->getTerminator());
- Function::iterator InsPt = BB; ++InsPt; // Insertion point for new BB.
-
- BasicBlock *NewBB = BasicBlock::Create("SPRet", F, InsPt);
-
- // Move the return instruction into the new basic block.
- RI->removeFromParent();
- NewBB->getInstList().insert(NewBB->begin(), RI);
-
- LoadInst *LI2 = new LoadInst(StackGuardVar, "", false, BB);
- LoadInst *LI1 = new LoadInst(StackProtFrameSlot, "", true, BB);
- ICmpInst *Cmp = new ICmpInst(CmpInst::ICMP_EQ, LI1, LI2, "", BB);
- BranchInst::Create(NewBB, FailBB, Cmp, BB);
+bool StackProtector::HasAddressTaken(const Instruction *AI) {
+ for (Value::const_use_iterator UI = AI->use_begin(), UE = AI->use_end();
+ UI != UE; ++UI) {
+ const User *U = *UI;
+ if (const StoreInst *SI = dyn_cast<StoreInst>(U)) {
+ if (AI == SI->getValueOperand())
+ return true;
+ } else if (const PtrToIntInst *SI = dyn_cast<PtrToIntInst>(U)) {
+ if (AI == SI->getOperand(0))
+ return true;
+ } else if (isa<CallInst>(U)) {
+ return true;
+ } else if (isa<InvokeInst>(U)) {
+ return true;
+ } else if (const SelectInst *SI = dyn_cast<SelectInst>(U)) {
+ if (HasAddressTaken(SI))
+ return true;
+ } else if (const PHINode *PN = dyn_cast<PHINode>(U)) {
+ // Keep track of what PHI nodes we have already visited to ensure
+ // they are only visited once.
+ if (VisitedPHIs.insert(PN))
+ if (HasAddressTaken(PN))
+ return true;
+ } else if (const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(U)) {
+ if (HasAddressTaken(GEP))
+ return true;
+ } else if (const BitCastInst *BI = dyn_cast<BitCastInst>(U)) {
+ if (HasAddressTaken(BI))
+ return true;
+ }
}
+ return false;
}
-/// CreateFailBB - Create a basic block to jump to when the stack protector
-/// check fails.
-void StackProtector::CreateFailBB() {
- assert(!FailBB && "Failure basic block already created?!");
- FailBB = BasicBlock::Create("CallStackCheckFailBlk", F);
- std::vector<const Type*> Params;
- Constant *StackChkFail =
- M->getOrInsertFunction("__stack_chk_fail", Type::VoidTy, NULL);
- CallInst::Create(StackChkFail, "", FailBB);
- new UnreachableInst(FailBB);
-}
+/// \brief Check whether or not this function needs a stack protector based
+/// upon the stack protector level.
+///
+/// We use two heuristics: a standard (ssp) and strong (sspstrong).
+/// The standard heuristic which will add a guard variable to functions that
+/// call alloca with a either a variable size or a size >= SSPBufferSize,
+/// functions with character buffers larger than SSPBufferSize, and functions
+/// with aggregates containing character buffers larger than SSPBufferSize. The
+/// strong heuristic will add a guard variables to functions that call alloca
+/// regardless of size, functions with any buffer regardless of type and size,
+/// functions with aggregates that contain any buffer regardless of type and
+/// size, and functions that contain stack-based variables that have had their
+/// address taken.
+bool StackProtector::RequiresStackProtector() {
+ bool Strong = false;
+ if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::StackProtectReq))
+ return true;
+ else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::StackProtectStrong))
+ Strong = true;
+ else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::StackProtect))
+ return false;
-/// RequiresStackProtector - Check whether or not this function needs a stack
-/// protector based upon the stack protector level.
-bool StackProtector::RequiresStackProtector() const {
- switch (Level) {
- default: return false;
- case SSP::ALL: return true;
- case SSP::SOME: {
- // If the size of the local variables allocated on the stack is greater than
- // SSPBufferSize, then we require a stack protector.
- uint64_t StackSize = 0;
- const TargetData *TD = TLI->getTargetData();
-
- for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
- BasicBlock *BB = I;
-
- for (BasicBlock::iterator
- II = BB->begin(), IE = BB->end(); II != IE; ++II)
- if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
- if (ConstantInt *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
- uint64_t Bytes = TD->getTypeSizeInBits(AI->getAllocatedType()) / 8;
- const APInt &Size = CI->getValue();
- StackSize += Bytes * Size.getZExtValue();
-
- if (SSPBufferSize <= StackSize)
+ for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
+ BasicBlock *BB = I;
+
+ for (BasicBlock::iterator
+ II = BB->begin(), IE = BB->end(); II != IE; ++II) {
+ if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
+ if (AI->isArrayAllocation()) {
+ // SSP-Strong: Enable protectors for any call to alloca, regardless
+ // of size.
+ if (Strong)
+ return true;
+
+ if (const ConstantInt *CI =
+ dyn_cast<ConstantInt>(AI->getArraySize())) {
+ unsigned BufferSize = TLI->getTargetMachine().Options.SSPBufferSize;
+ if (CI->getLimitedValue(BufferSize) >= BufferSize)
+ // A call to alloca with size >= SSPBufferSize requires
+ // stack protectors.
return true;
- }
+ } else // A call to alloca with a variable size requires protectors.
+ return true;
}
+
+ if (ContainsProtectableArray(AI->getAllocatedType(), Strong))
+ return true;
+
+ if (Strong && HasAddressTaken(AI)) {
+ ++NumAddrTaken;
+ return true;
+ }
+ }
}
+ }
- return false;
+ return false;
+}
+
+/// InsertStackProtectors - Insert code into the prologue and epilogue of the
+/// function.
+///
+/// - The prologue code loads and stores the stack guard onto the stack.
+/// - The epilogue checks the value stored in the prologue against the original
+/// value. It calls __stack_chk_fail if they differ.
+bool StackProtector::InsertStackProtectors() {
+ BasicBlock *FailBB = 0; // The basic block to jump to if check fails.
+ BasicBlock *FailBBDom = 0; // FailBB's dominator.
+ AllocaInst *AI = 0; // Place on stack that stores the stack guard.
+ Value *StackGuardVar = 0; // The stack guard variable.
+
+ for (Function::iterator I = F->begin(), E = F->end(); I != E; ) {
+ BasicBlock *BB = I++;
+ ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator());
+ if (!RI) continue;
+
+ if (!FailBB) {
+ // Insert code into the entry block that stores the __stack_chk_guard
+ // variable onto the stack:
+ //
+ // entry:
+ // StackGuardSlot = alloca i8*
+ // StackGuard = load __stack_chk_guard
+ // call void @llvm.stackprotect.create(StackGuard, StackGuardSlot)
+ //
+ PointerType *PtrTy = Type::getInt8PtrTy(RI->getContext());
+ unsigned AddressSpace, Offset;
+ if (TLI->getStackCookieLocation(AddressSpace, Offset)) {
+ Constant *OffsetVal =
+ ConstantInt::get(Type::getInt32Ty(RI->getContext()), Offset);
+
+ StackGuardVar = ConstantExpr::getIntToPtr(OffsetVal,
+ PointerType::get(PtrTy, AddressSpace));
+ } else if (Trip.getOS() == llvm::Triple::OpenBSD) {
+ StackGuardVar = M->getOrInsertGlobal("__guard_local", PtrTy);
+ cast<GlobalValue>(StackGuardVar)
+ ->setVisibility(GlobalValue::HiddenVisibility);
+ } else {
+ StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", PtrTy);
+ }
+
+ BasicBlock &Entry = F->getEntryBlock();
+ Instruction *InsPt = &Entry.front();
+
+ AI = new AllocaInst(PtrTy, "StackGuardSlot", InsPt);
+ LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsPt);
+
+ Value *Args[] = { LI, AI };
+ CallInst::
+ Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector),
+ Args, "", InsPt);
+
+ // Create the basic block to jump to when the guard check fails.
+ FailBB = CreateFailBB();
+ }
+
+ // For each block with a return instruction, convert this:
+ //
+ // return:
+ // ...
+ // ret ...
+ //
+ // into this:
+ //
+ // return:
+ // ...
+ // %1 = load __stack_chk_guard
+ // %2 = load StackGuardSlot
+ // %3 = cmp i1 %1, %2
+ // br i1 %3, label %SP_return, label %CallStackCheckFailBlk
+ //
+ // SP_return:
+ // ret ...
+ //
+ // CallStackCheckFailBlk:
+ // call void @__stack_chk_fail()
+ // unreachable
+
+ // Split the basic block before the return instruction.
+ BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");
+
+ if (DT && DT->isReachableFromEntry(BB)) {
+ DT->addNewBlock(NewBB, BB);
+ FailBBDom = FailBBDom ? DT->findNearestCommonDominator(FailBBDom, BB) :BB;
+ }
+
+ // Remove default branch instruction to the new BB.
+ BB->getTerminator()->eraseFromParent();
+
+ // Move the newly created basic block to the point right after the old basic
+ // block so that it's in the "fall through" position.
+ NewBB->moveAfter(BB);
+
+ // Generate the stack protector instructions in the old basic block.
+ LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
+ LoadInst *LI2 = new LoadInst(AI, "", true, BB);
+ ICmpInst *Cmp = new ICmpInst(*BB, CmpInst::ICMP_EQ, LI1, LI2, "");
+ BranchInst::Create(NewBB, FailBB, Cmp, BB);
}
+
+ // Return if we didn't modify any basic blocks. I.e., there are no return
+ // statements in the function.
+ if (!FailBB) return false;
+
+ if (DT && FailBBDom)
+ DT->addNewBlock(FailBB, FailBBDom);
+
+ return true;
+}
+
+/// CreateFailBB - Create a basic block to jump to when the stack protector
+/// check fails.
+BasicBlock *StackProtector::CreateFailBB() {
+ LLVMContext &Context = F->getContext();
+ BasicBlock *FailBB = BasicBlock::Create(Context, "CallStackCheckFailBlk", F);
+ if (Trip.getOS() == llvm::Triple::OpenBSD) {
+ Constant *StackChkFail = M->getOrInsertFunction(
+ "__stack_smash_handler", Type::getVoidTy(Context),
+ Type::getInt8PtrTy(Context), NULL);
+
+ Constant *NameStr = ConstantDataArray::getString(Context, F->getName());
+ Constant *FuncName =
+ new GlobalVariable(*M, NameStr->getType(), true,
+ GlobalVariable::PrivateLinkage, NameStr, "SSH");
+
+ SmallVector<Constant *, 2> IdxList;
+ IdxList.push_back(ConstantInt::get(Type::getInt8Ty(Context), 0));
+ IdxList.push_back(ConstantInt::get(Type::getInt8Ty(Context), 0));
+
+ SmallVector<Value *, 1> Args;
+ Args.push_back(ConstantExpr::getGetElementPtr(FuncName, IdxList));
+
+ CallInst::Create(StackChkFail, Args, "", FailBB);
+ } else {
+ Constant *StackChkFail = M->getOrInsertFunction(
+ "__stack_chk_fail", Type::getVoidTy(Context), NULL);
+ CallInst::Create(StackChkFail, "", FailBB);
}
+ new UnreachableInst(Context, FailBB);
+ return FailBB;
}