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

@@ -8,6 +8,7 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------| |-----------------------------|-----------|--------------------------------------------------------------------|
| Implicit function declarations (`cpp/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql`) | correctness, maintainability | This query finds calls to undeclared functions that are compiled by a C compiler. Results are shown on LGTM by default. |
## Changes to existing queries ## Changes to existing queries
@@ -39,4 +40,4 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
* The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had * The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had
the following improvements: the following improvements:
* The library now models data flow through `strdup` and similar functions. * The library now models data flow through `strdup` and similar functions.
* The library now models data flow through formatting functions such as `sprintf`.

View File

@@ -14,6 +14,7 @@ The following changes in version 1.24 affect C# analysis in all applications.
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------| |------------------------------|------------------------|-----------------------------------|
| Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. | | Useless assignment to local variable (`cs/useless-assignment-to-local`) | Fewer false positive results | Results have been removed when the variable is named `_` in a `foreach` statement. |
| Dereferenced variable may be null (`cs/dereferenced-value-may-be-null`) | More results | Results are reported from parameters with a default value of `null`. |
## Removal of old queries ## Removal of old queries

View File

@@ -10,15 +10,25 @@ The following changes in version 1.24 affect Java analysis in all applications.
| **Query** | **Tags** | **Purpose** | | **Query** | **Tags** | **Purpose** |
|-----------------------------|-----------|--------------------------------------------------------------------| |-----------------------------|-----------|--------------------------------------------------------------------|
| Disabled Spring CSRF protection (`java/spring-disabled-csrf-protection`) | security, external/cwe/cwe-352 | Finds disabled Cross-Site Request Forgery (CSRF) protection in Spring. |
| Failure to use HTTPS or SFTP URL in Maven artifact upload/download (`java/maven/non-https-url`) | security, external/cwe/cwe-300, external/cwe/cwe-319, external/cwe/cwe-494, external/cwe/cwe-829 | Finds use of insecure protocols during Maven dependency resolution. Results are shown on LGTM by default. | | Failure to use HTTPS or SFTP URL in Maven artifact upload/download (`java/maven/non-https-url`) | security, external/cwe/cwe-300, external/cwe/cwe-319, external/cwe/cwe-494, external/cwe/cwe-829 | Finds use of insecure protocols during Maven dependency resolution. Results are shown on LGTM by default. |
| Left shift by more than the type width (`java/lshift-larger-than-type-width`) | correctness | Finds left shifts of ints by 32 bits or more and left shifts of longs by 64 bits or more. Results are shown on LGTM by default. |
| Suspicious date format (`java/suspicious-date-format`) | correctness | Finds date format patterns that use placeholders that are likely to be incorrect. |
## Changes to existing queries ## Changes to existing queries
| **Query** | **Expected impact** | **Change** | | **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------| |------------------------------|------------------------|-----------------------------------|
| Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Final fields with a non-null initializer are no longer reported. | | Dereferenced variable may be null (`java/dereferenced-value-may-be-null`) | Fewer false positives | Final fields with a non-null initializer are no longer reported. |
| Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. | | Expression always evaluates to the same value (`java/evaluation-to-constant`) | Fewer false positives | Expressions of the form `0 * x` are usually intended and no longer reported. Also left shift of ints by 32 bits and longs by 64 bits are no longer reported as they are not constant, these results are instead reported by the new query `java/lshift-larger-than-type-width`. |
| Useless null check (`java/useless-null-check`) | More true positives | Useless checks on final fields with a non-null initializer are now reported. | | Useless null check (`java/useless-null-check`) | More true positives | Useless checks on final fields with a non-null initializer are now reported. |
## Changes to libraries ## Changes to libraries
* Identification of test classes has been improved. Previously, one of the
match conditions would classify any class with a name containing the string
"Test" as a test class, but now this matching has been replaced with one that
looks for the occurrence of actual unit-test annotations. This affects the
general file classification mechanism and thus suppression of alerts, and
also any security queries using taint tracking, as test classes act as
default barriers stopping taint flow.

View File

@@ -13,6 +13,11 @@
- [react](https://www.npmjs.com/package/react) - [react](https://www.npmjs.com/package/react)
- [typeahead.js](https://www.npmjs.com/package/typeahead.js) - [typeahead.js](https://www.npmjs.com/package/typeahead.js)
- [Handlebars](https://www.npmjs.com/package/handlebars) - [Handlebars](https://www.npmjs.com/package/handlebars)
- [Electron](https://electronjs.org/)
- [Node.js](https://nodejs.org/)
- [Socket.IO](https://socket.io/)
- [ws](https://github.com/websockets/ws)
- [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
## New queries ## New queries
@@ -33,7 +38,9 @@
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. | | Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | This query now recognizes additional ways event handler receivers can be bound. |
| Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. | | Expression has no effect (`js/useless-expression`) | Fewer false positive results | The query now recognizes block-level flow type annotations and ignores the first statement of a try block. |
| Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. | | Use of call stack introspection in strict mode (`js/strict-mode-call-stack-introspection`) | Fewer false positive results | The query no longer flags expression statements. |
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | The query reports fewer duplicates and only flags handlers that explicitly access cookie data. |
## Changes to libraries ## Changes to libraries
* The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow. * The predicates `RegExpTerm.getSuccessor` and `RegExpTerm.getPredecessor` have been changed to reflect textual, not operational, matching order. This only makes a difference in lookbehind assertions, which are operationally matched backwards. Previously, `getSuccessor` would mimick this, so in an assertion `(?<=ab)` the term `b` would be considered the predecessor, not the successor, of `a`. Textually, however, `a` is still matched before `b`, and this is the order we now follow.
* An extensible model of the `EventEmitter` pattern has been implemented.

View File

@@ -18,6 +18,7 @@
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors

View File

@@ -19,6 +19,7 @@
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors
+ semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors

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 import cpp
import MistypedFunctionArguments
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)
}
from FunctionCall fc, Function f, Parameter p from FunctionCall fc, Function f, Parameter p
where where mistypedFunctionArguments(fc, f, 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)
select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(),
fc.getArgument(p.getIndex()) as arg, arg.toString(), fc.getArgument(p.getIndex()) as arg, arg.toString(),
arg.getExplicitlyConverted().getUnspecifiedType() as atype, atype.toString(), p, p.getTypedName() 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 import cpp
import TooFewArguments
// 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)
}
from FunctionCall fc, Function f from FunctionCall fc, Function f
where where tooFewArguments(fc, 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()
)
select fc, "This call has fewer arguments than required by $@.", f, f.toString() 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 import cpp
import TooManyArguments
// 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)
}
from FunctionCall fc, Function f from FunctionCall fc, Function f
where where tooManyArguments(fc, 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()
)
select fc, "This call has more arguments than required by $@.", f, f.toString() 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. * An `int` that is a parameter index for some function. This is needed for binding in certain cases.
*/ */
class ParameterIndex extends int { 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 DataFlowType = Type;
class DataFlowLocation = Location;
/** A function call relevant for data flow. */ /** A function call relevant for data flow. */
class DataFlowCall extends Expr { class DataFlowCall extends Expr {
DataFlowCall() { this instanceof Call } DataFlowCall() { this instanceof Call }

View File

@@ -68,9 +68,11 @@ predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeT
) )
or or
// Taint can flow through modeled functions // Taint can flow through modeled functions
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr())
or
exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument()) exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument())
or or
exprToExprStep(nodeFrom.asExpr(), nodeTo.asExpr()) exprToPartialDefinitionStep(nodeFrom.asExpr(), nodeTo.asPartialDefinition())
} }
/** /**
@@ -130,14 +132,24 @@ private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
// dest_ptr = strdup(tainted_ptr) // dest_ptr = strdup(tainted_ptr)
inModel.isParameterDeref(argInIndex) and inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex) exprIn = call.getArgument(argInIndex)
or
inModel.isParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
) )
) )
or or
exists(TaintFunction f, Call call, FunctionOutput outModel | exists(TaintFunction f, Call call, FunctionInput inModel, FunctionOutput outModel |
call.getTarget() = f and call.getTarget() = f and
(
exprOut = call and exprOut = call and
outModel.isReturnValueDeref() and outModel.isReturnValueDeref()
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) | or
exprOut = call and
outModel.isReturnValue()
) and
f.hasTaintFlow(inModel, outModel) and
(
exists(int argInIndex |
inModel.isParameterDeref(argInIndex) and inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex) exprIn = call.getArgument(argInIndex)
or or
@@ -147,6 +159,10 @@ private predicate exprToExprStep(Expr exprIn, Expr exprOut) {
inModel.isParameter(argInIndex) and inModel.isParameter(argInIndex) and
exprIn = call.getArgument(argInIndex) exprIn = call.getArgument(argInIndex)
) )
or
inModel.isQualifierObject() and
exprIn = call.getQualifier()
)
) )
} }
@@ -160,14 +176,46 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
// memcpy(&dest_var, tainted_ptr, len) // memcpy(&dest_var, tainted_ptr, len)
inModel.isParameterDeref(argInIndex) and inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex) exprIn = call.getArgument(argInIndex)
or
inModel.isParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
) )
) )
or 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 call.getTarget() = f and
argOut = call.getArgument(argOutIndex) and argOut = call.getArgument(argOutIndex) and
outModel.isParameterDeref(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 inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex) exprIn = call.getArgument(argInIndex)
or or

View File

@@ -21,33 +21,30 @@ private predicate predictableInstruction(Instruction instr) {
predictableInstruction(instr.(UnaryInstruction).getUnary()) predictableInstruction(instr.(UnaryInstruction).getUnary())
} }
private predicate userInputInstruction(Instruction instr) { private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
override predicate isSource(DataFlow::Node source) {
exists(CallInstruction ci, WriteSideEffectInstruction wsei | exists(CallInstruction ci, WriteSideEffectInstruction wsei |
userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and userInputArgument(ci.getConvertedResultExpression(), wsei.getIndex()) and
instr = wsei and source.asInstruction() = wsei and
wsei.getPrimaryInstruction() = ci wsei.getPrimaryInstruction() = ci
) )
or or
userInputReturned(instr.getConvertedResultExpression()) userInputReturned(source.asExpr())
or or
isUserInput(instr.getConvertedResultExpression(), _) isUserInput(source.asExpr(), _)
or or
instr.getConvertedResultExpression() instanceof EnvironmentRead source.asExpr() instanceof EnvironmentRead
or or
instr source
.asInstruction()
.(LoadInstruction) .(LoadInstruction)
.getSourceAddress() .getSourceAddress()
.(VariableAddressInstruction) .(VariableAddressInstruction)
.getASTVariable() .getASTVariable()
.hasName("argv") and .hasName("argv") and
instr.getEnclosingFunction().hasGlobalName("main") source.asInstruction().getEnclosingFunction().hasGlobalName("main")
}
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
DefaultTaintTrackingCfg() { this = "DefaultTaintTrackingCfg" }
override predicate isSource(DataFlow::Node source) {
userInputInstruction(source.asInstruction())
} }
override predicate isSink(DataFlow::Node sink) { any() } override predicate isSink(DataFlow::Node sink) { any() }

View File

@@ -83,10 +83,24 @@ private module VirtualDispatch {
) )
or or
// Flow through global variable // Flow through global variable
exists(StoreInstruction store, Variable var | exists(StoreInstruction store |
store = src.asInstruction() and store = src.asInstruction() and
(
exists(Variable var |
var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and var = store.getDestinationAddress().(VariableAddressInstruction).getASTVariable() and
this.flowsFromGlobal(var) 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 allowFromArg = true
) )
} }
@@ -97,6 +111,19 @@ private module VirtualDispatch {
load.getSourceAddress().(VariableAddressInstruction).getASTVariable() = var 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. */ /** Call through a function pointer. */

View File

@@ -139,12 +139,6 @@ abstract class Configuration extends string {
partialFlow(source, node, this) and partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 partialFlow(source, node, this) and
dist = node.getSourceDistance() 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 DataFlowType = Type;
class DataFlowLocation = Location;
/** A function call relevant for data flow. */ /** A function call relevant for data flow. */
class DataFlowCall extends CallInstruction { class DataFlowCall extends CallInstruction {
/** /**

View File

@@ -55,6 +55,9 @@ class Node extends TIRDataFlowNode {
*/ */
Expr asConvertedExpr() { result = instr.getConvertedResultExpression() } 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. */ /** Gets the parameter corresponding to this node, if any. */
Parameter asParameter() { result = instr.(InitializeParameterInstruction).getParameter() } 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. // Treat all conversions as flow, even conversions between different numeric types.
iTo.(ConvertInstruction).getUnary() = iFrom iTo.(ConvertInstruction).getUnary() = iFrom
or or
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom iTo.(InheritanceConversionInstruction).getUnary() = iFrom
or or
// A chi instruction represents a point where a new value (the _partial_ // 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 } ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
} }
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/** /**
* Represents an instruction that converts between two addresses * Represents an instruction that converts between two addresses
* related by inheritance. * related by inheritance.

View File

@@ -96,6 +96,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) )
or 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. // Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert | exists(ConvertToDerivedInstruction convert |
convert = instr and convert = instr and

View File

@@ -947,6 +947,10 @@ class ConvertInstruction extends UnaryInstruction {
ConvertInstruction() { getOpcode() instanceof Opcode::Convert } ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
} }
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/** /**
* Represents an instruction that converts between two addresses * Represents an instruction that converts between two addresses
* related by inheritance. * related by inheritance.

View File

@@ -947,6 +947,10 @@ class ConvertInstruction extends UnaryInstruction {
ConvertInstruction() { getOpcode() instanceof Opcode::Convert } ConvertInstruction() { getOpcode() instanceof Opcode::Convert }
} }
class CheckedConvertOrNullInstruction extends UnaryInstruction {
CheckedConvertOrNullInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrNull }
}
/** /**
* Represents an instruction that converts between two addresses * Represents an instruction that converts between two addresses
* related by inheritance. * related by inheritance.

View File

@@ -96,6 +96,10 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) {
bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8) bitOffset = Ints::mul(convert.getDerivation().getByteOffset(), 8)
) )
or 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. // Converting to a derived class subtracts the offset of the base class.
exists(ConvertToDerivedInstruction convert | exists(ConvertToDerivedInstruction convert |
convert = instr and convert = instr and

View File

@@ -83,6 +83,11 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
override predicate hasOnlySpecificReadSideEffects() { none() } override predicate hasOnlySpecificReadSideEffects() { none() }
override predicate hasOnlySpecificWriteSideEffects() { any() } override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
getParameter(i).getUnspecifiedType() instanceof PointerType and
buffer = true
}
} }
class PureFunction extends TaintFunction, SideEffectFunction { class PureFunction extends TaintFunction, SideEffectFunction {

View File

@@ -47,20 +47,11 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
} }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { 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 input.isParameterDeref(1) and
output.isParameterDeref(0) output.isParameterDeref(0)
or or
input.isParameterDeref(1) and input.isParameterDeref(1) and
output.isReturnValueDeref() output.isReturnValueDeref()
)
or or
input.isParameter(0) and input.isParameter(0) and
output.isReturnValue() output.isReturnValue()
@@ -77,10 +68,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
this.hasName("wcsncpy") or this.hasName("wcsncpy") or
this.hasName("_wcsncpy_l") this.hasName("_wcsncpy_l")
) and ) and
( input.isParameter(2) and
input.isParameter(2) or
input.isParameterDeref(1)
) and
( (
output.isParameterDeref(0) or output.isParameterDeref(0) or
output.isReturnValueDeref() output.isReturnValueDeref()

View File

@@ -9,17 +9,14 @@ import semmle.code.cpp.models.interfaces.Taint
class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction { class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
StrdupFunction() { StrdupFunction() {
exists(string name | exists(string name |
hasGlobalOrStdName(name) and hasGlobalName(name) and
( (
// strdup(str) // strdup(str)
name = "strdup" name = "strdup"
or or
// wcsdup(str) // wcsdup(str)
name = "wcsdup" name = "wcsdup"
)
or or
hasGlobalName(name) and
(
// _strdup(str) // _strdup(str)
name = "_strdup" name = "_strdup"
or or
@@ -37,9 +34,32 @@ class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 } override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) { 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 input.isParameterDeref(0) and
output.isReturnValueDeref() 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 import semmle.code.cpp.models.Models
/** /**
* A library function for which a value is copied from a parameter or qualifier * A library function for which a value is or may be copied from a parameter
* to an output buffer, return value, or qualifier. * or qualifier to an output buffer, return value, or qualifier.
* *
* Note that this does not include partial copying of values or partial writes * Note that this does not include partial copying of values or partial writes
* to destinations; that is covered by `TaintModel.qll`. * to destinations; that is covered by `TaintModel.qll`.

View File

@@ -6,7 +6,8 @@
* `FormattingFunction` to match the flow within that function. * `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) { private Type stripTopLevelSpecifiersOnly(Type t) {
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType()) result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
@@ -39,7 +40,7 @@ private Type getAFormatterWideTypeOrDefault() {
/** /**
* A standard library function that uses a `printf`-like formatting string. * 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. */ /** Gets the position at which the format parameter occurs. */
abstract int getFormatParameterIndex(); abstract int getFormatParameterIndex();
@@ -133,4 +134,33 @@ abstract class FormattingFunction extends Function {
* Gets the position of the buffer size argument, if any. * Gets the position of the buffer size argument, if any.
*/ */
int getSizeParameterIndex() { none() } 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. * 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 * 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 class TaintFunction extends Function {
abstract predicate hasTaintFlow(FunctionInput input, FunctionOutput output); 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); void sink(int);
int main(int argc, char *argv[]) { 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")));
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); inet_addr_retval a = inet_addr((const char *)&env_pointer);
sink(a); 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: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: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: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: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: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 | 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: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: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: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: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: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 | 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: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:32 | call to getenv |
| defaulttainttracking.cpp:18:27:18:32 | call to getenv | defaulttainttracking.cpp:18:27:18:39 | (const char *)... | | 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: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: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 | 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: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:11:38:21 | env_pointer |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv | | 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: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:39:50:39:61 | & ... |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a | | 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] 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: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: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: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: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:18:8:18:8 | AST only |
| lambdas.cpp:8:10:8:15 | lambdas.cpp:21:3:21:6 | 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: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: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: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 | | 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: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 | | 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 cpp
import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.Taint
/** Common data flow configuration to be used by tests. */ /** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends TaintTracking::Configuration { class TestAllocationConfig extends TaintTracking::Configuration {
@@ -25,3 +26,39 @@ class TestAllocationConfig extends TaintTracking::Configuration {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer") 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 | | | 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: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:5:8:5:13 | clean1 | |
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | 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: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:371:2:371:25 | ... = ... | |
| taint.cpp:371:6:371:12 | call to strndup | taint.cpp:374:7:374:7 | c | | | 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: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:381:2:381:36 | ... = ... | |
| taint.cpp:381:6:381:12 | call to strndup | taint.cpp:382:7:382:7 | a | | | 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: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:389:2:389:19 | ... = ... | |
| taint.cpp:389:6:389:11 | call to wcsdup | taint.cpp:391:7:391:7 | a | | | 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:390:2:390:28 | ... = ... | |
| taint.cpp:390:6:390:11 | call to wcsdup | taint.cpp:392:7:392:7 | b | | | 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: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); c = strndup(source, 100);
sink(a); // tainted sink(a); // tainted
sink(b); sink(b);
sink(c); // tainted [NOT DETECTED] sink(c); // tainted
} }
void test_strndup(int source) void test_strndup(int source)
@@ -379,7 +379,7 @@ void test_strndup(int source)
char *a; char *a;
a = strndup("hello, world", source); a = strndup("hello, world", source);
sink(a); sink(a); // tainted
} }
void test_wcsdup(wchar_t *source) void test_wcsdup(wchar_t *source)
@@ -391,3 +391,58 @@ void test_wcsdup(wchar_t *source)
sink(a); // tainted sink(a); // tainted
sink(b); 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: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: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 | | 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: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: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: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: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: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: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 | | 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: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: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: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: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: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: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: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_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_13 # 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_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_3(char *) = Load : &:r200_2, m198_5
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_13 # 200| v200_6(void) = ^CallReadSideEffect : ~m198_13
# 200| r200_7(glval<int>) = VariableAddress[ret] : # 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_13
# 200| r200_8(int) = Load : &:r200_7, m199_11 # 200| r200_8(glval<int>) = VariableAddress[ret] :
# 200| r200_9(int) = Add : r200_8, r200_5 # 200| r200_9(int) = Load : &:r200_8, m199_13
# 200| m200_10(int) = Store : &:r200_7, r200_9 # 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_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_3(int) = Load : &:r201_2, m198_15
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

@@ -847,23 +847,26 @@ ssa.cpp:
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~m198_13 # 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_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_3(char *) = Load : &:r200_2, m198_5
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~m198_13 # 200| v200_6(void) = ^CallReadSideEffect : ~m198_13
# 200| r200_7(glval<int>) = VariableAddress[ret] : # 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~m198_13
# 200| r200_8(int) = Load : &:r200_7, m199_11 # 200| r200_8(glval<int>) = VariableAddress[ret] :
# 200| r200_9(int) = Add : r200_8, r200_5 # 200| r200_9(int) = Load : &:r200_8, m199_13
# 200| m200_10(int) = Store : &:r200_7, r200_9 # 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_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_15 # 201| r201_3(int) = Load : &:r201_2, m198_15
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

@@ -808,23 +808,26 @@ ssa.cpp:
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_3 # 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_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_3(char *) = Load : &:r200_2, m198_5
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3 # 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3
# 200| r200_7(glval<int>) = VariableAddress[ret] : # 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_3
# 200| r200_8(int) = Load : &:r200_7, m199_11 # 200| r200_8(glval<int>) = VariableAddress[ret] :
# 200| r200_9(int) = Add : r200_8, r200_5 # 200| r200_9(int) = Load : &:r200_8, m199_13
# 200| m200_10(int) = Store : &:r200_7, r200_9 # 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_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_3(int) = Load : &:r201_2, m198_13
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

@@ -808,23 +808,26 @@ ssa.cpp:
# 199| r199_8(char *) = Convert : r199_7 # 199| r199_8(char *) = Convert : r199_7
# 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8 # 199| r199_9(int) = Call : func:r199_2, 0:r199_5, 1:r199_8
# 199| v199_10(void) = ^CallReadSideEffect : ~mu198_3 # 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_1(glval<unknown>) = FunctionAddress[strlen] :
# 200| r200_2(glval<char *>) = VariableAddress[str1] : # 200| r200_2(glval<char *>) = VariableAddress[str1] :
# 200| r200_3(char *) = Load : &:r200_2, m198_5 # 200| r200_3(char *) = Load : &:r200_2, m198_5
# 200| r200_4(char *) = Convert : r200_3 # 200| r200_4(char *) = Convert : r200_3
# 200| r200_5(int) = Call : func:r200_1, 0:r200_4 # 200| r200_5(int) = Call : func:r200_1, 0:r200_4
# 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3 # 200| v200_6(void) = ^CallReadSideEffect : ~mu198_3
# 200| r200_7(glval<int>) = VariableAddress[ret] : # 200| v200_7(void) = ^BufferReadSideEffect[0] : &:r200_4, ~mu198_3
# 200| r200_8(int) = Load : &:r200_7, m199_11 # 200| r200_8(glval<int>) = VariableAddress[ret] :
# 200| r200_9(int) = Add : r200_8, r200_5 # 200| r200_9(int) = Load : &:r200_8, m199_13
# 200| m200_10(int) = Store : &:r200_7, r200_9 # 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_1(glval<unknown>) = FunctionAddress[abs] :
# 201| r201_2(glval<int>) = VariableAddress[x] : # 201| r201_2(glval<int>) = VariableAddress[x] :
# 201| r201_3(int) = Load : &:r201_2, m198_13 # 201| r201_3(int) = Load : &:r201_2, m198_13
# 201| r201_4(int) = Call : func:r201_1, 0:r201_3 # 201| r201_4(int) = Call : func:r201_1, 0:r201_3
# 201| r201_5(glval<int>) = VariableAddress[ret] : # 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| r201_7(int) = Add : r201_6, r201_4
# 201| m201_8(int) = Store : &:r201_5, r201_7 # 201| m201_8(int) = Store : &:r201_5, r201_7
# 202| r202_1(glval<int>) = VariableAddress[#return] : # 202| r202_1(glval<int>) = VariableAddress[#return] :

View File

@@ -108,7 +108,7 @@ instructionWithoutSuccessor
| stmt_in_type.cpp:5:53:5:53 | Constant: 1 | | stmt_in_type.cpp:5:53:5:53 | Constant: 1 |
| vla.c:5:9:5:14 | Uninitialized: definition of matrix | | vla.c:5:9:5:14 | Uninitialized: definition of matrix |
| vla.c:5:16:5:19 | Load: argc | | 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:11:6:11:16 | UnmodeledDefinition: vla_typedef |
| vla.c:12:33:12:44 | Add: ... + ... | | vla.c:12:33:12:44 | Add: ... + ... |
| vla.c:12:50:12:62 | Mul: ... * ... | | 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: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: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 | | 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: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: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. | | 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: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: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. | | 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_void(); // GOOD
declared_with(1); // GOOD declared_with(1); // GOOD
undeclared(); // GOOD undeclared(); // BAD (GOOD for everything except cpp/implicit-function-declaration)
undeclared(1); // GOOD undeclared(1); // GOOD
not_yet_declared1(1); // GOOD not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
not_yet_declared2(1); // GOOD not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
not_yet_declared2(ca); // BAD not_yet_declared2(ca); // BAD
not_yet_declared2(); // BAD not_yet_declared2(); // BAD
@@ -40,7 +40,7 @@ void test(int *argv[]) {
declared_empty_defined_with(&x); // BAD declared_empty_defined_with(&x); // BAD
declared_empty_defined_with(3, &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 not_declared_defined_with(4LL, 0, 2.5e9f); // BAD
declared_with_pointers(pv, ca); // GOOD declared_with_pointers(pv, ca); // GOOD
@@ -51,7 +51,7 @@ void test(int *argv[]) {
defined_with_float(2.f); // BAD defined_with_float(2.f); // BAD
defined_with_float(2.0); // 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_double('c'); // BAD
defined_with_long_long('c'); // BAD defined_with_long_long('c'); // BAD
@@ -63,9 +63,9 @@ void test(int *argv[]) {
k_and_r_func(2.5, &s); // GOOD k_and_r_func(2.5, &s); // GOOD
int (*parameterName)[2]; 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_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 defined_with_ptr_arr(argv); // GOOD
declared_and_defined_empty(); // 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 will_be_k_and_r(val)
int val; int val;
{ return val + 1; } { 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. |

Some files were not shown because too many files have changed in this diff Show More