mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-28 19:50:48 +08:00
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:
+35
-27
@@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+25
-4
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user