Merge branch 'master' into rdmarsh/cpp/ir-flow-through-outparams

This commit is contained in:
Robert Marsh
2020-01-29 14:44:29 -08:00
38 changed files with 605 additions and 65 deletions

View File

@@ -6,7 +6,7 @@
<overview>
<p>
This rule finds calls to <code>open</code> or <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
This rule finds calls to <code>socket</code> where there is no corresponding <code>close</code> call in the program analyzed.
Leaving descriptors open will cause a resource leak that will persist even after the program terminates.
</p>
@@ -14,7 +14,7 @@ Leaving descriptors open will cause a resource leak that will persist even after
</overview>
<recommendation>
<p>Ensure that all file or socket descriptors allocated by the program are freed before it terminates.</p>
<p>Ensure that all socket descriptors allocated by the program are freed before it terminates.</p>
</recommendation>
<example>

View File

@@ -1,6 +1,6 @@
/**
* @name Open descriptor never closed
* @description Functions that always return before closing the socket or file they opened leak resources.
* @description Functions that always return before closing the socket they opened leak resources.
* @kind problem
* @id cpp/descriptor-never-closed
* @problem.severity warning

View File

@@ -163,5 +163,8 @@ class Parameter extends LocalScopeVariable, @parameter {
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
*/
class ParameterIndex extends int {
ParameterIndex() { exists(Parameter p | this = p.getIndex()) }
ParameterIndex() {
exists(Parameter p | this = p.getIndex()) or
exists(Call c | exists(c.getArgument(this))) // permit indexing varargs
}
}

View File

@@ -149,6 +149,9 @@ private predicate instructionTaintStep(Instruction i1, Instruction i2) {
or
i2.(UnaryInstruction).getUnary() = i1
or
i2.(ChiInstruction).getPartial() = i1 and
not isChiForAllAliasedMemory(i2)
or
exists(BinaryInstruction bin |
bin = i2 and
predictableInstruction(i2.getAnOperand().getDef()) and
@@ -199,12 +202,29 @@ private Instruction getACallArgumentOrIndirection(CallInstruction call, int argu
private predicate modelTaintToParameter(Function f, int parameterIn, int parameterOut) {
exists(FunctionInput modelIn, FunctionOutput modelOut |
f.(TaintFunction).hasTaintFlow(modelIn, modelOut) and
(
f.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
or
f.(TaintFunction).hasTaintFlow(modelIn, modelOut)
) and
(modelIn.isParameter(parameterIn) or modelIn.isParameterDeref(parameterIn)) and
modelOut.isParameterDeref(parameterOut)
)
}
/**
* Holds if `chi` is on the chain of chi-instructions for all aliased memory.
* Taint shoud not pass through these instructions since they tend to mix up
* unrelated objects.
*/
private predicate isChiForAllAliasedMemory(Instruction instr) {
instr.(ChiInstruction).getTotal() instanceof AliasedDefinitionInstruction
or
isChiForAllAliasedMemory(instr.(ChiInstruction).getTotal())
or
isChiForAllAliasedMemory(instr.(PhiInstruction).getAnInput())
}
private predicate modelTaintToReturnValue(Function f, int parameterIn) {
// Taint flow from parameter to return value
exists(FunctionInput modelIn, FunctionOutput modelOut |

View File

@@ -264,11 +264,17 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
}
private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction iTo) {
iTo.(CopyInstruction).getSourceValue() = iFrom or
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom or
iTo.(CopyInstruction).getSourceValue() = iFrom
or
iTo.(PhiInstruction).getAnOperand().getDef() = iFrom
or
// Treat all conversions as flow, even conversions between different numeric types.
iTo.(ConvertInstruction).getUnary() = iFrom or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom or
iTo.(ConvertInstruction).getUnary() = iFrom
or
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
or
// A chi instruction represents a point where a new value (the _partial_
// operand) may overwrite an old value (the _total_ operand), but the alias
// analysis couldn't determine that it surely will overwrite every bit of it or
@@ -278,10 +284,8 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
// due to shortcomings of the alias analysis. We may get false flow in cases
// where the data is indeed overwritten.
//
// Allowing flow through the partial operand would be more noisy, especially
// for variables that have escaped: for soundness, the IR has to assume that
// every write to an unknown address can affect every escaped variable, and
// this assumption shows up as data flowing through partial chi operands.
// Flow through the partial operand belongs in the taint-tracking libraries
// for now.
iTo.getAnOperand().(ChiTotalOperand).getDef() = iFrom
}

View File

@@ -949,6 +949,10 @@ class ConvertInstruction extends UnaryInstruction {
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
}
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/**
* Represents an instruction that converts between two addresses
* related by inheritance.
@@ -989,7 +993,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
* to the address of a base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }

View File

@@ -84,6 +84,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
)
or
// Conversion using dynamic_cast results in an unknown offset
instr instanceof CheckedConvertOrNullInstruction and
bitOffset = Ints::unknown()
or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and

View File

@@ -949,6 +949,10 @@ class ConvertInstruction extends UnaryInstruction {
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
}
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/**
* Represents an instruction that converts between two addresses
* related by inheritance.
@@ -989,7 +993,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
* to the address of a base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }

View File

@@ -949,6 +949,10 @@ class ConvertInstruction extends UnaryInstruction {
ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
}
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/**
* Represents an instruction that converts between two addresses
* related by inheritance.
@@ -989,7 +993,7 @@ class InheritanceConversionInstruction extends UnaryInstruction {
/**
* Represents an instruction that converts from the address of a derived class
* to the address of a direct non-virtual base class.
* to the address of a base class.
*/
class ConvertToBaseInstruction extends InheritanceConversionInstruction {
ConvertToBaseInstruction() { getOpcode() instanceof ConvertToBaseOpcode }

View File

@@ -84,6 +84,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
)
or
// Conversion using dynamic_cast results in an unknown offset
instr instanceof CheckedConvertOrNullInstruction and
bitOffset = Ints::unknown()
or
// Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert |
convert = instr and

View File

@@ -6,7 +6,8 @@
* `FormattingFunction` to match the flow within that function.
*/
import semmle.code.cpp.Function
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.Taint
private Type stripTopLevelSpecifiersOnly(Type t) {
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
@@ -39,7 +40,7 @@ private Type getAFormatterWideTypeOrDefault() {
/**
* A standard library function that uses a `printf`-like formatting string.
*/
abstract class FormattingFunction extends Function {
abstract class FormattingFunction extends ArrayFunction, TaintFunction {
/** Gets the position at which the format parameter occurs. */
abstract int getFormatParameterIndex();
@@ -133,4 +134,33 @@ abstract class FormattingFunction extends Function {
* Gets the position of the buffer size argument, if any.
*/
int getSizeParameterIndex() { none() }
override predicate hasArrayWithNullTerminator(int bufParam) {
bufParam = getFormatParameterIndex()
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = getOutputParameterIndex() and
countParam = getSizeParameterIndex()
}
override predicate hasArrayWithUnknownSize(int bufParam) {
bufParam = getOutputParameterIndex() and
not exists(getSizeParameterIndex())
}
override predicate hasArrayInput(int bufParam) { bufParam = getFormatParameterIndex() }
override predicate hasArrayOutput(int bufParam) { bufParam = getOutputParameterIndex() }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(int arg |
(
arg = getFormatParameterIndex() or
arg >= getFirstFormatArgumentIndex()
) and
input.isParameterDeref(arg) and
output.isParameterDeref(getOutputParameterIndex())
)
}
}

View File

@@ -21,8 +21,8 @@ int main(int argc, char *argv[]) {
char buf[100] = "VAR = ";
sink(strcat(buf, getenv("VAR")));
sink(buf); // BUG: no taint
sink(untainted_buf); // the two buffers would be conflated if we added flow through partial chi inputs
sink(buf);
sink(untainted_buf); // the two buffers would be conflated if we added flow through all partial chi inputs
return 0;
}
@@ -39,3 +39,42 @@ void test_indirect_arg_to_model() {
inet_addr_retval a = inet_addr((const char *)&env_pointer);
sink(a);
}
class B {
public:
virtual void f(const char*) = 0;
};
class D1 : public B {};
class D2 : public D1 {
public:
void f(const char* p) override {}
};
class D3 : public D2 {
public:
void f(const char* p) override {
sink(p);
}
};
void test_dynamic_cast() {
B* b = new D3();
b->f(getenv("VAR")); // tainted
((D2*)b)->f(getenv("VAR")); // tainted
static_cast<D2*>(b)->f(getenv("VAR")); // tainted
dynamic_cast<D2*>(b)->f(getenv("VAR")); // tainted
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // tainted
B* b2 = new D2();
b2->f(getenv("VAR"));
((D2*)b2)->f(getenv("VAR"));
static_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // tainted [FALSE POSITIVE]
}

View File

@@ -21,6 +21,7 @@
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | p#0 |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer |
@@ -30,6 +31,64 @@
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:26:39:34 | call to inet_addr |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:15 | call to getenv |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:64:10:64:22 | (const char *)... |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:22 | call to getenv |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | defaulttainttracking.cpp:66:17:66:29 | (const char *)... |
| defaulttainttracking.cpp:66:17:66:22 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:33 | call to getenv |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | defaulttainttracking.cpp:67:28:67:40 | (const char *)... |
| defaulttainttracking.cpp:67:28:67:33 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:34 | call to getenv |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | defaulttainttracking.cpp:68:29:68:41 | (const char *)... |
| defaulttainttracking.cpp:68:29:68:34 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:38 | call to getenv |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | defaulttainttracking.cpp:69:33:69:45 | (const char *)... |
| defaulttainttracking.cpp:69:33:69:38 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | p#0 |
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:16 | call to getenv |
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:72:11:72:23 | (const char *)... |
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:23 | call to getenv |
| defaulttainttracking.cpp:74:18:74:23 | call to getenv | defaulttainttracking.cpp:74:18:74:30 | (const char *)... |
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:34 | call to getenv |
| defaulttainttracking.cpp:75:29:75:34 | call to getenv | defaulttainttracking.cpp:75:29:75:41 | (const char *)... |
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:35 | call to getenv |
| defaulttainttracking.cpp:76:30:76:35 | call to getenv | defaulttainttracking.cpp:76:30:76:42 | (const char *)... |
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p |
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:39 | call to getenv |
| defaulttainttracking.cpp:77:34:77:39 | call to getenv | defaulttainttracking.cpp:77:34:77:46 | (const char *)... |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:57:24:57:24 | p |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:58:14:58:14 | p |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:35 | call to getenv |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | defaulttainttracking.cpp:79:30:79:42 | (const char *)... |
| defaulttainttracking.cpp:79:30:79:35 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
| test_diff.cpp:92:10:92:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:1:11:1:20 | p#0 |
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:13 | argv |
@@ -123,7 +182,11 @@
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:46 | argv |
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | (const char *)... |
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:126:43:126:49 | access to array |
| test_diff.cpp:128:44:128:47 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:76:24:76:24 | p |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:47 | argv |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | (const char *)... |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:128:44:128:50 | access to array |

View File

@@ -5,10 +5,10 @@
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | AST only |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | AST only |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:52:24:52:24 | p | IR only |
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only |
| test_diff.cpp:111:10:111:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only |
@@ -16,7 +16,3 @@
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:29:24:29:24 | p | AST only |
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only |
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | IR only |
| test_diff.cpp:128:44:128:47 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p | AST only |
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p | AST only |

View File

@@ -1,6 +1,6 @@
import cpp
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTracking as ASTTaintTracking
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
predicate astFlow(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }

View File

@@ -0,0 +1,134 @@
typedef unsigned long size_t;
typedef struct {} FILE;
int snprintf(char *s, size_t n, const char *format, ...);
int sprintf(char *s, const char *format, ...);
int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...);
typedef void *va_list;
#define va_start(ap, parmN)
#define va_end(ap)
#define va_arg(ap, type) ((type)0)
int vsnprintf(char *s, size_t n, const char *format, va_list arg);
int mysprintf(char *s, size_t n, const char *format, ...)
{
va_list args;
va_start(args, format);
vsnprintf(s, n, format, args);
va_end(args);
}
int sscanf(const char *s, const char *format, ...);
// ----------
int source();
void sink(...) {};
namespace string
{
char *source();
};
namespace wstring
{
wchar_t *source();
};
// ----------
void test1()
{
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%s", "Hello."));
sink(buffer);
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%s", string::source()));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, string::source(), "Hello."));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%s %s %s", "a", "b", string::source()));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%.*s", 10, string::source()));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%i", 0));
sink(buffer);
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%i", source()));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%.*s", source(), "Hello."));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(snprintf(buffer, 256, "%p", string::source()));
sink(buffer); // tainted (debatable)
}
{
char buffer[256] = {0};
sink(sprintf(buffer, "%s", string::source()));
sink(buffer); // tainted
}
{
char buffer[256] = {0};
sink(sprintf(buffer, "%ls", wstring::source()));
sink(buffer); // tainted
}
{
wchar_t wbuffer[256] = {0};
sink(swprintf(wbuffer, 256, L"%s", wstring::source()));
sink(wbuffer); // tainted
}
{
char buffer[256] = {0};
sink(mysprintf(buffer, 256, "%s", string::source()));
sink(buffer); // tainted [NOT DETECTED - implement UserDefinedFormattingFunction.getOutputParameterIndex()]
}
{
int i = 0;
sink(sscanf("123", "%i", &i));
sink(i);
}
{
int i = 0;
sink(sscanf(string::source(), "%i", &i));
sink(i); // tainted [NOT DETECTED]
}
{
char buffer[256] = {0};
sink(sscanf("Hello.", "%s", &buffer));
sink(buffer);
}
{
char buffer[256] = {0};
sink(sscanf(string::source(), "%s", &buffer));
sink(buffer); // tainted [NOT DETECTED]
}
}

View File

@@ -3,6 +3,108 @@
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | |
| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | |
| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | |
| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | |
| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | |
| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT |
| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | |
| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | |
| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | |
| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT |
| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | |
| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | |
| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | |
| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT |
| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | |
| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | |
| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | |
| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT |
| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | |
| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | |
| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | |
| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT |
| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | |
| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | |
| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | |
| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT |
| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | |
| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | |
| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | |
| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT |
| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | |
| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | |
| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | |
| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT |
| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | |
| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | |
| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | |
| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT |
| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | |
| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | |
| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | |
| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT |
| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | |
| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | |
| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | |
| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT |
| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | |
| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | |
| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | |
| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT |
| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | |
| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | |
| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | |
| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT |
| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | |
| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | |
| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | |
| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | |
| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | |
| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | |
| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | |
| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | |
| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | |
| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | |
| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | |
| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT |
| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | |
| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | |
| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | |
| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | |
| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT |
| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | |
| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | |
| taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | |
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | |
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | |

View File

@@ -1,3 +1,13 @@
| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source |
| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source |
| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source |
| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source |
| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source |
| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source |
| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source |
| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source |
| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source |
| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source |
| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 |
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |

View File

@@ -1,3 +1,13 @@
| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only |
| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only |
| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only |
| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only |
| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only |
| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only |
| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only |
| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only |
| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only |
| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only |
| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only |
| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only |

View File

@@ -4,6 +4,7 @@
| test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. |
| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. |

View File

@@ -41,7 +41,7 @@ void good1(wchar_t *wstr) {
}
void bad3(char *str) {
// BAD -- zero-termination proved by sprintf (as destination) [NOT DETECTED]
// BAD -- zero-termination proved by sprintf (as destination)
char *buffer = (char *)malloc(strlen(str));
sprintf(buffer, "%s", str);
free(buffer);