Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ff98f56
feat(REDDI): port REDDI in ASPIS mainline
Mar 2, 2026
07357a7
feat(REDDI): Duplicate entrypoint in-place and bugfix
Mar 31, 2026
de1d745
fix(build_system): Now also FDSC and SEDDI have the DUPLICATE_ALL flag
Apr 15, 2026
6553b9d
feat(EDDI): Restored possibility to use private error blocks for each…
Apr 16, 2026
bfa6cab
fix(debug_locations): Fixed findNearestDebugLoc
Apr 16, 2026
77aca64
feat(EDDI): Supporting indirect function calls
Apr 17, 2026
f525b7e
fix(EDDI): Handle std::thread class and methods as to exclude from du…
Apr 19, 2026
3084f11
test(reddi): add reddi modifications to tests to effectively test REDDI
Apr 27, 2026
f4e87db
fix(DuplicateGlobals): Handling anonymous globals and fixing duplicat…
Apr 27, 2026
cf5d07d
fix(EDDI): handling duplication of constant global variables with TAD
Apr 27, 2026
1a23bcf
fix(EDDI): change name to unnamed global variables
Apr 27, 2026
a1987cb
tests(EDDI): removing blacklisting of duplication methods
Apr 27, 2026
62e6aa6
fix(EDDI): not duplicating extern global variables
Apr 29, 2026
83f3c8c
fix(CFCSS): restored check for predecessors when creating CFGVerifica…
Apr 29, 2026
d481693
fix(EDDI): enhanced prints during EDDI pass
Apr 29, 2026
401278a
test(EDDI): add complex test for cpp features
Apr 29, 2026
9ec40ef
upd(EDDI): use incremental counter for naming unnamed global variables
May 15, 2026
a4cad45
upd(EDDI): enhance handling of DuplicatedInstructionMap
May 15, 2026
4e4ad2b
fix(MultipleErrBB): add aspis option to toggle the usage of multiple …
May 15, 2026
3964b1b
test(MultipleErrBB): add testing of multiple error BB for EDDI and REDDI
May 15, 2026
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
12 changes: 12 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 All @@ -149,6 +150,8 @@ parse_commands() {
at synchonization points, which can be used to trace where
consistency checks are executed.

--multiple-errbb Enables multiple error basic blocks in EDDI

EOF
exit 0
;;
Expand Down Expand Up @@ -201,6 +204,9 @@ EOF
--eddi)
dup=0
;;
--reddi)
dup=3
;;
--seddi)
dup=1
;;
Expand Down Expand Up @@ -232,6 +238,9 @@ EOF
eddi_options="$eddi_options $opt=true";
cfc_options="$cfc_options $opt=true";
enable_profiling=true;
;;
--multiple-errbb)
eddi_options="$eddi_options -multiple-errbb=true";
;;
-g)
debug_enabled=true;
Expand Down Expand Up @@ -366,6 +375,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
48 changes: 34 additions & 14 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,47 @@ 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::unordered_multimap<Value *, Value *> DuplicatedInstructionMap;

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);
Instruction* cloneInstr(Instruction &I);
void duplicateOperands (Instruction &I, 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);
void addConsistencyChecks(Instruction &I, BasicBlock &ErrBB);
void fixFuncValsPassedByReference(Instruction &I, IRBuilder<> &B);
int transformCallBaseInst(CallBase *CInstr, 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);
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);
bool isValueDuplicated(std::map<Value *, Value *> &DuplicatedInstructionMap, Instruction &V);
Function *duplicateFnArgs(Function &Fn, Module &Md, std::map<Value *, Value *> &DuplicatedInstructionMap);

int duplicateInstruction (Instruction &I, BasicBlock &ErrBB);
bool isValueDuplicated(Instruction &V);
Function *duplicateFnArgs(Function &Fn, Module &Md);
void CreateErrBB(Module &Md, Function &Fn, BasicBlock *ErrBB);
bool temporaryArgumentDuplication(Module &Md, llvm::Value *value, IRBuilder<> &B);
Value *getDuplicateValue(Value *V, Instruction *I);

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 +138,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