#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
+#include "llvm/Attributes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
+#include "llvm/Intrinsics.h"
#include "llvm/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.
+// SSPBufferSize - The lower bound for a buffer to be considered for stack
+// smashing protection.
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."));
+ cl::desc("Lower bound for a buffer to be considered for "
+ "stack protection"));
namespace {
class VISIBILITY_HIDDEN StackProtector : public FunctionPass {
- /// Level - The level of stack protection.
- SSP::StackProtectorLevel Level;
-
/// 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;
-
Function *F;
Module *M;
- /// InsertStackProtectorPrologue - Insert code into the entry block that
- /// stores the __stack_chk_guard variable onto the stack.
- void InsertStackProtectorPrologue();
-
- /// 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();
+ /// 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();
/// RequiresStackProtector - Check whether or not this function needs a
/// stack protector based upon the stack protector level.
bool RequiresStackProtector() const;
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), TLI(0) {}
+ StackProtector(const TargetLowering *tli)
+ : FunctionPass(&ID), TLI(tli) {}
virtual bool runOnFunction(Function &Fn);
};
static RegisterPass<StackProtector>
X("stack-protector", "Insert stack protectors");
-FunctionPass *llvm::createStackProtectorPass(SSP::StackProtectorLevel lvl,
- const TargetLowering *tli) {
- return new StackProtector(lvl, tli);
+FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) {
+ return new StackProtector(tli);
}
bool StackProtector::runOnFunction(Function &Fn) {
if (!RequiresStackProtector()) return false;
- InsertStackProtectorPrologue();
- InsertStackProtectorEpilogue();
-
- // Cleanup.
- FailBB = 0;
- StackProtFrameSlot = 0;
- StackGuardVar = 0;
- return true;
+ 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();
+/// RequiresStackProtector - Check whether or not this function needs a stack
+/// protector based upon the stack protector level. The heuristic we use is to
+/// add a guard variable to functions that call alloca, and functions with
+/// buffers larger than SSPBufferSize bytes.
+bool StackProtector::RequiresStackProtector() const {
+ if (F->hasFnAttr(Attribute::StackProtectReq))
+ return true;
- const char *StackGuardStr = "__stack_chk_guard";
- StackGuardVar = M->getNamedGlobal(StackGuardStr);
+ if (!F->hasFnAttr(Attribute::StackProtect))
+ return false;
- if (!StackGuardVar)
- StackGuardVar = new GlobalVariable(PointerType::getUnqual(Type::Int8Ty),
- false, GlobalValue::ExternalLinkage,
- 0, StackGuardStr, M);
+ 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 (AI->isArrayAllocation())
+ // This is a call to alloca with a variable size. Emit stack
+ // protectors.
+ return true;
+
+ if (const ArrayType *AT = dyn_cast<ArrayType>(AI->getAllocatedType()))
+ // If an array has more than SSPBufferSize bytes of allocated space,
+ // then we emit stack protectors.
+ if (SSPBufferSize <= TD->getTypePaddedSize(AT))
+ 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);
+/// 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.
+ AllocaInst *AI = 0; // Place on stack that stores the stack guard.
+ Constant *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 = PointerType::getUnqual(Type::Int8Ty);
+ 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[0], array_endof(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");
+
+ // 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(CmpInst::ICMP_EQ, LI1, LI2, "", BB);
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;
+
+ return true;
}
/// 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;
+BasicBlock *StackProtector::CreateFailBB() {
+ BasicBlock *FailBB = BasicBlock::Create("CallStackCheckFailBlk", F);
Constant *StackChkFail =
M->getOrInsertFunction("__stack_chk_fail", Type::VoidTy, NULL);
CallInst::Create(StackChkFail, "", FailBB);
new UnreachableInst(FailBB);
-}
-
-/// 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)
- return true;
- }
- }
- }
-
- return false;
- }
- }
+ return FailBB;
}