Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions aspis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ parse_commands() {

Hardening mechanism:
--eddi (Default) Enable EDDI.
--reddi Enable Recursive-EDDI.
--seddi Enable Selective-EDDI.
--fdsc Enable Full Duplication with Selective Checking.
--no-dup Completely disable data duplication.
Expand Down Expand Up @@ -201,6 +202,9 @@ EOF
--eddi)
dup=0
;;
--reddi)
dup=3
;;
--seddi)
dup=1
;;
Expand Down Expand Up @@ -366,6 +370,9 @@ run_aspis() {
2)
exe $OPT -load-pass-plugin=$DIR/build/passes/libFDSC.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options
;;
3)
exe $OPT -load-pass-plugin=$DIR/build/passes/libREDDI.so --passes="eddi-verify" $build_dir/out.ll -o $build_dir/out.ll $eddi_options
;;
*)
echo -e "\t--no-dup specified!"
esac
Expand Down
32 changes: 25 additions & 7 deletions passes/ASPIS.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/Pass.h"
#include <llvm/IR/Instructions.h>
#include "Utils/Utils.h"
#include <map>
#include <set>

Expand Down Expand Up @@ -33,28 +34,45 @@ class EDDI : public PassInfoMixin<EDDI> {
std::set<Function*> CompiledFuncs;
std::map<Value*, StringRef> FuncAnnotations;
std::set<Function*> OriginalFunctions;

std::set<Instruction *> InstructionsToRemove;
std::set<Function*> toHardenConstructors;
std::set<Function*> toHardenFunctions;
std::set<Value*> toHardenVariables;
std::set<Value*> DuplicatedCalls;

std::string entryPoint;

// Map of <original, duplicate> for which we need to always use the duplicate in place of the original
std::map<Value*, Value*> ValuesToAlwaysDup;
LinkageMap linkageMap;

bool duplicateAll;
bool MultipleErrBBEnabled;

void preprocess(Module &Md);
void fixDuplicatedConstructors(Module &Md);
std::set<Function *> getVirtualMethodsFromConstructor(Function *Fn);
int isUsedByStore(Instruction &I, Instruction &Use);
Instruction* cloneInstr(Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap);
void duplicateOperands (Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap, BasicBlock &ErrBB);
Value* getPtrFinalValue(Value &V);
Value* comparePtrs(Value &V1, Value &V2, IRBuilder<> &B);
void addConsistencyChecks(Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap, BasicBlock &ErrBB);
void fixFuncValsPassedByReference(Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap, IRBuilder<> &B);
int transformCallBaseInst(CallBase *CInstr, std::map<Value *, Value *> &DuplicatedInstructionMap, IRBuilder<> &B, BasicBlock &ErrBB) ;
Function *getFunctionDuplicate(Function *Fn);
Function *getFunctionFromDuplicate(Function *Fn);
Constant *duplicateConstant(Constant *C, std::map<Value *, Value *> &DuplicatedInstructionMap);
void duplicateGlobals(Module &Md, std::map<Value *, Value *> &DuplicatedInstructionMap);
void duplicateGlobals (Module &Md, std::map<Value *, Value *> &DuplicatedInstructionMap);
bool isAllocaForExceptionHandling(AllocaInst &I);
int transformCallBaseInst(CallBase *CInstr, std::map<Value *, Value *> &DuplicatedInstructionMap, IRBuilder<> &B, BasicBlock &ErrBB);
int duplicateInstruction(Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap, BasicBlock &ErrBB);
int duplicateInstruction (Instruction &I, std::map<Value *, Value *> &DuplicatedInstructionMap, BasicBlock &ErrBB);
bool isValueDuplicated(std::map<Value *, Value *> &DuplicatedInstructionMap, Instruction &V);
Function *duplicateFnArgs(Function &Fn, Module &Md, std::map<Value *, Value *> &DuplicatedInstructionMap);
void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB);
bool temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B, std::map<llvm::Value *, llvm::Value *> &InstructionMap);

void fixGlobalCtors(Module &M);
public:
explicit EDDI(bool duplicateAll, bool MultipleErrBBEnabled = false, std::string entryPoint = "main") : duplicateAll(duplicateAll), MultipleErrBBEnabled(MultipleErrBBEnabled), entryPoint(entryPoint) {}

PreservedAnalyses run(Module &M,
ModuleAnalysisManager &);

Expand Down Expand Up @@ -118,7 +136,7 @@ class CFCSS : public PassInfoMixin<CFCSS> {
const std::map<BasicBlock *, int> &BBSigs,
std::map<int, BasicBlock *> *NewBBs,
BasicBlock &ErrBB,
Value *G, Value *D);
Value *G, Value *D, int NeighborSig);

public:
PreservedAnalyses run(Module &M,
Expand Down
164 changes: 98 additions & 66 deletions passes/CFCSS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void CFCSS::initializeBlocksSignatures(Module &Md, std::map<BasicBlock*, int> &B
for (Function &Fn : Md) {
if (shouldCompile(Fn, FuncAnnotations)) {
for (BasicBlock &BB : Fn) {
if (!BB.getName().equals_insensitive("errbb")) // we skip this since "errbb" Basic Blocks are generated by EDDI
if (!BB.hasName() || !BB.getName().equals_insensitive("CFGErrBB")) // we skip this since "CFGErrBB" Basic Blocks are generated by EDDI
BBSigs.insert(std::pair<BasicBlock *, int>(&BB, Counter));
Counter++;
}
Expand All @@ -54,12 +54,19 @@ void CFCSS::initializeBlocksSignatures(Module &Md, std::map<BasicBlock*, int> &B
*/
BasicBlock* CFCSS::getFirstPredecessor(BasicBlock &BB,
const std::map<BasicBlock*, int> &BBSigs) {
std::set<BasicBlock*> Predecessors;

// check between the basic block actual predecessors
for (auto *Pred : predecessors(&BB)) {
if (BBSigs.find(Pred) != BBSigs.end()) {
return Pred;
Predecessors.insert(Pred);
} else {
errs() << "Error: predecessor " << Pred->getName() << " of basic block " << BB.getName() << " not found in the original set of basic blocks\n";
}
}
if (!Predecessors.empty()) {
return *Predecessors.begin();
}
return NULL;
}

Expand All @@ -79,11 +86,15 @@ int CFCSS::getNeighborSig(BasicBlock &BB, const std::map<BasicBlock*, int> &BBSi
while (Todo.size() != 0) {
BasicBlock *Elem = *Todo.begin(); // get the first element
for (auto *Succ : successors(Elem)) {
if (BBSigs.find(Succ) != BBSigs.end()) {
for (auto *Pred : predecessors(Succ)) {
if (BBSigs.find(Pred) != BBSigs.end() && Candidates.find(Pred) == Candidates.end()){
Todo.insert(Pred);
Candidates.insert(Pred);
if(!Succ->getName().contains_insensitive("CFGErrBB")) {
if (BBSigs.find(Succ) != BBSigs.end()) {
for (auto *Pred : predecessors(Succ)) {
if (BBSigs.find(Pred) != BBSigs.end() && Candidates.find(Pred) == Candidates.end()){
if(!Pred->getName().contains_insensitive("CFGErrBB")) {
Todo.insert(Pred);
Candidates.insert(Pred);
}
}
}
}
}
Expand All @@ -102,7 +113,9 @@ bool CFCSS::hasNPredecessorsOrMore(BasicBlock &BB, int N, const std::map<BasicBl
// Count the BB actual predecessors
for (auto *Pred : predecessors(&BB)) {
if (BBSigs.find(Pred) != BBSigs.end()) {
Count++;
if(!BB.getName().contains_insensitive("CFGErrBB")) {
Count++;
}
}
if(Count == N) {
return true;
Expand Down Expand Up @@ -131,14 +144,14 @@ void CFCSS::sortBasicBlocks(const std::map<BasicBlock *, int> &BBSigs, const std
// errs()<<"cond for "<<CFGVerificationBB->getName()<<": "<<
// Cond->getValueName() <<"\n";

if (!isa<InvokeInst>(BB->getTerminator())) {
// if (!isa<InvokeInst>(BB->getTerminator())) {
Value *Cond = &CFGVerificationBB->back();
B.CreateCondBr(Cond, BB, FuncErrBBs.find(BB->getParent())->second);
}
else {
//if the BB has an invoke at the end branch unconditionally
B.CreateBr(BB);
}
// }
// else {
// //if the BB has an invoke at the end branch unconditionally // Emilio: Why?
// B.CreateBr(BB);
// }
// move all the phi instructions from the next BB into the CFGVerificationBB
while (isa<PHINode>(BB->front())) {
Instruction &PHIInst = BB->front();
Expand All @@ -153,24 +166,24 @@ void CFCSS::sortBasicBlocks(const std::map<BasicBlock *, int> &BBSigs, const std
I->replaceSuccessorWith(BB, CFGVerificationBB);
}
}
}
}
}

/**
* Creates a new basic block for the CFG verification of basic block BB.
* Such basic block is added to the map NewBBs setting the signature of BB as key.
* @param BB
* @param BBSigs
* @param NewBBs
* @param ErrBB
* @param CFGErrBB
* @param G
* @param D
*/
void CFCSS::createCFGVerificationBB (BasicBlock &BB,
const std::map<BasicBlock *, int> &BBSigs,
std::map<int, BasicBlock *> *NewBBs,
BasicBlock &ErrBB,
Value *G, Value *D) {
BasicBlock &CFGErrBB,
Value *G, Value *D, int NeighborSig) {
// local variables
int CurSig = BBSigs.find(&BB)->second; // current signature
LLVMContext &C = BB.getModule()->getContext(); // the module context
Expand All @@ -182,53 +195,65 @@ void CFCSS::createCFGVerificationBB (BasicBlock &BB,
if (BBSigs.find(Predecessor) != BBSigs.end()) {
if(hasNPredecessorsOrMore(BB, 2, BBSigs)) {
PredSig = getNeighborSig(*Predecessor, BBSigs);
} else {
PredSig = BBSigs.find(Predecessor)->second;
}
else PredSig = BBSigs.find(Predecessor)->second;
}

//no CFG for landingPad
if(PredSig == CurSig) {
errs() << "Error: the signature of the predecessor " << Predecessor->getName() << " of basic block " << BB.getName() << " is the same as the one of the block itself.\n";
}

//no CFG for landingPad
IRBuilder<> B(C);

if (isa<LandingPadInst>(BB.getFirstNonPHI()))
{
//if the BB start with a landing pad instruction don't create CFGVerificationBB
B.SetInsertPoint(&*BB.getFirstInsertionPt());
B.CreateStore(llvm::ConstantInt::get(IntType, CurSig), G);
}
else {
// initialize new basic block, add it to the NewBBs and initialize the builder
BasicBlock *CFGVerificationBB = BasicBlock::Create(C, "CFGVerificationBB_"+std::to_string(CurSig), BB.getParent());
NewBBs->insert(std::pair<int, BasicBlock*>(CurSig, CFGVerificationBB));
B.SetInsertPoint(CFGVerificationBB);

// create the body of the CFG verification basic block
Value *InstrG = B.CreateLoad(IntType, G, "LoadG"); // load InstrG from memory
Value *InstrDLower =
llvm::ConstantInt::get(IntType, CurSig ^ PredSig);
Value *InstrCurSig = llvm::ConstantInt::get(IntType, CurSig);
Value *XorRes;

if(hasNPredecessorsOrMore(BB, 2, BBSigs)) {
// if we have multiple predecessors we compute the result as d ^ G ^ D
Value *InstrD = B.CreateLoad(IntType, D, "LoadD");
XorRes = B.CreateXor(InstrDLower, B.CreateXor(InstrG, InstrD), "RunTimeG");
if(BB.getName().contains_insensitive("CFGErrBB")) {
return;
}
else {
// otherwise the result is just d ^ G
XorRes = B.CreateXor(InstrDLower, InstrG);

if (!isa<LandingPadInst>(BB.getFirstNonPHI())) {
// initialize new basic block, add it to the NewBBs and initialize the builder
BasicBlock *CFGVerificationBB = BasicBlock::Create(C, "CFGVerificationBB_"+std::to_string(CurSig), BB.getParent());
NewBBs->insert(std::pair<int, BasicBlock*>(CurSig, CFGVerificationBB));
B.SetInsertPoint(CFGVerificationBB);

// create the body of the CFG verification basic block
Value *InstrG = B.CreateLoad(IntType, G, true, "LoadG"); // load InstrG from memory
Value *InstrDLower =
llvm::ConstantInt::get(IntType, CurSig ^ PredSig);
Value *InstrCurSig = llvm::ConstantInt::get(IntType, CurSig);
Value *XorRes;

if(hasNPredecessorsOrMore(BB, 2, BBSigs)) {
// if we have multiple predecessors we compute the result as d ^ G ^ D
Value *InstrD = B.CreateLoad(IntType, D, true, "LoadD");
XorRes = B.CreateXor(InstrDLower, B.CreateXor(InstrG, InstrD), "RunTimeG");
}
else {
// otherwise the result is just d ^ G
XorRes = B.CreateXor(InstrDLower, InstrG);

}
B.CreateStore(XorRes, G, true);
// compare the new run-time signature (stored in XorRes) with the signature of the block

}
B.CreateStore(XorRes, G, false);
// compare the new run-time signature (stored in XorRes) with the signature of the block

// if the BB has a neighbor, it means that we also have to compute D
int NeighborSig = getNeighborSig(BB, BBSigs);
if (NeighborSig != -1) {
Value *InstrD =
llvm::ConstantInt::get(IntType, CurSig ^ NeighborSig);
B.CreateStore(InstrD, D);
}
Value *Cond = B.CreateCmp(llvm::CmpInst::ICMP_EQ, XorRes, InstrCurSig);
// if the BB has a neighbor, it means that we also have to compute D
if (NeighborSig != -1) {
Value *InstrD =
llvm::ConstantInt::get(IntType, CurSig ^ NeighborSig);
B.CreateStore(InstrD, D, true);
}
Value *Cond = B.CreateCmp(llvm::CmpInst::ICMP_EQ, XorRes, InstrCurSig);
} else {
//if the BB start with a landing pad instruction don't create CFGVerificationBB
B.SetInsertPoint(&*BB.getFirstInsertionPt());

if (NeighborSig != -1) {
Value *InstrD =
llvm::ConstantInt::get(IntType, CurSig ^ NeighborSig);
B.CreateStore(InstrD, D, true);
}
B.CreateStore(llvm::ConstantInt::get(IntType, CurSig), G, true);
}

// the Branch instruction is inserted later in the function sortBasicBlocks()
Expand All @@ -243,6 +268,13 @@ PreservedAnalyses CFCSS::run(Module &Md, ModuleAnalysisManager &AM) {
std::map<BasicBlock *, int> BBSigs;
initializeBlocksSignatures(Md, BBSigs);

// Precompute NeighborSigs for all original BBs before modifying the CFG
std::map<BasicBlock *, int> NeighborSigs;
for (const auto &pair : BBSigs) {
BasicBlock *BB = pair.first;
NeighborSigs[BB] = getNeighborSig(*BB, BBSigs);
}

// map of signatures of basic blocks and their CFG-verification basic blocks
std::map<int, BasicBlock *> NewBBs;

Expand Down Expand Up @@ -274,34 +306,34 @@ PreservedAnalyses CFCSS::run(Module &Md, ModuleAnalysisManager &AM) {
Value *G = B.CreateAlloca(IntType, (llvm::Value *)nullptr, "G");
Value *D = B.CreateAlloca(IntType, (llvm::Value *)nullptr, "D");
Value *InstrG = llvm::ConstantInt::get(IntType, CurSig);
B.CreateStore(InstrG, G, false);
B.CreateStore(InstrG, G, true);

// if the Fn's first BasicBlock has a neighbor, it means that we have to compute D
int NeighborSig = getNeighborSig(Fn.front(), BBSigs);
if (NeighborSig != -1) {
Value *InstrD =
llvm::ConstantInt::get(IntType, CurSig ^ NeighborSig);
B.CreateStore(InstrD, D);
B.CreateStore(InstrD, D, true);
}

// add the error basic block to jump to in case of error
BasicBlock *ErrBB = BasicBlock::Create(Fn.getContext(), "ErrBB", &Fn);
BasicBlock *CFGErrBB = BasicBlock::Create(Fn.getContext(), "CFGErrBB", &Fn);

// insert the actual cfg verification basic blocks in the function
for (auto &Elem : BBSigs) {
BasicBlock *BB = Elem.first;
if (!BB->isEntryBlock() && BB->getParent() == &Fn) {
createCFGVerificationBB(*BB, BBSigs, &NewBBs, *ErrBB, G, D);
if (!BB->isEntryBlock() && BB->getParent() == &Fn) {
createCFGVerificationBB(*BB, BBSigs, &NewBBs, *CFGErrBB, G, D, NeighborSigs[BB]);
}
}
IRBuilder<> ErrB(ErrBB);
IRBuilder<> ErrB(CFGErrBB);

assert(!getLinkageName(linkageMap,"SigMismatch_Handler").empty() && "Function SigMismatch_Handler is missing!");
auto CalleeF = ErrBB->getModule()->getOrInsertFunction(
auto CalleeF = CFGErrBB->getModule()->getOrInsertFunction(
getLinkageName(linkageMap,"SigMismatch_Handler"), FunctionType::getVoidTy(Md.getContext()));
ErrB.CreateCall(CalleeF)->setDebugLoc(debugLoc);
ErrB.CreateUnreachable();
ErrBBs.insert(std::pair<Function*, BasicBlock*>(&Fn, ErrBB));
ErrBBs.insert(std::pair<Function*, BasicBlock*>(&Fn, CFGErrBB));
}
}

Expand Down
Loading
Loading