Skip to content
Merged
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
87 changes: 75 additions & 12 deletions cpp/ql/src/semmle/code/cpp/ir/dataflow/DefaultTaintTracking.qll
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.dataflow.DataFlow2
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch as Dispatch
private import semmle.code.cpp.models.interfaces.Taint
private import semmle.code.cpp.models.interfaces.DataFlow

/**
* A predictable instruction is one where an external user can predict
Expand Down Expand Up @@ -159,18 +161,79 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
// This is part of the translation of `a[i]`, where we want taint to flow
// from `a`.
i2.(PointerAddInstruction).getLeft() = i1
// TODO: robust Chi handling
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to remove this TODO comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because I don't think it belongs here. It probably belongs in the IR data-flow library and the IR itself, which means it should be in a Jira ticket -- I've opened CPP-490.

//
// TODO: Flow from argument to return of known functions: Port missing parts
// of `returnArgument` to the `interfaces.Taint` and `interfaces.DataFlow`
// libraries.
//
// TODO: Flow from input argument to output argument of known functions: Port
// missing parts of `copyValueBetweenArguments` to the `interfaces.Taint` and
// `interfaces.DataFlow` libraries and implement call side-effect nodes. This
// will help with the test for `ExecTainted.ql`. The test for
// `TaintedPath.ql` is more tricky because the output arg is a pointer
// addition expression.
or
// Flow from argument to return value
i2 = any(CallInstruction call |
exists(int indexIn |
modelTaintToReturnValue(call.getStaticCallTarget(), indexIn) and
i1 = getACallArgumentOrIndirection(call, indexIn)
)
)
or
// Flow from input argument to output argument
// TODO: This won't work in practice as long as all aliased memory is tracked
// together in a single virtual variable.
// TODO: Will this work on the test for `TaintedPath.ql`, where the output arg
// is a pointer addition expression?
i2 = any(WriteSideEffectInstruction outNode |
exists(CallInstruction call, int indexIn, int indexOut |
modelTaintToParameter(call.getStaticCallTarget(), indexIn, indexOut) and
i1 = getACallArgumentOrIndirection(call, indexIn) and
outNode.getIndex() = indexOut and
outNode.getPrimaryInstruction() = call
)
)
}

/**
* Get an instruction that goes into argument `argumentIndex` of `call`. This
* can be either directly or through one pointer indirection.
*/
private Instruction getACallArgumentOrIndirection(CallInstruction call, int argumentIndex) {
result = call.getPositionalArgument(argumentIndex)
or
exists(ReadSideEffectInstruction readSE |
// TODO: why are read side effect operands imprecise?
result = readSE.getSideEffectOperand().getAnyDef() and
readSE.getPrimaryInstruction() = call and
readSE.getIndex() = argumentIndex
)
}

private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) {
exists(FunctionInput modelIn, FunctionOutput modelOut |
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
modelOut.isParameterDeref(parameterOut)
)
}

private predicate modelTaintToReturnValue(Function f, int parameterIn) {
// Taint flow from parameter to return value
exists(FunctionInput modelIn, FunctionOutput modelOut |
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
(modelOut.isReturnValue() or modelOut.isReturnValueDeref())
)
or
// Data flow (not taint flow) to where the return value points. For the time
// being we will conflate pointers and objects in taint tracking.
exists(FunctionInput modelIn, FunctionOutput modelOut |
f.(DataFlowFunction).hasDataFlow(modelIn, modelOut) and
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
modelOut.isReturnValueDeref()
)
or
// Taint flow from one argument to another and data flow from an argument to a
// return value. This happens in functions like `strcat` and `memcpy`. We
// could model this flow in two separate steps, but that would add reverse
// flow from the write side-effect to the call instruction, which may not be
// desirable.
exists(int parameterMid, InParameter modelMid, OutReturnValue returnOut |
modelTaintToParameter(f, parameterIn, parameterMid) and
modelMid.isParameter(parameterMid) and
f.(DataFlowFunction).hasDataFlow(modelMid, returnOut)
)
}

private Element adjustedSink(DataFlow::Node sink) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1198,52 +1198,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
}

/**
* An instruction representing the side effect of a function call on any memory that might be read
* by that call.
* An instruction representing the side effect of a function call on any memory
* that might be read by that call. This instruction is emitted instead of
* `CallSideEffectInstruction` when it's certain that the call target cannot
* write to escaped memory.
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
* An instruction representing a read side effect of a function call on a
* specific parameter.
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
/** Gets the operand for the value that will be read from this instruction, if known. */
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }

/** Gets the value that will be read from this instruction, if known. */
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }

/** Gets the operand for the address from which this instruction may read. */
final AddressOperand getArgumentOperand() { result = getAnOperand() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
/** Gets the address from which this instruction may read. */
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
*/
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing a side effect of a function call.
* An instruction representing a write side effect of a function call on a
* specific parameter.
*/
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Expand Down
47 changes: 29 additions & 18 deletions cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1198,52 +1198,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
}

/**
* An instruction representing the side effect of a function call on any memory that might be read
* by that call.
* An instruction representing the side effect of a function call on any memory
* that might be read by that call. This instruction is emitted instead of
* `CallSideEffectInstruction` when it's certain that the call target cannot
* write to escaped memory.
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
* An instruction representing a read side effect of a function call on a
* specific parameter.
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
/** Gets the operand for the value that will be read from this instruction, if known. */
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }

/** Gets the value that will be read from this instruction, if known. */
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }

/** Gets the operand for the address from which this instruction may read. */
final AddressOperand getArgumentOperand() { result = getAnOperand() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
/** Gets the address from which this instruction may read. */
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
*/
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing a side effect of a function call.
* An instruction representing a write side effect of a function call on a
* specific parameter.
*/
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1198,52 +1198,63 @@ class CallSideEffectInstruction extends SideEffectInstruction {
}

/**
* An instruction representing the side effect of a function call on any memory that might be read
* by that call.
* An instruction representing the side effect of a function call on any memory
* that might be read by that call. This instruction is emitted instead of
* `CallSideEffectInstruction` when it's certain that the call target cannot
* write to escaped memory.
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
* An instruction representing a read side effect of a function call on a
* specific parameter.
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
class ReadSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
ReadSideEffectInstruction() { getOpcode() instanceof ReadSideEffectOpcode }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
/** Gets the operand for the value that will be read from this instruction, if known. */
final SideEffectOperand getSideEffectOperand() { result = getAnOperand() }

/** Gets the value that will be read from this instruction, if known. */
final Instruction getSideEffect() { result = getSideEffectOperand().getDef() }

/** Gets the operand for the address from which this instruction may read. */
final AddressOperand getArgumentOperand() { result = getAnOperand() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
/** Gets the address from which this instruction may read. */
final Instruction getArgumentDef() { result = getArgumentOperand().getDef() }
}

/**
* An instruction representing the read of an indirect parameter within a function call.
*/
class IndirectReadSideEffectInstruction extends ReadSideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
class BufferReadSideEffectInstruction extends ReadSideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}

Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }

Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }

Instruction getSideEffect() { result = getAnOperand().(SideEffectOperand).getDef() }
}

/**
* An instruction representing a side effect of a function call.
* An instruction representing a write side effect of a function call on a
* specific parameter.
*/
class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Expand Down
8 changes: 7 additions & 1 deletion cpp/ql/src/semmle/code/cpp/models/implementations/Inet.qll
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class InetAton extends TaintFunction, ArrayFunction {
}
}

class InetAddr extends TaintFunction, ArrayFunction {
class InetAddr extends TaintFunction, ArrayFunction, AliasFunction {
InetAddr() { hasGlobalName("inet_addr") }

override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
Expand All @@ -41,6 +41,12 @@ class InetAddr extends TaintFunction, ArrayFunction {
override predicate hasArrayInput(int bufParam) { bufParam = 0 }

override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }

override predicate parameterNeverEscapes(int index) { index = 0 }

override predicate parameterEscapesOnlyViaReturn(int index) { none() }

override predicate parameterIsAlwaysReturned(int index) { none() }
}

class InetNetwork extends TaintFunction, ArrayFunction {
Expand Down
Loading