#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/ValueMap.h"
#include "llvm/Pass.h"
#include "llvm/Target/TargetLowering.h"
class PHINode;
class StackProtector : public FunctionPass {
+public:
+ /// SSPLayoutKind. Stack Smashing Protection (SSP) rules require that
+ /// vulnerable stack allocations are located close the stack protector.
+ enum SSPLayoutKind {
+ SSPLK_None, //< Did not trigger a stack protector. No effect on data
+ //< layout.
+ SSPLK_LargeArray, //< Array or nested array >= SSP-buffer-size. Closest
+ //< to the stack protector.
+ SSPLK_SmallArray, //< Array or nested array < SSP-buffer-size. 2nd closest
+ //< to the stack protector.
+ SSPLK_AddrOf //< The address of this allocation is exposed and
+ //< triggered protection. 3rd closest to the protector.
+ };
+
+ /// A mapping of AllocaInsts to their required SSP layout.
+ typedef ValueMap<const AllocaInst*, SSPLayoutKind> SSPLayoutMap;
+
+private:
const TargetMachine *TM;
/// TLI - Keep a pointer of a TargetLowering to consult for determining
DominatorTree *DT;
+ /// Layout - Mapping of allocations to the required SSPLayoutKind.
+ /// StackProtector analysis will update this map when determining if an
+ /// AllocaInst triggers a stack protector.
+ SSPLayoutMap Layout;
+
/// \brief The minimum size of buffers that will receive stack smashing
/// protection when -fstack-protection is used.
unsigned SSPBufferSize;
/// 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,
+ /// \param [out] IsLarge is set to true if a protectable array is found and
+ /// it is "large" ( >= ssp-buffer-size). In the case of a structure with
+ /// multiple arrays, this gets set if any of them is large.
+ bool ContainsProtectableArray(Type *Ty, bool &IsLarge, bool Strong = false,
bool InStruct = false) const;
/// \brief Check whether a stack allocation has its address taken.
AU.addPreserved<DominatorTree>();
}
+ SSPLayoutKind getSSPLayout(const AllocaInst *AI) const;
+
virtual bool runOnFunction(Function &Fn);
};
} // end namespace llvm
char StackProtector::ID = 0;
INITIALIZE_PASS(StackProtector, "stack-protector",
- "Insert stack protectors", false, false)
+ "Insert stack protectors", false, true)
FunctionPass *llvm::createStackProtectorPass(const TargetMachine *TM) {
return new StackProtector(TM);
}
+StackProtector::SSPLayoutKind StackProtector::getSSPLayout(const AllocaInst *AI)
+ const {
+ return AI ? Layout.lookup(AI) : SSPLK_None;
+}
+
bool StackProtector::runOnFunction(Function &Fn) {
F = &Fn;
M = F->getParent();
return InsertStackProtectors();
}
-/// 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 {
+/// \param [out] IsLarge is set to true if a protectable array is found and
+/// it is "large" ( >= ssp-buffer-size). In the case of a structure with
+/// multiple arrays, this gets set if any of them is large.
+bool StackProtector::ContainsProtectableArray(Type *Ty, bool &IsLarge,
+ 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;
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;
+ // However, in strong mode any array, regardless of type and size,
+ // triggers a protector.
+ if (!Strong && (InStruct || !Trip.isOSDarwin()))
+ return false;
}
// If an array has more than SSPBufferSize bytes of allocated space, then we
// emit stack protectors.
- if (SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT))
+ if (SSPBufferSize <= TLI->getDataLayout()->getTypeAllocSize(AT)) {
+ IsLarge = true;
+ return true;
+ }
+
+ if (Strong)
+ // Require a protector for all arrays in strong mode
return true;
}
const StructType *ST = dyn_cast<StructType>(Ty);
if (!ST) return false;
+ bool NeedsProtector = false;
for (StructType::element_iterator I = ST->element_begin(),
E = ST->element_end(); I != E; ++I)
- if (ContainsProtectableArray(*I, Strong, true))
- return true;
+ if (ContainsProtectableArray(*I, IsLarge, Strong, true)) {
+ // If the element is a protectable array and is large (>= SSPBufferSize)
+ // then we are done. If the protectable array is not large, then
+ // keep looking in case a subsequent element is a large array.
+ if (IsLarge)
+ return true;
+ NeedsProtector = true;
+ }
- return false;
+ return NeedsProtector;
}
bool StackProtector::HasAddressTaken(const Instruction *AI) {
/// address taken.
bool StackProtector::RequiresStackProtector() {
bool Strong = false;
+ bool NeedsProtector = false;
if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectReq))
- return true;
- else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
- Attribute::StackProtectStrong))
+ Attribute::StackProtectReq)) {
+ NeedsProtector = true;
+ Strong = true; // Use the same heuristic as strong to determine SSPLayout
+ } else if (F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
+ Attribute::StackProtectStrong))
Strong = true;
else if (!F->getAttributes().hasAttribute(AttributeSet::FunctionIndex,
Attribute::StackProtect))
if (const ConstantInt *CI =
dyn_cast<ConstantInt>(AI->getArraySize())) {
- if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize)
+ if (CI->getLimitedValue(SSPBufferSize) >= SSPBufferSize) {
// A call to alloca with size >= SSPBufferSize requires
// stack protectors.
- return true;
+ Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ NeedsProtector = true;
+ } else if (Strong) {
+ // Require protectors for all alloca calls in strong mode.
+ Layout.insert(std::make_pair(AI, SSPLK_SmallArray));
+ NeedsProtector = true;
+ }
} else {
// A call to alloca with a variable size requires protectors.
- return true;
+ Layout.insert(std::make_pair(AI, SSPLK_LargeArray));
+ NeedsProtector = true;
}
+ continue;
}
- if (ContainsProtectableArray(AI->getAllocatedType(), Strong))
- return true;
+ bool IsLarge = false;
+ if (ContainsProtectableArray(AI->getAllocatedType(), IsLarge, Strong)) {
+ Layout.insert(std::make_pair(AI, IsLarge ? SSPLK_LargeArray
+ : SSPLK_SmallArray));
+ NeedsProtector = true;
+ continue;
+ }
if (Strong && HasAddressTaken(AI)) {
++NumAddrTaken;
- return true;
+ Layout.insert(std::make_pair(AI, SSPLK_AddrOf));
+ NeedsProtector = true;
}
}
}
}
- return false;
+ return NeedsProtector;
}
static bool InstructionWillNotHaveChain(const Instruction *I) {