References:
Only in Mips, not in RISCV.
A function pass with instruction visitor: class CheriRangeChecker : public FunctionPass, public InstVisitor<CheriRangeChecker>
;
Pass is initialized at
void initializeCheriRangeCheckerPass(PassRegistry &); in llvm/lib/Target/Mips/Mips.h (LLM: this init func’s implementation will be automatically generated by LLVM using macro INITIALIZE_PASS_BEGIN
).
<–
llvm/lib/Target/Mips/MipsTargetMachine.cpp: LLVMInitializeMipsTarget(): initializeCheriRangeCheckerPass(*PR);
Pass is invoked at
llvm/lib/Target/Mips/MipsTargetMachine.cpp: void MipsPassConfig::addIRPasses(): addPass(createCheriRangeChecker());
Functions/Steps:
runOnFunction()
:
visit(F)
: collect pairs of range info and correspondign cast instruction in vectors: <AllocaOperands, xxxCastInst>
in Casts
and <AllocaOperands, ConstantCast>
in ConstantCasts
:ValueSource
of the cast operand: auto Src = getValueSource(ASC.getOperand(0));
AllocOperands AO = getRangeForAllocation(Src);
getRangeForAllocation(ValueSource Src)
, see below.Casts
User *P2I = testI2P(I2P)
: get the operand(0) as PtrToInt
instruction.ValueSource
of the operands of P2I
Casts
Value *RV = RI.getReturnValue()
testI2P(*cast<User>(RV))
testI2P()
: get the operand(0) as PtrToInt
instruction.ConstantCasts
CallInst
testI2P(*cast<User>(AV))
: get the operand(0) as PtrToInt
instruction.ConstantCasts
cheri_cap_bounds_set
:SetLengthFn = Intrinsic::getDeclaration(M, SetLength, SizeTy);
Casts
and ConstantCasts
I2P
Casts
ConstantCasts
I2P
in Casts
ConstantCasts
RangCheckedValue()
to inert bound check instruction and get the new instruction contain the casted object pointer New
New
(Now all users are refering New
)
User *testI2P(User &I2P)
: Return Operand(0) as P2I
, if it is Instruction::PtrToInt
and is {non-extenal global || AllocaInst || CallSite}.
dyn_cast<PointerType>(I2P.getType())
), andisCheriPointer(DestTy, TD.get())
), andInstruction::PtrToInt
User
and store as P2I;Value *Src = P2I->getOperand(0)->stripPointerCasts()
RangeCheckedValue()
: add cheri_cap_bounds_set
instruction and return a set of new instructions (IRBuilder)
I2P
.Result -> I2P
, and return.getRangeForAllocation()
:
malloc/valloc/realloc/aligned_alloc/reallocf/calloc
for Heap objectAllocaInst
for stack object,AllocOperands()
instance.get the range of the malloc’d and alloca’d object.
CallSite Malloc = CallSite(Src.Base); // initialize a CallSite instance to get the call instruction information.
Function * Fn = Malloc.getCalledFunction; // get function information.runOnFunction
Fn->getName(); // get the function name in string. can be malloc, valloc, realloc, aligned_alloc, reallocf, calloc.
Malloc.getArgument(0); // first argument
// a special switch statement in C++
switch (StringSwitch<int>(Fn->getName())
.Case("malloc", 1)
.Case("valloc", 1)
.Case("realloc", 2)
.Case("aligned_alloc", 2)
.Case("reallocf", 2)
.Case("calloc", 3)
.Default(-1)) {
default:
return AllocOperands();
case 1:
return AllocOperands{Malloc.getArgument(0), nullptr, Src,
cheri::SetBoundsPointerSource::Heap};
case 2:
return AllocOperands{Malloc.getArgument(1), nullptr, Src,
cheri::SetBoundsPointerSource::Heap};
case 3:
return AllocOperands{Malloc.getArgument(0), Malloc.getArgument(1),
Src, cheri::SetBoundsPointerSource::Heap};
}
Get and set bound for heap and stack objects.
First, tracking the operands of different instructions, collect the object size and source instruction:
Second, insert instruction after the object allocation site to set the bounds to the pointer.
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?