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:
Jonas Jensen
2020-01-29 13:03:40 +01:00
265 changed files with 5712 additions and 13687 deletions

View File

@@ -0,0 +1,8 @@
/* '#include <stdlib.h>' was forgotton */
int main(void) {
/* 'int malloc()' assumed */
unsigned char *p = malloc(100);
*p = 'a';
return 0;
}

View File

@@ -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>

View File

@@ -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() + "'."

View File

@@ -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()

View File

@@ -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)
}

View File

@@ -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()

View File

@@ -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()
)
}

View File

@@ -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()

View File

@@ -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()
)
}

View File

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

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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 }

View File

@@ -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

View File

@@ -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() }

View File

@@ -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. */

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -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) }
}
/**

View File

@@ -191,8 +191,6 @@ class DataFlowExpr = Expr;
class DataFlowType = Type;
class DataFlowLocation = Location;
/** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction {
/**

View File

@@ -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_

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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 {

View File

@@ -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()

View File

@@ -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()
}
}

View File

@@ -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`.

View File

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

View File

@@ -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);

View File

@@ -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 |

View File

@@ -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(), ", ")

View File

@@ -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;
}

View File

@@ -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 |

View File

@@ -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(), ", ")

View File

@@ -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]
}

View File

@@ -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 |

View File

@@ -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]
}

View File

@@ -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 |

View File

@@ -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

View File

@@ -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]
}

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 *)... | |

View File

@@ -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

View 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 *));
}

View File

@@ -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()
}
}

View File

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

View File

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

View File

@@ -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
}

View File

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

View File

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

View File

@@ -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 |

View File

@@ -1 +0,0 @@
| Test for deprecated library StackVariableReachability. |

View File

@@ -1,4 +0,0 @@
import cpp
import semmle.code.cpp.controlflow.StackVariableReachability
select "Test for deprecated library StackVariableReachability."

View File

@@ -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 |

View File

@@ -1 +0,0 @@
Best Practices/Unused Entities/UnusedStaticFunctions.ql

View File

@@ -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 |

View File

@@ -1 +0,0 @@
Best Practices/Unused Entities/UnusedStaticFunctions.ql

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.ql

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.ql

View File

@@ -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] :

View File

@@ -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] :

View File

@@ -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] :

View File

@@ -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] :

View File

@@ -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: ... * ... |

View File

@@ -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 |

View File

@@ -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. |

View File

@@ -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. |

View File

@@ -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'. |

View File

@@ -0,0 +1 @@
Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql

View File

@@ -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
}

View File

@@ -0,0 +1,6 @@
void implicit_declaration(int x) {}
int implicit_declaration_k_and_r(x) int x;
{
return x;
}

View File

@@ -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. |

View File

@@ -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. |

View File

@@ -1,2 +0,0 @@
Likely Bugs/Memory Management/StrncpyFlippedArgs.ql

View File

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

View File

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