Add the heuristic to differentiate SSPStrong from SSPRequired.

The requirements of the strong heuristic are:

* A Protector is required for functions which contain an array, regardless of
  type or length.

* A Protector is required for functions which contain a structure/union which
  contains an array, regardless of type or length.  Note, there is no limit to
  the depth of nesting.

* A protector is required when the address of a local variable (i.e., stack
  based variable) is exposed. (E.g., such as through a local whose address is
  taken as part of the RHS of an assignment or a local whose address is taken as
  part of a function argument.)


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173231 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bill Wendling
2013-01-23 06:43:53 +00:00
parent 114baee1fa
commit e4957fb9b7
3 changed files with 2635 additions and 38 deletions

View File

@@ -825,7 +825,11 @@ example:
placed on the stack before the local variables that's checked upon placed on the stack before the local variables that's checked upon
return from the function to see if it has been overwritten. A return from the function to see if it has been overwritten. A
heuristic is used to determine if a function needs stack protectors heuristic is used to determine if a function needs stack protectors
or not. or not. The heuristic used will enable protectors for functions with:
- Character arrays larger than ``ssp-buffer-size`` (default 8).
- Aggregates containing character arrays larger than ``ssp-buffer-size``.
- Calls to alloca() with variable sizes or constant sizes greater than
``ssp-buffer-size``.
If a function that has an ``ssp`` attribute is inlined into a If a function that has an ``ssp`` attribute is inlined into a
function that doesn't have an ``ssp`` attribute, then the resulting function that doesn't have an ``ssp`` attribute, then the resulting
@@ -841,8 +845,15 @@ example:
an ``sspreq`` attribute. an ``sspreq`` attribute.
``sspstrong`` ``sspstrong``
This attribute indicates that the function should emit a stack smashing This attribute indicates that the function should emit a stack smashing
protector. Currently this attribute has the same effect as protector. This attribute causes a strong heuristic to be used when
``sspreq``. This overrides the ``ssp`` function attribute. determining if a function needs stack protectors. The strong heuristic
will enable protectors for functions with:
- Arrays of any size and type
- Aggregates containing an array of any size and type.
- Calls to alloca().
- Local variables that have had their address taken.
This overrides the ``ssp`` function attribute.
If a function that has an ``sspstrong`` attribute is inlined into a If a function that has an ``sspstrong`` attribute is inlined into a
function that doesn't have an ``sspstrong`` attribute, then the function that doesn't have an ``sspstrong`` attribute, then the

View File

@@ -16,6 +16,8 @@
#define DEBUG_TYPE "stack-protector" #define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/Passes.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h" #include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/Dominators.h"
#include "llvm/IR/Attributes.h" #include "llvm/IR/Attributes.h"
@@ -32,6 +34,10 @@
#include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetOptions.h"
using namespace llvm; using namespace llvm;
STATISTIC(NumFunProtected, "Number of functions protected");
STATISTIC(NumAddrTaken, "Number of local variables that have their address"
" taken.");
namespace { namespace {
class StackProtector : public FunctionPass { class StackProtector : public FunctionPass {
/// TLI - Keep a pointer of a TargetLowering to consult for determining /// TLI - Keep a pointer of a TargetLowering to consult for determining
@@ -43,6 +49,12 @@ namespace {
DominatorTree *DT; DominatorTree *DT;
/// 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 /// InsertStackProtectors - Insert code into the prologue and epilogue of
/// the function. /// the function.
/// ///
@@ -58,11 +70,15 @@ namespace {
/// ContainsProtectableArray - Check whether the type either is an array or /// ContainsProtectableArray - Check whether the type either is an array or
/// contains an array of sufficient size so that we need stack protectors /// contains an array of sufficient size so that we need stack protectors
/// for it. /// for it.
bool ContainsProtectableArray(Type *Ty, bool InStruct = false) const; 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 /// RequiresStackProtector - Check whether or not this function needs a
/// stack protector based upon the stack protector level. /// stack protector based upon the stack protector level.
bool RequiresStackProtector() const; bool RequiresStackProtector();
public: public:
static char ID; // Pass identification, replacement for typeid. static char ID; // Pass identification, replacement for typeid.
StackProtector() : FunctionPass(ID), TLI(0) { StackProtector() : FunctionPass(ID), TLI(0) {
@@ -96,15 +112,21 @@ bool StackProtector::runOnFunction(Function &Fn) {
if (!RequiresStackProtector()) return false; if (!RequiresStackProtector()) return false;
++NumFunProtected;
return InsertStackProtectors(); return InsertStackProtectors();
} }
/// ContainsProtectableArray - Check whether the type either is an array or /// ContainsProtectableArray - Check whether the type either is an array or
/// contains a char array of sufficient size so that we need stack protectors /// contains a char array of sufficient size so that we need stack protectors
/// for it. /// for it.
bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const { bool StackProtector::ContainsProtectableArray(Type *Ty, bool Strong,
bool InStruct) const {
if (!Ty) return false; if (!Ty) return false;
if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) { 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(); const TargetMachine &TM = TLI->getTargetMachine();
if (!AT->getElementType()->isIntegerTy(8)) { if (!AT->getElementType()->isIntegerTy(8)) {
Triple Trip(TM.getTargetTriple()); Triple Trip(TM.getTargetTriple());
@@ -126,28 +148,68 @@ bool StackProtector::ContainsProtectableArray(Type *Ty, bool InStruct) const {
for (StructType::element_iterator I = ST->element_begin(), for (StructType::element_iterator I = ST->element_begin(),
E = ST->element_end(); I != E; ++I) E = ST->element_end(); I != E; ++I)
if (ContainsProtectableArray(*I, true)) if (ContainsProtectableArray(*I, Strong, true))
return true; return true;
return false; return false;
} }
/// RequiresStackProtector - Check whether or not this function needs a stack bool StackProtector::HasAddressTaken(const Instruction *AI) {
/// protector based upon the stack protector level. The heuristic we use is to for (Value::const_use_iterator UI = AI->use_begin(), UE = AI->use_end();
/// add a guard variable to functions that call alloca, and functions with UI != UE; ++UI) {
/// buffers larger than SSPBufferSize bytes. const User *U = *UI;
bool StackProtector::RequiresStackProtector() const { 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;
}
/// \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, if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::StackProtectReq)) Attribute::StackProtectReq))
return true; return true;
else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
// FIXME: Dummy SSP-strong implementation. Default to required until
// strong heuristic is implemented.
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::StackProtectStrong)) Attribute::StackProtectStrong))
return true; Strong = true;
else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::StackProtect)) Attribute::StackProtect))
return false; return false;
@@ -155,15 +217,33 @@ bool StackProtector::RequiresStackProtector() const {
BasicBlock *BB = I; BasicBlock *BB = I;
for (BasicBlock::iterator for (BasicBlock::iterator
II = BB->begin(), IE = BB->end(); II != IE; ++II) II = BB->begin(), IE = BB->end(); II != IE; ++II) {
if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) { if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
if (AI->isArrayAllocation()) if (AI->isArrayAllocation()) {
// This is a call to alloca with a variable size. Emit stack // SSP-Strong: Enable protectors for any call to alloca, regardless
// protectors. // of size.
if (Strong)
return true; return true;
if (ContainsProtectableArray(AI->getAllocatedType())) 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; 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;
}
}
} }
} }

File diff suppressed because it is too large Load Diff