GP-6129: post-review(2)

GP-6129: post-review
GP-6129: post-review
GP-6129: typo
GP-6129: first bits
GP-6129: first resultsGP-6129: more or less functional sarif tableGP-6129: pre-refactorGP-6129: tagging taint with opGP-6129: fix for composed libsGP-6129: taint action workingGP-6129: fqname errorGP-6129: error handlingGP-6129: error handling
This commit is contained in:
d-millar
2025-11-24 15:11:54 -05:00
parent 4c7ea237c3
commit cba3d5a963
23 changed files with 883 additions and 68 deletions
@@ -98,6 +98,11 @@ public enum TaintPcodeArithmetic implements PcodeArithmetic<TaintVec> {
* carries. All others, we assume every byte could be tainted by any other byte in the vector,
* so we union and broadcast.
*/
@Override
public TaintVec unaryOp(PcodeOp op, TaintVec in1) {
return PcodeArithmetic.super.unaryOp(op, in1).withOp(op);
}
@Override
public TaintVec unaryOp(int opcode, int sizeout, int sizein1, TaintVec in1) {
return switch (opcode) {
@@ -128,35 +133,20 @@ public enum TaintPcodeArithmetic implements PcodeArithmetic<TaintVec> {
switch (op.getOpcode()) {
case PcodeOp.INT_XOR, PcodeOp.INT_SUB, PcodeOp.BOOL_XOR -> {
if (Objects.equals(op.getInput(0), op.getInput(1))) {
return fromConst(0, op.getOutput().getSize());
return fromConst(0, op.getOutput().getSize()); // NB: withOp unneeded, as this essentially removes taint
}
}
}
return PcodeArithmetic.super.binaryOp(op, in1, in2);
}
/**
* {@inheritDoc}
*
* <p>
* For bitwise operations, we pair-wise union corresponding elements of the two input taint
* vectors. For integer add and subtract, we do the same, but account for the carry bits
* possibly cascading into bytes of higher significance. For {@link PcodeOp#PIECE}, we perform
* the analog as on concrete state, since the operand sizes are constant. For all others, we
* must consider that every output byte is potentially affected by any or all bytes of both
* input operands. Thus, we union and broadcast.
*/
@Override
public TaintVec binaryOp(int opcode, int sizeout, int sizein1, TaintVec in1,
int sizein2, TaintVec in2) {
return switch (opcode) {
int sizein2 = op.getInput(1).getSize();
int sizeout = op.getOutput().getSize();
return switch (op.getOpcode()) {
case PcodeOp.BOOL_AND, PcodeOp.BOOL_OR, PcodeOp.BOOL_XOR, PcodeOp.INT_AND, //
PcodeOp.INT_OR, PcodeOp.INT_XOR -> {
yield in1.zipUnion(in2);
yield in1.zipUnion(in2).withOp(op);
}
case PcodeOp.INT_ADD, PcodeOp.INT_SUB -> {
TaintVec temp = in1.zipUnion(in2);
yield temp.setCascade(endian.isBigEndian());
yield temp.setCascade(endian.isBigEndian()).withOp(op);
}
case PcodeOp.INT_SLESS, PcodeOp.INT_SLESSEQUAL, //
PcodeOp.INT_LESS, PcodeOp.INT_LESSEQUAL, //
@@ -164,30 +154,42 @@ public enum TaintPcodeArithmetic implements PcodeArithmetic<TaintVec> {
PcodeOp.FLOAT_LESS, PcodeOp.FLOAT_LESSEQUAL, //
PcodeOp.FLOAT_EQUAL, PcodeOp.FLOAT_NOTEQUAL -> {
TaintSet temp = in1.union().union(in2.union());
yield TaintVec.copies(temp, sizeout);
yield TaintVec.copies(temp, sizeout).withOp(op);
}
case PcodeOp.PIECE -> {
TaintVec temp = in1.extended(sizeout, endian.isBigEndian(), false);
temp.setShifted(endian.isBigEndian() ? -sizein2 : sizein2, ShiftMode.UNBOUNDED);
yield temp.set(endian.isBigEndian() ? sizeout - sizein2 : 0, in2);
yield temp.set(endian.isBigEndian() ? sizeout - sizein2 : 0, in2).withOp(op);
}
default -> {
TaintVec temp = in1.zipUnion(in2);
yield temp.setCopies(temp.union());
TaintVec temp = in1.zipUnion(in2).truncated(sizeout, endian.isBigEndian());
yield temp.setCopies(temp.union()).withOp(op);
}
};
}
@Override
public TaintVec binaryOp(int opcode, int sizeout, int sizein1, TaintVec in1,
int sizein2, TaintVec in2) {
throw new RuntimeException("Not supported");
}
/**
* {@inheritDoc}
*
* <p>
* Here we handle indirect taint for indirect writes
*/
@Override
public TaintVec modBeforeStore(PcodeOp op, AddressSpace space, TaintVec inOffset,
TaintVec inValue) {
return inValue.tagIndirectWrite(inOffset).withOp(op);
}
@Override
public TaintVec modBeforeStore(int sizeinOffset, AddressSpace space, TaintVec inOffset,
int sizeinValue, TaintVec inValue) {
return inValue.tagIndirectWrite(inOffset);
throw new RuntimeException("Not supported");
}
/**
@@ -196,10 +198,16 @@ public enum TaintPcodeArithmetic implements PcodeArithmetic<TaintVec> {
* <p>
* Here we handle indirect taint for indirect reads
*/
@Override
public TaintVec modAfterLoad(PcodeOp op, AddressSpace space, TaintVec inOffset,
TaintVec inValue) {
return inValue.tagIndirectRead(inOffset).withOp(op);
}
@Override
public TaintVec modAfterLoad(int sizeinOffset, AddressSpace space, TaintVec inOffset,
int sizeinValue, TaintVec inValue) {
return inValue.tagIndirectRead(inOffset);
throw new RuntimeException("Not supported");
}
/**
@@ -19,7 +19,11 @@ import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import ghidra.pcode.emu.DefaultPcodeThread.PcodeThreadExecutor;
import ghidra.pcode.exec.AnnotatedPcodeUseropLibrary;
import ghidra.pcode.exec.PcodeExecutor;
import ghidra.program.model.address.Address;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.taint.model.*;
import ghidra.trace.model.time.schedule.TraceSchedule;
@@ -59,8 +63,15 @@ public class TaintPcodeUseropLibrary extends AnnotatedPcodeUseropLibrary<Pair<by
* @return the same value, with the generated taint unioned in
*/
@PcodeUserop
public Pair<byte[], TaintVec> taint_var(Pair<byte[], TaintVec> in) {
return Pair.of(in.getLeft(), in.getRight().eachUnion(nextVar()));
public Pair<byte[], TaintVec> taint_var(Pair<byte[], TaintVec> in, @OpOp PcodeOp op,
@OpExecutor PcodeExecutor executor) {
if (executor instanceof PcodeThreadExecutor te) {
Address counter = te.getThread().getCounter();
op = new PcodeOp(counter, op.getSeqnum().getTime(), op.getOpcode(), op.getInputs(),
op.getOutput());
}
return Pair.of(in.getLeft(), in.getRight().eachUnion(nextVar()).withOp(op));
}
/**
@@ -73,12 +84,22 @@ public class TaintPcodeUseropLibrary extends AnnotatedPcodeUseropLibrary<Pair<by
* [arr_0_0][arr_0_1]...[arr_0_7].
*
* @param in the input value
* @param op the taint source
* @param executor the current executor
* @return the same value, with the generated taint unioned in
*/
@PcodeUserop
public Pair<byte[], TaintVec> taint_arr(Pair<byte[], TaintVec> in) {
public Pair<byte[], TaintVec> taint_arr(Pair<byte[], TaintVec> in, @OpOp PcodeOp op,
@OpExecutor PcodeExecutor executor) {
if (executor instanceof PcodeThreadExecutor te) {
Address counter = te.getThread().getCounter();
op = new PcodeOp(counter, op.getSeqnum().getTime(), op.getOpcode(), op.getInputs(),
op.getOutput());
}
TaintVec taint = in.getRight();
taint = taint.zipUnion(TaintVec.array(nextArrName(), 0, taint.length));
taint = taint.zipUnion(TaintVec.array(nextArrName(), 0, taint.length)).withOp(op);
return Pair.of(in.getLeft(), taint);
}
}
@@ -78,6 +78,10 @@ public class TaintPieceHandler extends AbstractPropertyBasedPieceHandler<byte[],
@Override
protected void decodeFrom(PcodeExecutorStatePiece<byte[], TaintVec> piece, AddressSetView limit,
AddressRange range, String propertyValue) {
if (propertyValue.contains("@")) {
// FIXME: WOuld be nice to actually decode the p-code op
propertyValue = propertyValue.substring(0, propertyValue.indexOf("@"));
}
TaintVec vec = TaintVec.copies(TaintSet.parse(propertyValue), (int) range.getLength());
if (limit.contains(range.getMaxAddress(), range.getMaxAddress())) {
piece.setVarInternal(range.getAddressSpace(), range.getMinAddress().getOffset(),
@@ -115,7 +119,11 @@ public class TaintPieceHandler extends AbstractPropertyBasedPieceHandler<byte[],
property.clear(new AddressRangeImpl(address, address));
}
else {
property.put(address, s.toString());
String desc = s.toString();
if (value.getOriginatingOp() != null) {
desc += "@" + value.getOriginatingOp().getSeqnum().toString();
}
property.put(address, desc);
}
}
}
@@ -21,6 +21,7 @@ import java.util.Map.Entry;
import ghidra.pcode.exec.PcodeStateCallbacks;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.lang.Register;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.taint.model.TaintSet;
import ghidra.taint.model.TaintVec;
import ghidra.util.MathUtilities;
@@ -39,6 +40,7 @@ public class TaintSpace {
protected final TaintPcodeExecutorStatePiece piece;
// TODO: There must be a better way. Similar to SemisparseByteArray?
protected final NavigableMap<Long, TaintSet> taints = new TreeMap<>(Long::compareUnsigned);
protected final NavigableMap<Long, PcodeOp> ops = new TreeMap<>(Long::compareUnsigned);
public TaintSpace(AddressSpace space, TaintPcodeExecutorStatePiece piece) {
this.space = space;
@@ -59,6 +61,7 @@ public class TaintSpace {
* @param cb callbacks to receive emulation events
*/
public void set(long offset, TaintVec val, PcodeStateCallbacks cb) {
ops.put(offset, val.getOriginatingOp());
for (int i = 0; i < val.length; i++) {
TaintSet s = val.get(i);
/*
@@ -148,7 +151,8 @@ public class TaintSpace {
while (taints.get(end) != null) {
end++;
}
TaintVec vec = new TaintVec(MathUtilities.unsignedMin(1024, end - offset));
PcodeOp pcodeOp = ops.get(offset); // Needed here to generate the TaintVec
TaintVec vec = new TaintVec(MathUtilities.unsignedMin(1024, end - offset), pcodeOp);
getInto(offset, vec, PcodeStateCallbacks.NONE);
return Map.entry(offset, vec);
}
@@ -20,6 +20,8 @@ import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import ghidra.program.model.pcode.PcodeOp;
/**
* A mutable, but fixed-size, buffer of taint sets
*
@@ -33,8 +35,15 @@ import java.util.stream.Stream;
*/
public class TaintVec {
public static TaintVec of(TaintSet... taints) {
return new TaintVec(taints);
/**
* Create a vector of taint sets
*
* @param op the originating p-code op
* @param taints the taint set
* @return the new vector
*/
public static TaintVec of(PcodeOp op, TaintSet... taints) {
return new TaintVec(taints, op);
}
/**
@@ -79,11 +88,13 @@ public class TaintVec {
private TaintSet[] sets;
private List<TaintSet> setsView;
public final int length;
private final PcodeOp originatingOp;
private TaintVec(TaintSet[] sets) {
private TaintVec(TaintSet[] sets, PcodeOp op) {
this.sets = sets;
this.setsView = Collections.unmodifiableList(Arrays.asList(sets));
this.length = sets.length;
this.originatingOp = op;
}
/**
@@ -92,7 +103,17 @@ public class TaintVec {
* @param length the length
*/
public TaintVec(int length) {
this(new TaintSet[length]);
this(new TaintSet[length], null);
}
/**
* Create a new uninitialized taint vector of the given length
*
* @param length the length
* @param op the originating op
*/
public TaintVec(int length, PcodeOp op) {
this(new TaintSet[length], op);
}
@Override
@@ -573,4 +594,22 @@ public class TaintVec {
}
return vec;
}
/**
* @return the originating op
*/
public PcodeOp getOriginatingOp() {
return originatingOp;
}
/**
* Supply the originating op
*
* @param the originating op
* @return the tagged TaintVec
*
*/
public TaintVec withOp(PcodeOp op) {
return new TaintVec(sets, op);
}
}