mirror of
https://github.com/github/codeql.git
synced 2025-12-22 03:36:30 +01:00
Merge remote-tracking branch 'upstream/master' into dataflow-partial-chi
Conflicts: cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/tainted.expected
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
/* '#include <stdlib.h>' was forgotton */
|
||||
|
||||
int main(void) {
|
||||
/* 'int malloc()' assumed */
|
||||
unsigned char *p = malloc(100);
|
||||
*p = 'a';
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>A function is called without a prior function declaration or definition.
|
||||
When this happens, the compiler generates an implicit declaration of the function,
|
||||
specifying an integer return type and no parameters.
|
||||
If the implicit declaration does not match the true signature of the function, the
|
||||
function may behave unpredictably.</p>
|
||||
|
||||
<p>This may indicate a misspelled function name, or that the required header containing
|
||||
the function declaration has not been included.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Provide an explicit declaration of the function before invoking it.</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="ImplicitFunctionDeclaration.c" />
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL31-C.+Declare+identifiers+before+using+them">DCL31-C. Declare identifiers before using them</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @name Implicit function declaration
|
||||
* @description An implicitly declared function is assumed to take no
|
||||
* arguments and return an integer. If this assumption does not hold, it
|
||||
* may lead to unpredictable behavior.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id cpp/implicit-function-declaration
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import MistypedFunctionArguments
|
||||
import TooFewArguments
|
||||
import TooManyArguments
|
||||
import semmle.code.cpp.commons.Exclusions
|
||||
|
||||
predicate locInfo(Locatable e, File file, int line, int col) {
|
||||
e.getFile() = file and
|
||||
e.getLocation().getStartLine() = line and
|
||||
e.getLocation().getStartColumn() = col
|
||||
}
|
||||
|
||||
predicate sameLocation(FunctionDeclarationEntry fde, FunctionCall fc) {
|
||||
exists(File file, int line, int col |
|
||||
locInfo(fde, file, line, col) and
|
||||
locInfo(fc, file, line, col)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
from FunctionDeclarationEntry fdeIm, FunctionCall fc
|
||||
where
|
||||
isCompiledAsC(fdeIm.getFile()) and
|
||||
not isFromMacroDefinition(fc) and
|
||||
fdeIm.isImplicit() and
|
||||
sameLocation(fdeIm, fc) and
|
||||
not mistypedFunctionArguments(fc, _, _) and
|
||||
not tooFewArguments(fc, _) and
|
||||
not tooManyArguments(fc, _)
|
||||
select fc, "Function call implicitly declares '" + fdeIm.getName() + "'."
|
||||
@@ -12,95 +12,10 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
predicate arithTypesMatch(Type arg, Type parm) {
|
||||
arg = parm
|
||||
or
|
||||
arg.getSize() = parm.getSize() and
|
||||
(
|
||||
arg instanceof IntegralOrEnumType and
|
||||
parm instanceof IntegralOrEnumType
|
||||
or
|
||||
arg instanceof FloatingPointType and
|
||||
parm instanceof FloatingPointType
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
|
||||
// arithmetic types
|
||||
arithTypesMatch(arg, parm)
|
||||
or
|
||||
// conversion to/from pointers to void is allowed
|
||||
arg instanceof VoidType
|
||||
or
|
||||
parm instanceof VoidType
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
|
||||
nestedPointerArgTypeMayBeUsed(arg, parm)
|
||||
or
|
||||
// nested pointers
|
||||
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate argTypeMayBeUsed(Type arg, Type parm) {
|
||||
// arithmetic types
|
||||
arithTypesMatch(arg, parm)
|
||||
or
|
||||
// pointers to compatible types
|
||||
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
// C11 arrays
|
||||
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(ArrayType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(ArrayType).getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
// This predicate holds whenever expression `arg` may be used to initialize
|
||||
// function parameter `parm` without need for run-time conversion.
|
||||
pragma[inline]
|
||||
predicate argMayBeUsed(Expr arg, Parameter parm) {
|
||||
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
|
||||
}
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
import MistypedFunctionArguments
|
||||
|
||||
from FunctionCall fc, Function f, Parameter p
|
||||
where
|
||||
f = fc.getTarget() and
|
||||
p = f.getAParameter() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
p.getIndex() < fc.getNumberOfArguments() and
|
||||
// Parameter p and its corresponding call argument must have mismatched types
|
||||
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
|
||||
where mistypedFunctionArguments(fc, f, p)
|
||||
select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(),
|
||||
fc.getArgument(p.getIndex()) as arg, arg.toString(),
|
||||
arg.getExplicitlyConverted().getUnspecifiedType() as atype, atype.toString(), p, p.getTypedName()
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Provides the implementation of the MistypedFunctionArguments query. The
|
||||
* query is implemented as a library, so that we can avoid producing
|
||||
* duplicate results in other similar queries.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
private predicate arithTypesMatch(Type arg, Type parm) {
|
||||
arg = parm
|
||||
or
|
||||
arg.getSize() = parm.getSize() and
|
||||
(
|
||||
arg instanceof IntegralOrEnumType and
|
||||
parm instanceof IntegralOrEnumType
|
||||
or
|
||||
arg instanceof FloatingPointType and
|
||||
parm instanceof FloatingPointType
|
||||
)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
|
||||
// arithmetic types
|
||||
arithTypesMatch(arg, parm)
|
||||
or
|
||||
// conversion to/from pointers to void is allowed
|
||||
arg instanceof VoidType
|
||||
or
|
||||
parm instanceof VoidType
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
|
||||
nestedPointerArgTypeMayBeUsed(arg, parm)
|
||||
or
|
||||
// nested pointers
|
||||
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
private predicate argTypeMayBeUsed(Type arg, Type parm) {
|
||||
// arithmetic types
|
||||
arithTypesMatch(arg, parm)
|
||||
or
|
||||
// pointers to compatible types
|
||||
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(PointerType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
// C11 arrays
|
||||
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
|
||||
parm.(ArrayType).getBaseType().getUnspecifiedType())
|
||||
or
|
||||
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
|
||||
parm.(ArrayType).getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
// This predicate holds whenever expression `arg` may be used to initialize
|
||||
// function parameter `parm` without need for run-time conversion.
|
||||
pragma[inline]
|
||||
private predicate argMayBeUsed(Expr arg, Parameter parm) {
|
||||
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
|
||||
}
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
private predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
|
||||
f = fc.getTarget() and
|
||||
p = f.getAParameter() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
p.getIndex() < fc.getNumberOfArguments() and
|
||||
// Parameter p and its corresponding call argument must have mismatched types
|
||||
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
|
||||
}
|
||||
@@ -15,31 +15,8 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
import TooFewArguments
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
where
|
||||
f = fc.getTarget() and
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
// There is an explicit declaration of the function whose parameter count is larger
|
||||
// than the number of call arguments
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
fde.getNumberOfParameters() > fc.getNumberOfArguments()
|
||||
)
|
||||
where tooFewArguments(fc, f)
|
||||
select fc, "This call has fewer arguments than required by $@.", f, f.toString()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Provides the implementation of the TooFewArguments query. The
|
||||
* query is implemented as a library, so that we can avoid producing
|
||||
* duplicate results in other similar queries.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
private predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
predicate tooFewArguments(FunctionCall fc, Function f) {
|
||||
f = fc.getTarget() and
|
||||
not f.isVarargs() and
|
||||
not f instanceof BuiltInFunction and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
// There is an explicit declaration of the function whose parameter count is larger
|
||||
// than the number of call arguments
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
fde.getNumberOfParameters() > fc.getNumberOfArguments()
|
||||
)
|
||||
}
|
||||
@@ -12,35 +12,8 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
// or implicitly declared (i.e., lacking a prototype)
|
||||
predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.isImplicit() and
|
||||
not fde.hasVoidParamList() and
|
||||
fde.getNumberOfParameters() = 0 and
|
||||
not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
import TooManyArguments
|
||||
|
||||
from FunctionCall fc, Function f
|
||||
where
|
||||
f = fc.getTarget() and
|
||||
not f.isVarargs() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
exists(f.getBlock()) and
|
||||
// There must not exist a declaration with the number of parameters
|
||||
// at least as large as the number of call arguments
|
||||
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
|
||||
)
|
||||
where tooManyArguments(fc, f)
|
||||
select fc, "This call has more arguments than required by $@.", f, f.toString()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Provides the implementation of the TooManyArguments query. The
|
||||
* query is implemented as a library, so that we can avoid producing
|
||||
* duplicate results in other similar queries.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
// True if function was ()-declared, but not (void)-declared or K&R-defined
|
||||
// or implicitly declared (i.e., lacking a prototype)
|
||||
private predicate hasZeroParamDecl(Function f) {
|
||||
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
not fde.isImplicit() and
|
||||
not fde.hasVoidParamList() and
|
||||
fde.getNumberOfParameters() = 0 and
|
||||
not fde.isDefinition()
|
||||
)
|
||||
}
|
||||
|
||||
// True if this file (or header) was compiled as a C file
|
||||
private predicate isCompiledAsC(File f) {
|
||||
f.compiledAsC()
|
||||
or
|
||||
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
|
||||
}
|
||||
|
||||
predicate tooManyArguments(FunctionCall fc, Function f) {
|
||||
f = fc.getTarget() and
|
||||
not f.isVarargs() and
|
||||
hasZeroParamDecl(f) and
|
||||
isCompiledAsC(f.getFile()) and
|
||||
exists(f.getBlock()) and
|
||||
// There must not exist a declaration with the number of parameters
|
||||
// at least as large as the number of call arguments
|
||||
not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
|
||||
fde.getNumberOfParameters() >= fc.getNumberOfArguments()
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -282,8 +282,6 @@ class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
|
||||
class DataFlowLocation = Location;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends Expr {
|
||||
DataFlowCall() { this instanceof Call }
|
||||
|
||||
@@ -68,9 +68,11 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
|
||||
)
|
||||
or
|
||||
// Taint can flow through modeled functions
|
||||
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
or
|
||||
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
|
||||
or
|
||||
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
|
||||
exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,24 +132,38 @@ private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
|
||||
// dest_ptr = strdup(tainted_ptr)
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
exprOut = call and
|
||||
outModel.isReturnValueDeref() and
|
||||
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
(
|
||||
exprOut = call and
|
||||
outModel.isReturnValueDeref()
|
||||
or
|
||||
exprOut = call and
|
||||
outModel.isReturnValue()
|
||||
) and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
(
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
or
|
||||
inModel.isQualifierObject() and
|
||||
exprIn = call.getQualifier()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
@@ -160,14 +176,46 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
|
||||
// memcpy(&dest_var, tainted_ptr, len)
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(TaintFunction f, Call call, FunctionOutput outModel, int argOutIndex |
|
||||
exists(
|
||||
TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel, int argOutIndex
|
||||
|
|
||||
call.getTarget() = f and
|
||||
argOut = call.getArgument(argOutIndex) and
|
||||
outModel.isParameterDeref(argOutIndex) and
|
||||
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) |
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
(
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
call.passesByReference(argInIndex, exprIn)
|
||||
or
|
||||
inModel.isParameter(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
)
|
||||
or
|
||||
inModel.isQualifierObject() and
|
||||
exprIn = call.getQualifier()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate exprToPartialDefinitionStep(Expr exprIn, Expr exprOut) {
|
||||
exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
|
||||
call.getTarget() = f and
|
||||
(
|
||||
exprOut = call.getQualifier() and
|
||||
outModel.isQualifierObject()
|
||||
) and
|
||||
f.hasTaintFlow(inModel, outModel) and
|
||||
exists(int argInIndex |
|
||||
inModel.isParameterDeref(argInIndex) and
|
||||
exprIn = call.getArgument(argInIndex)
|
||||
or
|
||||
|
||||
@@ -21,33 +21,30 @@ private predicate predictableInstruction(Instruction instr) {
|
||||
predictableInstruction(instr.(UnaryInstruction).getUnary())
|
||||
}
|
||||
|
||||
private predicate userInputInstruction(Instruction instr) {
|
||||
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
|
||||
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
|
||||
instr = wsei and
|
||||
wsei.getPrimaryInstruction() = ci
|
||||
)
|
||||
or
|
||||
userInputReturned(instr.getConvertedResultExpression())
|
||||
or
|
||||
isUserInput(instr.getConvertedResultExpression(), _)
|
||||
or
|
||||
instr.getConvertedResultExpression() instanceof EnvironmentRead
|
||||
or
|
||||
instr
|
||||
.(LoadInstruction)
|
||||
.getSourceAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable()
|
||||
.hasName("argv") and
|
||||
instr.getEnclosingFunction().hasGlobalName("main")
|
||||
}
|
||||
|
||||
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
|
||||
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
userInputInstruction(source.asInstruction())
|
||||
exists(CallInstruction ci, WriteSideEffectInstruction wsei |
|
||||
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
|
||||
source.asInstruction() = wsei and
|
||||
wsei.getPrimaryInstruction() = ci
|
||||
)
|
||||
or
|
||||
userInputReturned(source.asExpr())
|
||||
or
|
||||
isUserInput(source.asExpr(), _)
|
||||
or
|
||||
source.asExpr() instanceof EnvironmentRead
|
||||
or
|
||||
source
|
||||
.asInstruction()
|
||||
.(LoadInstruction)
|
||||
.getSourceAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable()
|
||||
.hasName("argv") and
|
||||
source.asInstruction().getEnclosingFunction().hasGlobalName("main")
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { any() }
|
||||
|
||||
@@ -83,10 +83,24 @@ private module VirtualDispatch {
|
||||
)
|
||||
or
|
||||
// Flow through global variable
|
||||
exists(StoreInstruction store, Variable var |
|
||||
exists(StoreInstruction store |
|
||||
store = src.asInstruction() and
|
||||
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
|
||||
this.flowsFromGlobal(var) and
|
||||
(
|
||||
exists(Variable var |
|
||||
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
|
||||
this.flowsFromGlobal(var)
|
||||
)
|
||||
or
|
||||
exists(Variable var, FieldAccess a |
|
||||
var = store
|
||||
.getDestinationAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable() and
|
||||
this.flowsFromGlobalUnionField(var, a)
|
||||
)
|
||||
) and
|
||||
allowFromArg = true
|
||||
)
|
||||
}
|
||||
@@ -97,6 +111,19 @@ private module VirtualDispatch {
|
||||
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var
|
||||
)
|
||||
}
|
||||
|
||||
private predicate flowsFromGlobalUnionField(Variable var, FieldAccess a) {
|
||||
a.getTarget().getDeclaringType() instanceof Union and
|
||||
exists(LoadInstruction load |
|
||||
this.flowsFrom(DataFlow::instructionNode(load), _) and
|
||||
load
|
||||
.getSourceAddress()
|
||||
.(FieldAddressInstruction)
|
||||
.getObjectAddress()
|
||||
.(VariableAddressInstruction)
|
||||
.getASTVariable() = var
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Call through a function pointer. */
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -139,12 +139,6 @@ abstract class Configuration extends string {
|
||||
partialFlow(source, node, this) and
|
||||
dist = node.getSourceDistance()
|
||||
}
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowForward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
|
||||
/** DEPRECATED: use `hasFlow` instead. */
|
||||
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -191,8 +191,6 @@ class DataFlowExpr = Expr;
|
||||
|
||||
class DataFlowType = Type;
|
||||
|
||||
class DataFlowLocation = Location;
|
||||
|
||||
/** A function call relevant for data flow. */
|
||||
class DataFlowCall extends CallInstruction {
|
||||
/**
|
||||
|
||||
@@ -55,6 +55,9 @@ class Node extends TIRDataFlowNode {
|
||||
*/
|
||||
Expr asConvertedExpr() { result = instr.getConvertedResultExpression() }
|
||||
|
||||
/** Gets the argument that defines this `DefinitionByReferenceNode`, if any. */
|
||||
Expr asDefiningArgument() { result = this.(DefinitionByReferenceNode).getArgument() }
|
||||
|
||||
/** Gets the parameter corresponding to this node, if any. */
|
||||
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() }
|
||||
|
||||
@@ -268,6 +271,8 @@ private predicate simpleInstructionLocalFlowStep(Instruction iFrom, Instruction
|
||||
// Treat all conversions as flow, even conversions between different numeric types.
|
||||
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_
|
||||
|
||||
@@ -947,6 +947,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.
|
||||
|
||||
@@ -96,6 +96,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
|
||||
|
||||
@@ -947,6 +947,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.
|
||||
|
||||
@@ -947,6 +947,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.
|
||||
|
||||
@@ -96,6 +96,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
|
||||
|
||||
@@ -83,6 +83,11 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
|
||||
override predicate hasOnlySpecificReadSideEffects() { none() }
|
||||
|
||||
override predicate hasOnlySpecificWriteSideEffects() { any() }
|
||||
|
||||
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
|
||||
getParameter(i).getUnspecifiedType() instanceof PointerType and
|
||||
buffer = true
|
||||
}
|
||||
}
|
||||
|
||||
class PureFunction extends TaintFunction, SideEffectFunction {
|
||||
|
||||
@@ -47,20 +47,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
// These always copy the full value of the input buffer to the output
|
||||
// buffer
|
||||
this.hasName("strcpy") or
|
||||
this.hasName("_mbscpy") or
|
||||
this.hasName("wcscpy")
|
||||
) and
|
||||
(
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isReturnValueDeref()
|
||||
)
|
||||
input.isParameterDeref(1) and
|
||||
output.isParameterDeref(0)
|
||||
or
|
||||
input.isParameterDeref(1) and
|
||||
output.isReturnValueDeref()
|
||||
or
|
||||
input.isParameter(0) and
|
||||
output.isReturnValue()
|
||||
@@ -77,10 +68,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
|
||||
this.hasName("wcsncpy") or
|
||||
this.hasName("_wcsncpy_l")
|
||||
) and
|
||||
(
|
||||
input.isParameter(2) or
|
||||
input.isParameterDeref(1)
|
||||
) and
|
||||
input.isParameter(2) and
|
||||
(
|
||||
output.isParameterDeref(0) or
|
||||
output.isReturnValueDeref()
|
||||
|
||||
@@ -9,17 +9,14 @@ import semmle.code.cpp.models.interfaces.Taint
|
||||
class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
|
||||
StrdupFunction() {
|
||||
exists(string name |
|
||||
hasGlobalOrStdName(name) and
|
||||
hasGlobalName(name) and
|
||||
(
|
||||
// strdup(str)
|
||||
name = "strdup"
|
||||
or
|
||||
// wcsdup(str)
|
||||
name = "wcsdup"
|
||||
)
|
||||
or
|
||||
hasGlobalName(name) and
|
||||
(
|
||||
or
|
||||
// _strdup(str)
|
||||
name = "_strdup"
|
||||
or
|
||||
@@ -37,9 +34,32 @@ class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
// These always copy the full value of the input buffer to the result
|
||||
// buffer
|
||||
input.isParameterDeref(0) and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `strndup` style allocation function.
|
||||
*/
|
||||
class StrndupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
|
||||
StrndupFunction() {
|
||||
exists(string name |
|
||||
hasGlobalName(name) and
|
||||
// strndup(str, maxlen)
|
||||
name = "strndup"
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
|
||||
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
input.isParameterDeref(0) or
|
||||
input.isParameter(1)
|
||||
) and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import FunctionInputsAndOutputs
|
||||
import semmle.code.cpp.models.Models
|
||||
|
||||
/**
|
||||
* A library function for which a value is copied from a parameter or qualifier
|
||||
* to an output buffer, return value, or qualifier.
|
||||
* A library function for which a value is or may be copied from a parameter
|
||||
* or qualifier to an output buffer, return value, or qualifier.
|
||||
*
|
||||
* Note that this does not include partial copying of values or partial writes
|
||||
* to destinations; that is covered by `TaintModel.qll`.
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ import semmle.code.cpp.models.Models
|
||||
* from a parameter or qualifier to an output buffer, return value, or qualifier.
|
||||
*
|
||||
* Note that this does not include direct copying of values; that is covered by
|
||||
* DataFlowModel.qll
|
||||
* DataFlowModel.qll. If a value is sometimes copied in full, and sometimes
|
||||
* altered (for example copying a string with `strncpy`), this is also considered
|
||||
* data flow.
|
||||
*/
|
||||
abstract class TaintFunction extends Function {
|
||||
abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output);
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
|
||||
| stackVariableReachability.c:11:6:11:6 | a | 10 |
|
||||
| stackVariableReachability.c:12:2:12:2 | a | 40 |
|
||||
| stackVariableReachability.c:13:2:13:2 | a | 40 |
|
||||
| stackVariableReachability.c:14:4:14:4 | a | 40 |
|
||||
| stackVariableReachability.c:15:2:15:2 | a | call to f |
|
||||
| stackVariableReachability.c:15:8:15:8 | a | 40 |
|
||||
| stackVariableReachability.c:16:2:16:2 | a | call to f |
|
||||
| stackVariableReachability.c:19:3:19:3 | b | 50 |
|
||||
| stackVariableReachability.c:21:3:21:3 | b | 60 |
|
||||
| stackVariableReachability.c:23:2:23:2 | c | b |
|
||||
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
|
||||
| stackVariableReachability.c:24:2:24:2 | c | 50, 60, b |
|
||||
@@ -0,0 +1,19 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class MyStackVariableReachability extends StackVariableReachabilityWithReassignment {
|
||||
MyStackVariableReachability() { this = "MyStackVariableReachability" }
|
||||
|
||||
override predicate isSourceActual(ControlFlowNode node, StackVariable v) {
|
||||
exprDefinition(v, _, node)
|
||||
}
|
||||
|
||||
override predicate isSinkActual(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
}
|
||||
|
||||
from MyStackVariableReachability svr, ControlFlowNode sink
|
||||
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
int cond();
|
||||
int f(int x);
|
||||
|
||||
void test(int p)
|
||||
{
|
||||
int a = 10;
|
||||
int b = 20;
|
||||
int c = 30;
|
||||
|
||||
a = a + 1;
|
||||
a = 40;
|
||||
a++;
|
||||
++a;
|
||||
a = f(a);
|
||||
a;
|
||||
|
||||
if (cond()) {
|
||||
b = 50;
|
||||
} else {
|
||||
b = 60;
|
||||
}
|
||||
c = b;
|
||||
c;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
| stackVariableReachability.c:11:2:11:2 | a | ... + ... |
|
||||
| stackVariableReachability.c:11:6:11:6 | a | 10 |
|
||||
| stackVariableReachability.c:12:2:12:2 | a | 40 |
|
||||
| stackVariableReachability.c:13:2:13:2 | a | 40 |
|
||||
| stackVariableReachability.c:14:4:14:4 | a | 40 |
|
||||
| stackVariableReachability.c:15:2:15:2 | a | call to f |
|
||||
| stackVariableReachability.c:15:8:15:8 | a | 40 |
|
||||
| stackVariableReachability.c:16:2:16:2 | a | call to f |
|
||||
| stackVariableReachability.c:19:3:19:3 | b | 50 |
|
||||
| stackVariableReachability.c:21:3:21:3 | b | 60 |
|
||||
| stackVariableReachability.c:23:2:23:2 | c | b |
|
||||
| stackVariableReachability.c:23:6:23:6 | b | 50, 60 |
|
||||
| stackVariableReachability.c:24:2:24:2 | c | b |
|
||||
@@ -0,0 +1,17 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
class MyStackVariableReachability extends StackVariableReachability {
|
||||
MyStackVariableReachability() { this = "MyStackVariableReachability" }
|
||||
|
||||
override predicate isSource(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
|
||||
override predicate isSink(ControlFlowNode node, StackVariable v) {
|
||||
node.(VariableAccess).getTarget() = v
|
||||
}
|
||||
|
||||
override predicate isBarrier(ControlFlowNode node, StackVariable v) { exprDefinition(v, _, node) }
|
||||
}
|
||||
|
||||
from MyStackVariableReachability svr, ControlFlowNode sink
|
||||
select sink, strictconcat(Expr source | svr.reaches(source, _, sink) | source.toString(), ", ")
|
||||
@@ -10,8 +10,8 @@ void sink(const char *);
|
||||
void sink(int);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int taintedInt = atoi(getenv("VAR"));
|
||||
taintedInt++; // BUG: `taintedInt` isn't marked as tainted. Only `++` is.
|
||||
|
||||
|
||||
|
||||
sink(_strdup(getenv("VAR")));
|
||||
sink(strdup(getenv("VAR")));
|
||||
@@ -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]
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:1:22:1:25 | nptr |
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:13:7:13:16 | taintedInt |
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:13:20:13:23 | call to atoi |
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:13:25:13:30 | call to getenv |
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:13:25:13:37 | (const char *)... |
|
||||
| defaulttainttracking.cpp:13:25:13:30 | call to getenv | defaulttainttracking.cpp:14:3:14:14 | ... ++ |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:6:15:6:24 | p#0 |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:5:14:5:23 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... |
|
||||
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:7:26:7:35 | p#0 |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:32 | call to getenv |
|
||||
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... |
|
||||
@@ -26,6 +22,7 @@
|
||||
| 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 |
|
||||
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv |
|
||||
@@ -34,3 +31,162 @@
|
||||
| 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 |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | (const char *)... |
|
||||
| test_diff.cpp:92:10:92:13 | argv | test_diff.cpp:92:10:92:16 | access to array |
|
||||
| test_diff.cpp:94:32:94:35 | argv | defaulttainttracking.cpp:10:11:10:13 | p#0 |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:2:11:2:13 | p#0 |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:10:94:36 | reinterpret_cast<int>... |
|
||||
| test_diff.cpp:94:32:94:35 | argv | test_diff.cpp:94:32:94:35 | argv |
|
||||
| test_diff.cpp:96:26:96:29 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:16:39:16:39 | a |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:17:10:17:10 | a |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:29 | argv |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | (const char *)... |
|
||||
| test_diff.cpp:96:26:96:29 | argv | test_diff.cpp:96:26:96:32 | access to array |
|
||||
| test_diff.cpp:98:18:98:21 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:16:39:16:39 | a |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:17:10:17:10 | a |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:13:98:13 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:17:98:21 | & ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:98:18:98:21 | argv |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | (const char *)... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:10:100:14 | * ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:11 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:100:11:100:14 | access to array |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | (const char *)... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:26:102:30 | * ... |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:27 | p |
|
||||
| test_diff.cpp:98:18:98:21 | argv | test_diff.cpp:102:27:102:30 | access to array |
|
||||
| test_diff.cpp:104:12:104:15 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | (const char *)... |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:10:104:20 | * ... |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:15 | argv |
|
||||
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:12:104:19 | ... + ... |
|
||||
| test_diff.cpp:108:10:108:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:29:24:29:24 | p |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:30:14:30:14 | p |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:13 | argv |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | (const char *)... |
|
||||
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:108:10:108:16 | access to array |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:36:24:36:24 | p |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:13 | argv |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | (const char *)... |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:111:10:111:16 | access to array |
|
||||
| test_diff.cpp:115:11:115:14 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:41:24:41:24 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:42:14:42:14 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:52:24:52:24 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:53:37:53:37 | p |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:14 | argv |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | (const char *)... |
|
||||
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:115:11:115:17 | access to array |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:60:24:60:24 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:61:34:61:34 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:88:24:88:24 | p |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:29 | argv |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | (const char *)... |
|
||||
| test_diff.cpp:118:26:118:29 | argv | test_diff.cpp:118:26:118:32 | access to array |
|
||||
| test_diff.cpp:121:23:121:26 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:60:24:60:24 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:61:34:61:34 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:67:24:67:24 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:68:14:68:14 | p |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:26 | argv |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | (const char *)... |
|
||||
| test_diff.cpp:121:23:121:26 | argv | test_diff.cpp:121:23:121:29 | access to array |
|
||||
| test_diff.cpp:124:19:124:22 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:24:20:24:29 | p#0 |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:81:24:81:24 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:82:14:82:14 | p |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:22 | argv |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | (const char *)... |
|
||||
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:124:19:124:25 | access to array |
|
||||
| test_diff.cpp:126:43:126:46 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:1:11:1:20 | p#0 |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:76:24:76:24 | p |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:81:24:81:24 | p |
|
||||
| test_diff.cpp:126:43:126:46 | argv | test_diff.cpp:82:14:82:14 | p |
|
||||
| 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 |
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
void sink(const char *);
|
||||
void sink(int);
|
||||
|
||||
struct S {
|
||||
void(*f)(const char*);
|
||||
|
||||
void apply(char* p) {
|
||||
f(p);
|
||||
}
|
||||
|
||||
void (*get())(const char*) {
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
void calls_sink_with_argv(const char* a) {
|
||||
sink(a);
|
||||
}
|
||||
|
||||
extern int i;
|
||||
|
||||
class BaseWithPureVirtual {
|
||||
public:
|
||||
virtual void f(const char*) = 0;
|
||||
};
|
||||
|
||||
class DerivedCallsSink : public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class DerivedDoesNotCallSink : public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class DerivedDoesNotCallSinkDiamond2 : virtual public BaseWithPureVirtual {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
|
||||
void f(const char* p) override {
|
||||
DerivedCallsSinkDiamond1::f(p);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class CRTP {
|
||||
public:
|
||||
void f(const char* p) {
|
||||
static_cast<T*>(this)->g(p);
|
||||
}
|
||||
};
|
||||
|
||||
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
|
||||
public:
|
||||
void g(const char* p) {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class Derived1 : public BaseWithPureVirtual {};
|
||||
|
||||
class Derived2 : public Derived1 {
|
||||
public:
|
||||
void f(const char* p) override {}
|
||||
};
|
||||
|
||||
class Derived3 : public Derived2 {
|
||||
public:
|
||||
void f(const char* p) override {
|
||||
sink(p);
|
||||
}
|
||||
};
|
||||
|
||||
class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
|
||||
public:
|
||||
void g(const char* p) {}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
sink(argv[0]);
|
||||
|
||||
sink(reinterpret_cast<int>(argv));
|
||||
|
||||
calls_sink_with_argv(argv[1]);
|
||||
|
||||
char*** p = &argv;
|
||||
|
||||
sink(*p[0]);
|
||||
|
||||
calls_sink_with_argv(*p[i]);
|
||||
|
||||
sink(*(argv + 1));
|
||||
|
||||
BaseWithPureVirtual* b = new DerivedCallsSink;
|
||||
|
||||
b->f(argv[1]);
|
||||
|
||||
b = new DerivedDoesNotCallSink;
|
||||
b->f(argv[0]); // no flow [FALSE POSITIVE by AST]
|
||||
|
||||
BaseWithPureVirtual* b2 = new DerivesMultiple;
|
||||
|
||||
b2->f(argv[i]);
|
||||
|
||||
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
|
||||
crtp_not_call_sink.f(argv[0]);
|
||||
|
||||
CRTP<CRTPCallsSink> crtp_calls_sink;
|
||||
crtp_calls_sink.f(argv[0]);
|
||||
|
||||
Derived1* calls_sink = new Derived3;
|
||||
calls_sink->f(argv[1]);
|
||||
|
||||
static_cast<Derived2*>(calls_sink)->f(argv[1]);
|
||||
|
||||
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED by IR]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | IR only |
|
||||
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only |
|
||||
| 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: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 |
|
||||
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only |
|
||||
| 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 |
|
||||
@@ -0,0 +1,19 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.TaintTracking as ASTTaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||
|
||||
predicate astFlow(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
|
||||
|
||||
predicate irFlow(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) }
|
||||
|
||||
from Expr source, Element sink, string note
|
||||
where
|
||||
astFlow(source, sink) and
|
||||
not irFlow(source, sink) and
|
||||
note = "AST only"
|
||||
or
|
||||
irFlow(source, sink) and
|
||||
not astFlow(source, sink) and
|
||||
note = "IR only"
|
||||
select source, sink, note
|
||||
@@ -130,3 +130,46 @@ namespace virtual_inheritance {
|
||||
sink(topRef.isSource()); // flow [NOT DETECTED]
|
||||
}
|
||||
}
|
||||
|
||||
union union_with_sink_fun_ptrs {
|
||||
SinkFunctionType f;
|
||||
SinkFunctionType g;
|
||||
} u;
|
||||
|
||||
void call_sink_through_union_field_f(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void call_sink_through_union_field_g(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void set_global_union_field_f() {
|
||||
u.f = callSink;
|
||||
}
|
||||
|
||||
void test_call_sink_through_union() {
|
||||
set_global_union_field_f();
|
||||
call_sink_through_union_field_f(u.f);
|
||||
call_sink_through_union_field_g(u.g);
|
||||
}
|
||||
|
||||
union { union_with_sink_fun_ptrs u; } u2;
|
||||
|
||||
void call_sink_through_union_field_u_g(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void call_sink_through_union_field_u_f(SinkFunctionType func) {
|
||||
func(source());
|
||||
}
|
||||
|
||||
void set_global_union_field_u_f() {
|
||||
u2.u.f = callSink;
|
||||
}
|
||||
|
||||
void test_call_sink_through_union_2() {
|
||||
set_global_union_field_u_f();
|
||||
call_sink_through_union_field_u_f(u2.u.f); // flow [NOT DETECTED]
|
||||
call_sink_through_union_field_u_g(u2.u.g); // flow [NOT DETECTED]
|
||||
}
|
||||
@@ -17,6 +17,8 @@
|
||||
| dispatch.cpp:73:14:73:19 | dispatch.cpp:23:38:23:38 | IR only |
|
||||
| dispatch.cpp:81:13:81:18 | dispatch.cpp:23:38:23:38 | IR only |
|
||||
| dispatch.cpp:107:17:107:22 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| dispatch.cpp:140:8:140:13 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| dispatch.cpp:144:8:144:13 | dispatch.cpp:96:8:96:8 | IR only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:14:3:14:6 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:18:8:18:8 | AST only |
|
||||
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | AST only |
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
| dispatch.cpp:55:22:55:30 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
|
||||
| dispatch.cpp:58:28:58:36 | call to isSource1 | dispatch.cpp:22:37:22:42 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:107:17:107:22 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:140:8:140:13 | call to source |
|
||||
| dispatch.cpp:96:8:96:8 | x | dispatch.cpp:144:8:144:13 | call to source |
|
||||
| lambdas.cpp:35:8:35:8 | a | lambdas.cpp:8:10:8:15 | call to source |
|
||||
| test.cpp:7:8:7:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
| test.cpp:9:8:9:9 | t1 | test.cpp:6:12:6:17 | call to source |
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:14:23:19 | envStr | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:28 | call to getenv | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:23:23:23:40 | (const char *)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:6:25:29 | ! ... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:12 | call to strcmp | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:7:25:29 | (bool)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:25:14:25:19 | envStr | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:6:29:28 | ! ... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:12 | call to strcmp | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:7:29:28 | (bool)... | |
|
||||
| test.cpp:23:23:23:28 | call to getenv | test.cpp:29:14:29:19 | envStr | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:8:24:8:25 | s1 | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:14:38:19 | envStr | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:28 | call to getenv | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:38:23:38:40 | (const char *)... | |
|
||||
| test.cpp:38:23:38:28 | call to getenv | test.cpp:40:14:40:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:8:24:8:25 | s1 | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:45:13:45:24 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:14:49:19 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:15:50:24 | envStr_ptr | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:28:50:40 | & ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr | |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | envStrGlobal |
|
||||
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | envStrGlobal |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... | |
|
||||
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:36:11:37 | s2 | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:67:7:67:13 | copying | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:17:68:24 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:33 | call to getenv | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:68:28:68:46 | (const char *)... | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:69:10:69:13 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:5:70:10 | call to strcpy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:12:70:15 | copy | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:70:18:70:25 | userName | |
|
||||
| test.cpp:68:28:68:33 | call to getenv | test.cpp:71:12:71:15 | copy | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:15:22:15:25 | nptr | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:15:75:18 | call to atoi | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:25 | call to getenv | |
|
||||
| test.cpp:75:20:75:25 | call to getenv | test.cpp:75:20:75:45 | (const char *)... | |
|
||||
@@ -0,0 +1,7 @@
|
||||
import semmle.code.cpp.security.TaintTracking
|
||||
|
||||
from Expr source, Element tainted, string globalVar
|
||||
where
|
||||
taintedIncludingGlobalVars(source, tainted, globalVar) and
|
||||
not tainted.getLocation().getFile().getExtension() = "h"
|
||||
select source, tainted, globalVar
|
||||
78
cpp/ql/test/library-tests/dataflow/security-taint/test.cpp
Normal file
78
cpp/ql/test/library-tests/dataflow/security-taint/test.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Test for the general-purpose taint-tracking
|
||||
// mechanism that is used by several of the security queries.
|
||||
|
||||
///// Library functions //////
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
char *getenv(const char *name);
|
||||
size_t strlen(const char *s);
|
||||
char *strcpy(char *s1, const char *s2);
|
||||
|
||||
void *malloc(size_t size);
|
||||
|
||||
int atoi(const char *nptr);
|
||||
|
||||
//// Test code /////
|
||||
|
||||
bool isAdmin = false;
|
||||
|
||||
void test1()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
|
||||
if (!strcmp(envStr, "admin")) {
|
||||
isAdmin = true;
|
||||
}
|
||||
|
||||
if (!strcmp(envStr, "none")) {
|
||||
isAdmin = false;
|
||||
}
|
||||
}
|
||||
|
||||
extern const char *specialUser;
|
||||
|
||||
void test2()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
|
||||
if (!strcmp(envStr, specialUser)) {
|
||||
isAdmin = true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *envStrGlobal;
|
||||
|
||||
void test3()
|
||||
{
|
||||
const char *envStr = getenv("USERINFO");
|
||||
const char **envStr_ptr = &envStrGlobal;
|
||||
|
||||
*envStr_ptr = envStr;
|
||||
|
||||
if (!strcmp(envStrGlobal, "admin")) {
|
||||
isAdmin = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bugWithBinop() {
|
||||
const char *userName = getenv("USER_NAME");
|
||||
|
||||
// The following is tainted, but should not cause
|
||||
// the whole program to be considered tainted.
|
||||
int bytes = strlen(userName) + 1;
|
||||
}
|
||||
|
||||
char* copying() {
|
||||
const char *userName = getenv("USER_NAME");
|
||||
char copy[1024];
|
||||
strcpy(copy, userName);
|
||||
return copy; // copy should be tainted
|
||||
}
|
||||
|
||||
void guard() {
|
||||
int len = atoi(getenv("FOOBAZ_BRANCHING"));
|
||||
if (len > 1000) return;
|
||||
char **node = (char **) malloc(len * sizeof(char *));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.Taint
|
||||
|
||||
/** Common data flow configuration to be used by tests. */
|
||||
class TestAllocationConfig extends TaintTracking::Configuration {
|
||||
@@ -25,3 +26,39 @@ class TestAllocationConfig extends TaintTracking::Configuration {
|
||||
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
|
||||
}
|
||||
}
|
||||
|
||||
class SetMemberFunction extends TaintFunction {
|
||||
SetMemberFunction() { this.hasName("setMember") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
class GetMemberFunction extends TaintFunction {
|
||||
GetMemberFunction() { this.hasName("getMember") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValue()
|
||||
}
|
||||
}
|
||||
|
||||
class SetStringFunction extends TaintFunction {
|
||||
SetStringFunction() { this.hasName("setString") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
}
|
||||
|
||||
class GetStringFunction extends TaintFunction {
|
||||
GetStringFunction() { this.hasName("getString") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isQualifierObject() and
|
||||
output.isReturnValueDeref()
|
||||
}
|
||||
}
|
||||
|
||||
134
cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp
Normal file
134
cpp/ql/test/library-tests/dataflow/taint-tests/format.cpp
Normal 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]
|
||||
}
|
||||
}
|
||||
@@ -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 | |
|
||||
@@ -337,9 +439,13 @@
|
||||
| taint.cpp:370:13:370:26 | hello, world | taint.cpp:370:6:370:11 | call to strdup | TAINT |
|
||||
| taint.cpp:371:6:371:12 | call to strndup | taint.cpp:371:2:371:25 | ... = ... | |
|
||||
| taint.cpp:371:6:371:12 | call to strndup | taint.cpp:374:7:374:7 | c | |
|
||||
| taint.cpp:371:14:371:19 | source | taint.cpp:371:6:371:12 | call to strndup | TAINT |
|
||||
| taint.cpp:371:22:371:24 | 100 | taint.cpp:371:6:371:12 | call to strndup | TAINT |
|
||||
| taint.cpp:377:23:377:28 | source | taint.cpp:381:30:381:35 | source | |
|
||||
| taint.cpp:381:6:381:12 | call to strndup | taint.cpp:381:2:381:36 | ... = ... | |
|
||||
| taint.cpp:381:6:381:12 | call to strndup | taint.cpp:382:7:382:7 | a | |
|
||||
| taint.cpp:381:14:381:27 | hello, world | taint.cpp:381:6:381:12 | call to strndup | TAINT |
|
||||
| taint.cpp:381:30:381:35 | source | taint.cpp:381:6:381:12 | call to strndup | TAINT |
|
||||
| taint.cpp:385:27:385:32 | source | taint.cpp:389:13:389:18 | source | |
|
||||
| taint.cpp:389:6:389:11 | call to wcsdup | taint.cpp:389:2:389:19 | ... = ... | |
|
||||
| taint.cpp:389:6:389:11 | call to wcsdup | taint.cpp:391:7:391:7 | a | |
|
||||
@@ -347,3 +453,62 @@
|
||||
| taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:390:2:390:28 | ... = ... | |
|
||||
| taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | |
|
||||
| taint.cpp:390:13:390:27 | hello, world | taint.cpp:390:6:390:11 | call to wcsdup | TAINT |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:420:7:420:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:421:7:421:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:422:2:422:2 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:417:13:417:14 | call to MyClass2 | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:426:7:426:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:427:7:427:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:428:2:428:2 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:417:19:417:20 | call to MyClass2 | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:443:7:443:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:444:7:444:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:445:2:445:2 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:418:13:418:15 | call to MyClass3 | taint.cpp:447:7:447:7 | d | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:422:2:422:2 | a | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:421:7:421:7 | a [post update] | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:423:7:423:7 | a | |
|
||||
| taint.cpp:422:2:422:2 | a [post update] | taint.cpp:424:7:424:7 | a | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:428:2:428:2 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:427:7:427:7 | b [post update] | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:429:7:429:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:430:7:430:7 | b | |
|
||||
| taint.cpp:428:2:428:2 | b [post update] | taint.cpp:431:7:431:7 | b | |
|
||||
| taint.cpp:428:2:428:20 | ... = ... | taint.cpp:430:9:430:14 | member | |
|
||||
| taint.cpp:428:13:428:18 | call to source | taint.cpp:428:2:428:20 | ... = ... | |
|
||||
| taint.cpp:433:6:433:20 | call to MyClass2 | taint.cpp:433:6:433:20 | new | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:433:2:433:20 | ... = ... | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:435:7:435:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:436:7:436:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:433:6:433:20 | new | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:436:7:436:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:435:7:435:7 | ref arg c | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:437:2:437:2 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:436:7:436:7 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:438:7:438:7 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:437:2:437:2 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:438:7:438:7 | ref arg c | taint.cpp:439:7:439:7 | c | |
|
||||
| taint.cpp:438:7:438:7 | ref arg c | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:439:7:439:7 | c [post update] | taint.cpp:441:9:441:9 | c | |
|
||||
| taint.cpp:441:9:441:9 | c | taint.cpp:441:2:441:9 | delete | TAINT |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:445:2:445:2 | d | |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:444:7:444:7 | d [post update] | taint.cpp:447:7:447:7 | d | |
|
||||
| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:446:7:446:7 | d | |
|
||||
| taint.cpp:445:2:445:2 | d [post update] | taint.cpp:447:7:447:7 | d | |
|
||||
|
||||
@@ -371,7 +371,7 @@ void test_strdup(char *source)
|
||||
c = strndup(source, 100);
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
sink(c); // tainted [NOT DETECTED]
|
||||
sink(c); // tainted
|
||||
}
|
||||
|
||||
void test_strndup(int source)
|
||||
@@ -379,7 +379,7 @@ void test_strndup(int source)
|
||||
char *a;
|
||||
|
||||
a = strndup("hello, world", source);
|
||||
sink(a);
|
||||
sink(a); // tainted
|
||||
}
|
||||
|
||||
void test_wcsdup(wchar_t *source)
|
||||
@@ -391,3 +391,58 @@ void test_wcsdup(wchar_t *source)
|
||||
sink(a); // tainted
|
||||
sink(b);
|
||||
}
|
||||
|
||||
// --- qualifiers ---
|
||||
|
||||
class MyClass2 {
|
||||
public:
|
||||
MyClass2(int value);
|
||||
void setMember(int value);
|
||||
int getMember();
|
||||
|
||||
int member;
|
||||
};
|
||||
|
||||
class MyClass3 {
|
||||
public:
|
||||
MyClass3(const char *string);
|
||||
void setString(const char *string);
|
||||
const char *getString();
|
||||
|
||||
const char *buffer;
|
||||
};
|
||||
|
||||
void test_qualifiers()
|
||||
{
|
||||
MyClass2 a(0), b(0), *c;
|
||||
MyClass3 d("");
|
||||
|
||||
sink(a);
|
||||
sink(a.getMember());
|
||||
a.setMember(source());
|
||||
sink(a); // tainted
|
||||
sink(a.getMember()); // tainted
|
||||
|
||||
sink(b);
|
||||
sink(b.getMember());
|
||||
b.member = source();
|
||||
sink(b); // tainted
|
||||
sink(b.member); // tainted
|
||||
sink(b.getMember());
|
||||
|
||||
c = new MyClass2(0);
|
||||
|
||||
sink(c);
|
||||
sink(c->getMember());
|
||||
c->setMember(source());
|
||||
sink(c); // tainted (deref)
|
||||
sink(c->getMember()); // tainted
|
||||
|
||||
delete c;
|
||||
|
||||
sink(d);
|
||||
sink(d.getString());
|
||||
d.setString(strings::source());
|
||||
sink(d); // tainted
|
||||
sink(d.getString()); // tainted
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
@@ -38,4 +48,13 @@
|
||||
| taint.cpp:351:7:351:7 | a | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:352:7:352:7 | b | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:372:7:372:7 | a | taint.cpp:365:24:365:29 | source |
|
||||
| taint.cpp:374:7:374:7 | c | taint.cpp:365:24:365:29 | source |
|
||||
| taint.cpp:382:7:382:7 | a | taint.cpp:377:23:377:28 | source |
|
||||
| taint.cpp:391:7:391:7 | a | taint.cpp:385:27:385:32 | source |
|
||||
| taint.cpp:423:7:423:7 | a | taint.cpp:422:14:422:19 | call to source |
|
||||
| taint.cpp:424:9:424:17 | call to getMember | taint.cpp:422:14:422:19 | call to source |
|
||||
| taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source |
|
||||
| taint.cpp:438:7:438:7 | c | taint.cpp:437:15:437:20 | call to source |
|
||||
| taint.cpp:439:10:439:18 | call to getMember | taint.cpp:437:15:437:20 | call to source |
|
||||
| taint.cpp:446:7:446:7 | d | taint.cpp:445:14:445:28 | call to source |
|
||||
| taint.cpp:447:9:447:17 | call to getString | taint.cpp:445:14:445:28 | call to source |
|
||||
|
||||
@@ -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 |
|
||||
@@ -26,4 +36,13 @@
|
||||
| taint.cpp:351:7:351:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
| taint.cpp:352:7:352:7 | taint.cpp:330:6:330:11 | AST only |
|
||||
| taint.cpp:372:7:372:7 | taint.cpp:365:24:365:29 | AST only |
|
||||
| taint.cpp:374:7:374:7 | taint.cpp:365:24:365:29 | AST only |
|
||||
| taint.cpp:382:7:382:7 | taint.cpp:377:23:377:28 | AST only |
|
||||
| taint.cpp:391:7:391:7 | taint.cpp:385:27:385:32 | AST only |
|
||||
| taint.cpp:423:7:423:7 | taint.cpp:422:14:422:19 | AST only |
|
||||
| taint.cpp:424:9:424:17 | taint.cpp:422:14:422:19 | AST only |
|
||||
| taint.cpp:429:7:429:7 | taint.cpp:428:13:428:18 | IR only |
|
||||
| taint.cpp:438:7:438:7 | taint.cpp:437:15:437:20 | AST only |
|
||||
| taint.cpp:439:10:439:18 | taint.cpp:437:15:437:20 | AST only |
|
||||
| taint.cpp:446:7:446:7 | taint.cpp:445:14:445:28 | AST only |
|
||||
| taint.cpp:447:9:447:17 | taint.cpp:445:14:445:28 | AST only |
|
||||
|
||||
@@ -20,3 +20,5 @@
|
||||
| taint.cpp:291:7:291:7 | y | taint.cpp:275:6:275:11 | call to source |
|
||||
| taint.cpp:337:7:337:7 | t | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:350:7:350:7 | t | taint.cpp:330:6:330:11 | call to source |
|
||||
| taint.cpp:429:7:429:7 | b | taint.cpp:428:13:428:18 | call to source |
|
||||
| taint.cpp:430:9:430:14 | member | taint.cpp:428:13:428:18 | call to source |
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
| Test for deprecated library StackVariableReachability. |
|
||||
@@ -1,4 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.StackVariableReachability
|
||||
|
||||
select "Test for deprecated library StackVariableReachability."
|
||||
@@ -1,4 +0,0 @@
|
||||
| unused_functions.c:16:13:16:27 | unused_function | Static function unused_function is unreachable | unused_functions.c:16:13:16:27 | unused_function | unused_function |
|
||||
| unused_functions.c:20:13:20:28 | unused_function2 | Static function unused_function2 is unreachable ($@ must be removed at the same time) | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:24:13:24:28 | unused_function3 | Static function unused_function3 is unreachable | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:63:13:63:14 | h4 | Static function h4 is unreachable | unused_functions.c:63:13:63:14 | h4 | h4 |
|
||||
@@ -1 +0,0 @@
|
||||
Best Practices/Unused Entities/UnusedStaticFunctions.ql
|
||||
@@ -1,2 +0,0 @@
|
||||
| unused_mut.c:5:13:5:31 | mut_unused_function | Static function mut_unused_function is unreachable ($@ must be removed at the same time) | unused_mut.c:9:13:9:32 | mut_unused_function2 | mut_unused_function2 |
|
||||
| unused_mut.c:9:13:9:32 | mut_unused_function2 | Static function mut_unused_function2 is unreachable ($@ must be removed at the same time) | unused_mut.c:5:13:5:31 | mut_unused_function | mut_unused_function |
|
||||
@@ -1 +0,0 @@
|
||||
Best Practices/Unused Entities/UnusedStaticFunctions.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.ql
|
||||
@@ -850,23 +850,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_13
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_13
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_15
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -847,23 +847,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~m198_13
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~m198_13
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_13
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_13
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_15
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -808,23 +808,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_3
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_3
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_3
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_13
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -808,23 +808,26 @@ ssa.cpp:
|
||||
# 199| r199_8(char *) = Convert : r199_7
|
||||
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
|
||||
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 199| m199_11(int) = Store : &:r199_1, r199_9
|
||||
# 199| v199_11(void) = ^BufferReadSideEffect[0] : &:r199_5, ~mu198_3
|
||||
# 199| v199_12(void) = ^BufferReadSideEffect[1] : &:r199_8, ~mu198_3
|
||||
# 199| m199_13(int) = Store : &:r199_1, r199_9
|
||||
# 200| r200_1(glval<unknown>) = FunctionAddress[strlen] :
|
||||
# 200| r200_2(glval<char *>) = VariableAddress[str1] :
|
||||
# 200| r200_3(char *) = Load : &:r200_2, m198_5
|
||||
# 200| r200_4(char *) = Convert : r200_3
|
||||
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4
|
||||
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3
|
||||
# 200| r200_7(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_8(int) = Load : &:r200_7, m199_11
|
||||
# 200| r200_9(int) = Add : r200_8, r200_5
|
||||
# 200| m200_10(int) = Store : &:r200_7, r200_9
|
||||
# 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_3
|
||||
# 200| r200_8(glval<int>) = VariableAddress[ret] :
|
||||
# 200| r200_9(int) = Load : &:r200_8, m199_13
|
||||
# 200| r200_10(int) = Add : r200_9, r200_5
|
||||
# 200| m200_11(int) = Store : &:r200_8, r200_10
|
||||
# 201| r201_1(glval<unknown>) = FunctionAddress[abs] :
|
||||
# 201| r201_2(glval<int>) = VariableAddress[x] :
|
||||
# 201| r201_3(int) = Load : &:r201_2, m198_13
|
||||
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3
|
||||
# 201| r201_5(glval<int>) = VariableAddress[ret] :
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_10
|
||||
# 201| r201_6(int) = Load : &:r201_5, m200_11
|
||||
# 201| r201_7(int) = Add : r201_6, r201_4
|
||||
# 201| m201_8(int) = Store : &:r201_5, r201_7
|
||||
# 202| r202_1(glval<int>) = VariableAddress[#return] :
|
||||
|
||||
@@ -108,7 +108,7 @@ instructionWithoutSuccessor
|
||||
| stmt_in_type.cpp:5:53:5:53 | Constant: 1 |
|
||||
| vla.c:5:9:5:14 | Uninitialized: definition of matrix |
|
||||
| vla.c:5:16:5:19 | Load: argc |
|
||||
| vla.c:5:22:5:25 | CallReadSideEffect: call to atoi |
|
||||
| vla.c:5:27:5:33 | BufferReadSideEffect: (const char *)... |
|
||||
| vla.c:11:6:11:16 | UnmodeledDefinition: vla_typedef |
|
||||
| vla.c:12:33:12:44 | Add: ... + ... |
|
||||
| vla.c:12:50:12:62 | Mul: ... * ... |
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
| unused_functions.c:16:13:16:27 | unused_function | Static function unused_function is unreachable | unused_functions.c:16:13:16:27 | unused_function | unused_function |
|
||||
| unused_functions.c:20:13:20:28 | unused_function2 | Static function unused_function2 is unreachable ($@ must be removed at the same time) | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:24:13:24:28 | unused_function3 | Static function unused_function3 is unreachable | unused_functions.c:24:13:24:28 | unused_function3 | unused_function3 |
|
||||
| unused_functions.c:63:13:63:14 | h4 | Static function h4 is unreachable | unused_functions.c:63:13:63:14 | h4 | h4 |
|
||||
| unused_mut.c:5:13:5:31 | mut_unused_function | Static function mut_unused_function is unreachable ($@ must be removed at the same time) | unused_mut.c:9:13:9:32 | mut_unused_function2 | mut_unused_function2 |
|
||||
| unused_mut.c:9:13:9:32 | mut_unused_function2 | Static function mut_unused_function2 is unreachable ($@ must be removed at the same time) | unused_mut.c:5:13:5:31 | mut_unused_function | mut_unused_function |
|
||||
| unused_static_functions.cpp:19:13:19:14 | f2 | Static function f2 is unreachable | unused_static_functions.cpp:19:13:19:14 | f2 | f2 |
|
||||
| unused_static_functions.cpp:33:13:33:14 | f5 | Static function f5 is unreachable ($@ must be removed at the same time) | unused_static_functions.cpp:34:13:34:14 | f6 | f6 |
|
||||
| unused_static_functions.cpp:34:13:34:14 | f6 | Static function f6 is unreachable ($@ must be removed at the same time) | unused_static_functions.cpp:33:13:33:14 | f5 | f5 |
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
| test2.c:28:19:28:20 | 41 | Potential buffer-overflow: 'buffer' has size 40 not 41. |
|
||||
| test2.c:29:26:29:27 | 43 | Potential buffer-overflow: 'buffer' has size 40 not 43. |
|
||||
| test2.c:31:26:31:27 | 44 | Potential buffer-overflow: 'buffer' has size 40 not 44. |
|
||||
| test2.c:32:25:32:26 | 45 | Potential buffer-overflow: 'buffer' has size 40 not 45. |
|
||||
| test2.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
|
||||
| test2.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
|
||||
| test2.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |
|
||||
| test.c:14:9:14:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[5]' is accessed here. |
|
||||
| test.c:15:9:15:13 | access to array | Potential buffer-overflow: 'xs' has size 5 but 'xs[6]' is accessed here. |
|
||||
| test.c:20:9:20:18 | access to array | Potential buffer-overflow: 'ys' has size 5 but 'ys[5]' is accessed here. |
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
| test.c:22:2:22:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.c:33:2:33:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:19:2:19:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:20:2:20:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:21:2:21:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
| test.c:28:3:28:12 | call to undeclared | Function call implicitly declares 'undeclared'. |
|
||||
| test.c:31:3:31:19 | call to not_yet_declared1 | Function call implicitly declares 'not_yet_declared1'. |
|
||||
| test.c:32:3:32:19 | call to not_yet_declared2 | Function call implicitly declares 'not_yet_declared2'. |
|
||||
| test.c:43:3:43:27 | call to not_declared_defined_with | Function call implicitly declares 'not_declared_defined_with'. |
|
||||
| test.c:54:3:54:21 | call to defined_with_double | Function call implicitly declares 'defined_with_double'. |
|
||||
| test.c:66:3:66:22 | call to defined_with_ptr_ptr | Function call implicitly declares 'defined_with_ptr_ptr'. |
|
||||
| test.c:68:3:68:22 | call to defined_with_ptr_arr | Function call implicitly declares 'defined_with_ptr_arr'. |
|
||||
| test.c:132:3:132:22 | call to implicit_declaration | Function call implicitly declares 'implicit_declaration'. |
|
||||
| test.c:133:3:133:30 | call to implicit_declaration_k_and_r | Function call implicitly declares 'implicit_declaration_k_and_r'. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql
|
||||
@@ -25,11 +25,11 @@ void test(int *argv[]) {
|
||||
declared_void(); // GOOD
|
||||
declared_with(1); // GOOD
|
||||
|
||||
undeclared(); // GOOD
|
||||
undeclared(); // BAD (GOOD for everything except cpp/implicit-function-declaration)
|
||||
undeclared(1); // GOOD
|
||||
|
||||
not_yet_declared1(1); // GOOD
|
||||
not_yet_declared2(1); // GOOD
|
||||
not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_yet_declared2(ca); // BAD
|
||||
not_yet_declared2(); // BAD
|
||||
|
||||
@@ -40,7 +40,7 @@ void test(int *argv[]) {
|
||||
declared_empty_defined_with(&x); // BAD
|
||||
declared_empty_defined_with(3, &x); // BAD
|
||||
|
||||
not_declared_defined_with(-1, 0, 2U); // GOOD
|
||||
not_declared_defined_with(-1, 0, 2U); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
not_declared_defined_with(4LL, 0, 2.5e9f); // BAD
|
||||
|
||||
declared_with_pointers(pv, ca); // GOOD
|
||||
@@ -51,7 +51,7 @@ void test(int *argv[]) {
|
||||
defined_with_float(2.f); // BAD
|
||||
defined_with_float(2.0); // BAD
|
||||
|
||||
defined_with_double(2.f); // GOOD
|
||||
defined_with_double(2.f); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_double('c'); // BAD
|
||||
|
||||
defined_with_long_long('c'); // BAD
|
||||
@@ -63,9 +63,9 @@ void test(int *argv[]) {
|
||||
k_and_r_func(2.5, &s); // GOOD
|
||||
|
||||
int (*parameterName)[2];
|
||||
defined_with_ptr_ptr(parameterName); // GOOD
|
||||
defined_with_ptr_ptr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_ptr_ptr(argv); // GOOD
|
||||
defined_with_ptr_arr(parameterName); // GOOD
|
||||
defined_with_ptr_arr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
|
||||
defined_with_ptr_arr(argv); // GOOD
|
||||
|
||||
declared_and_defined_empty(); // GOOD
|
||||
@@ -124,3 +124,15 @@ int call_k_and_r(int i) {
|
||||
int will_be_k_and_r(val)
|
||||
int val;
|
||||
{ return val + 1; }
|
||||
|
||||
extern int extern_definition(double, double*);
|
||||
|
||||
void test_implicit_function_declaration(int x, double d) {
|
||||
int y;
|
||||
implicit_declaration(1, 2); // BAD
|
||||
implicit_declaration_k_and_r(1, 2); // BAD
|
||||
|
||||
implicit_declaration(1, 2); // GOOD (no longer an implicit declaration)
|
||||
|
||||
y = extern_definition(3.0f, &d); // GOOD
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
void implicit_declaration(int x) {}
|
||||
|
||||
int implicit_declaration_k_and_r(x) int x;
|
||||
{
|
||||
return x;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
| test.c:28:19:28:20 | 41 | Potential buffer-overflow: 'buffer' has size 40 not 41. |
|
||||
| test.c:29:26:29:27 | 43 | Potential buffer-overflow: 'buffer' has size 40 not 43. |
|
||||
| test.c:31:26:31:27 | 44 | Potential buffer-overflow: 'buffer' has size 40 not 44. |
|
||||
| test.c:32:25:32:26 | 45 | Potential buffer-overflow: 'buffer' has size 40 not 45. |
|
||||
| test.c:33:26:33:27 | 46 | Potential buffer-overflow: 'buffer' has size 40 not 46. |
|
||||
| test.c:34:22:34:23 | 47 | Potential buffer-overflow: 'buffer' has size 40 not 47. |
|
||||
| test.c:35:23:35:24 | 48 | Potential buffer-overflow: 'buffer' has size 40 not 48. |
|
||||
@@ -1 +0,0 @@
|
||||
Critical/OverflowStatic.ql
|
||||
@@ -1,2 +0,0 @@
|
||||
| test.c:22:2:22:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.c:33:2:33:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
@@ -1,2 +0,0 @@
|
||||
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql
|
||||
|
||||
@@ -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. |
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user