Merge branch 'main' into modelclasses

This commit is contained in:
Geoffrey White
2021-01-08 17:11:25 +00:00
940 changed files with 112831 additions and 64625 deletions

View File

@@ -0,0 +1,4 @@
lgtm,codescanning
* `FormattingFunction.getOutputParameterIndex` now has a parameter identifying whether the output at that index is a buffer or a stream.
* `FormattingFunction` now has a predicate `isOutputGlobal` indicating when the output is to a global stream.
* The `primitiveVariadicFormatter` and `variadicFormatter` predicates have more parameters exposing information about the function.

View File

@@ -8,168 +8,41 @@ import semmle.code.cpp.AutogeneratedFile
predicate trivialPositiveIntValue(string s) {
// Small numbers
s = [0 .. 20].toString() or
// Popular powers of two (decimal)
s = "16" or
s = "24" or
s = "32" or
s = "64" or
s = "128" or
s = "256" or
s = "512" or
s = "1024" or
s = "2048" or
s = "4096" or
s = "16384" or
s = "32768" or
s = "65536" or
s = "1048576" or
s = "2147483648" or
s = "4294967296" or
// Popular powers of two, minus one (decimal)
s = "15" or
s = "31" or
s = "63" or
s = "127" or
s = "255" or
s = "511" or
s = "1023" or
s = "2047" or
s = "4095" or
s = "16383" or
s = "32767" or
s = "65535" or
s = "1048577" or
s = "2147483647" or
s = "4294967295" or
// Popular powers of two (32-bit hex)
s = "0x00000001" or
s = "0x00000002" or
s = "0x00000004" or
s = "0x00000008" or
s = "0x00000010" or
s = "0x00000020" or
s = "0x00000040" or
s = "0x00000080" or
s = "0x00000100" or
s = "0x00000200" or
s = "0x00000400" or
s = "0x00000800" or
s = "0x00001000" or
s = "0x00002000" or
s = "0x00004000" or
s = "0x00008000" or
s = "0x00010000" or
s = "0x00020000" or
s = "0x00040000" or
s = "0x00080000" or
s = "0x00100000" or
s = "0x00200000" or
s = "0x00400000" or
s = "0x00800000" or
s = "0x01000000" or
s = "0x02000000" or
s = "0x04000000" or
s = "0x08000000" or
s = "0x10000000" or
s = "0x20000000" or
s = "0x40000000" or
s = "0x80000000" or
// Popular powers of two, minus one (32-bit hex)
s = "0x00000001" or
s = "0x00000003" or
s = "0x00000007" or
s = "0x0000000f" or
s = "0x0000001f" or
s = "0x0000003f" or
s = "0x0000007f" or
s = "0x000000ff" or
s = "0x000001ff" or
s = "0x000003ff" or
s = "0x000007ff" or
s = "0x00000fff" or
s = "0x00001fff" or
s = "0x00003fff" or
s = "0x00007fff" or
s = "0x0000ffff" or
s = "0x0001ffff" or
s = "0x0003ffff" or
s = "0x0007ffff" or
s = "0x000fffff" or
s = "0x001fffff" or
s = "0x003fffff" or
s = "0x007fffff" or
s = "0x00ffffff" or
s = "0x01ffffff" or
s = "0x03ffffff" or
s = "0x07ffffff" or
s = "0x0fffffff" or
s = "0x1fffffff" or
s = "0x3fffffff" or
s = "0x7fffffff" or
s = "0xffffffff" or
// Popular powers of two (16-bit hex)
s = "0x0001" or
s = "0x0002" or
s = "0x0004" or
s = "0x0008" or
s = "0x0010" or
s = "0x0020" or
s = "0x0040" or
s = "0x0080" or
s = "0x0100" or
s = "0x0200" or
s = "0x0400" or
s = "0x0800" or
s = "0x1000" or
s = "0x2000" or
s = "0x4000" or
s = "0x8000" or
// Popular powers of two, minus one (16-bit hex)
s = "0x0001" or
s = "0x0003" or
s = "0x0007" or
s = "0x000f" or
s = "0x001f" or
s = "0x003f" or
s = "0x007f" or
s = "0x00ff" or
s = "0x01ff" or
s = "0x03ff" or
s = "0x07ff" or
s = "0x0fff" or
s = "0x1fff" or
s = "0x3fff" or
s = "0x7fff" or
s = "0xffff" or
// Popular powers of two (8-bit hex)
s = "0x01" or
s = "0x02" or
s = "0x04" or
s = "0x08" or
s = "0x10" or
s = "0x20" or
s = "0x40" or
s = "0x80" or
// Popular powers of two, minus one (8-bit hex)
s = "0x01" or
s = "0x03" or
s = "0x07" or
s = "0x0f" or
s = "0x1f" or
s = "0x3f" or
s = "0x7f" or
s = "0xff" or
s = "0x00" or
// Powers of ten
s = "10" or
s = "100" or
s = "1000" or
s = "10000" or
s = "100000" or
s = "1000000" or
s = "10000000" or
s = "100000000" or
s = "1000000000"
s =
[
// Popular powers of two (decimal)
"16", "24", "32", "64", "128", "256", "512", "1024", "2048", "4096", "16384", "32768",
"65536", "1048576", "2147483648", "4294967296",
// Popular powers of two, minus one (decimal)
"15", "31", "63", "127", "255", "511", "1023", "2047", "4095", "16383", "32767", "65535",
"1048577", "2147483647", "4294967295",
// Popular powers of two (32-bit hex)
"0x00000001", "0x00000002", "0x00000004", "0x00000008", "0x00000010", "0x00000020",
"0x00000040", "0x00000080", "0x00000100", "0x00000200", "0x00000400", "0x00000800",
"0x00001000", "0x00002000", "0x00004000", "0x00008000", "0x00010000", "0x00020000",
"0x00040000", "0x00080000", "0x00100000", "0x00200000", "0x00400000", "0x00800000",
"0x01000000", "0x02000000", "0x04000000", "0x08000000", "0x10000000", "0x20000000",
"0x40000000", "0x80000000",
// Popular powers of two, minus one (32-bit hex)
"0x00000001", "0x00000003", "0x00000007", "0x0000000f", "0x0000001f", "0x0000003f",
"0x0000007f", "0x000000ff", "0x000001ff", "0x000003ff", "0x000007ff", "0x00000fff",
"0x00001fff", "0x00003fff", "0x00007fff", "0x0000ffff", "0x0001ffff", "0x0003ffff",
"0x0007ffff", "0x000fffff", "0x001fffff", "0x003fffff", "0x007fffff", "0x00ffffff",
"0x01ffffff", "0x03ffffff", "0x07ffffff", "0x0fffffff", "0x1fffffff", "0x3fffffff",
"0x7fffffff", "0xffffffff",
// Popular powers of two (16-bit hex)
"0x0001", "0x0002", "0x0004", "0x0008", "0x0010", "0x0020", "0x0040", "0x0080", "0x0100",
"0x0200", "0x0400", "0x0800", "0x1000", "0x2000", "0x4000", "0x8000",
// Popular powers of two, minus one (16-bit hex)
"0x0001", "0x0003", "0x0007", "0x000f", "0x001f", "0x003f", "0x007f", "0x00ff", "0x01ff",
"0x03ff", "0x07ff", "0x0fff", "0x1fff", "0x3fff", "0x7fff", "0xffff",
// Popular powers of two (8-bit hex)
"0x01", "0x02", "0x04", "0x08", "0x10", "0x20", "0x40", "0x80",
// Popular powers of two, minus one (8-bit hex)
"0x01", "0x03", "0x07", "0x0f", "0x1f", "0x3f", "0x7f", "0xff", "0x00",
// Powers of ten
"10", "100", "1000", "10000", "100000", "1000000", "10000000", "100000000", "1000000000"
]
}
predicate trivialIntValue(string s) {
@@ -235,10 +108,7 @@ predicate joiningStringTrivial(Literal lit) {
// understand (which is against the spirit of these queries).
stringLiteral(lit) and
exists(FunctionCall fc |
(
fc.getTarget().getName() = "operator+" or
fc.getTarget().getName() = "operator<<"
) and
fc.getTarget().getName() = ["operator+", "operator<<"] and
fc.getAnArgument().getAChild*() = lit
) and
lit.getValue().length() < 16
@@ -291,8 +161,7 @@ predicate arrayInitializerChild(AggregateLiteral parent, Expr e) {
// i.e. not a constant folded expression
predicate literallyLiteral(Literal lit) {
lit
.getValueText()
lit.getValueText()
.regexpMatch(".*\".*|\\s*+[-+]?+\\s*+(0[xob][0-9a-fA-F]|[0-9])[0-9a-fA-F,._]*+([eE][-+]?+[0-9,._]*+)?+\\s*+[a-zA-Z]*+\\s*+")
}

View File

@@ -59,14 +59,9 @@ class Options extends string {
predicate exits(Function f) {
f.getAnAttribute().hasName("noreturn")
or
exists(string name | f.hasGlobalOrStdName(name) |
name = "exit" or
name = "_exit" or
name = "abort" or
name = "__assert_fail" or
name = "longjmp" or
name = "__builtin_unreachable"
)
f.hasGlobalOrStdName([
"exit", "_exit", "abort", "__assert_fail", "longjmp", "__builtin_unreachable"
])
or
CustomOptions::exits(f) // old Options.qll
}

View File

@@ -21,15 +21,7 @@ class Initialization extends Function {
}
class Allocation extends FunctionCall {
Allocation() {
exists(string name | name = this.getTarget().getName() |
name = "malloc" or
name = "calloc" or
name = "alloca" or
name = "sbrk" or
name = "valloc"
)
}
Allocation() { this.getTarget().getName() = ["malloc", "calloc", "alloca", "sbrk", "valloc"] }
}
from Function f, Allocation a

View File

@@ -13,13 +13,8 @@ import cpp
class ForbiddenCall extends FunctionCall {
ForbiddenCall() {
exists(string name | name = this.getTarget().getName() |
name = "task_delay" or
name = "taskDelay" or
name = "sleep" or
name = "nanosleep" or
name = "clock_nanosleep"
)
this.getTarget().getName() =
["task_delay", "taskDelay", "sleep", "nanosleep", "clock_nanosleep"]
}
}

View File

@@ -6,12 +6,7 @@ import cpp
class SemaphoreCreation extends FunctionCall {
SemaphoreCreation() {
exists(string name | name = this.getTarget().getName() |
name = "semBCreate" or
name = "semMCreate" or
name = "semCCreate" or
name = "semRWCreate"
)
this.getTarget().getName() = ["semBCreate", "semMCreate", "semCCreate", "semRWCreate"]
}
Variable getSemaphore() { result.getAnAccess() = this.getParent().(Assignment).getLValue() }
@@ -72,11 +67,7 @@ class SemaphoreGive extends UnlockOperation {
}
class LockingPrimitive extends FunctionCall, LockOperation {
LockingPrimitive() {
exists(string name | name = this.getTarget().getName() |
name = "taskLock" or name = "intLock" or name = "taskRtpLock"
)
}
LockingPrimitive() { this.getTarget().getName() = ["taskLock", "intLock", "taskRtpLock"] }
override Function getLocked() { result = this.getTarget() }
@@ -89,11 +80,7 @@ class LockingPrimitive extends FunctionCall, LockOperation {
}
class UnlockingPrimitive extends FunctionCall, UnlockOperation {
UnlockingPrimitive() {
exists(string name | name = this.getTarget().getName() |
name = "taskUnlock" or name = "intUnlock" or name = "taskRtpUnlock"
)
}
UnlockingPrimitive() { this.getTarget().getName() = ["taskUnlock", "intUnlock", "taskRtpUnlock"] }
Function getLocked() { result = getMatchingLock().getLocked() }

View File

@@ -12,18 +12,7 @@
import cpp
predicate allowedTypedefs(TypedefType t) {
exists(string name | name = t.getName() |
name = "I64" or
name = "U64" or
name = "I32" or
name = "U32" or
name = "I16" or
name = "U16" or
name = "I8" or
name = "U8" or
name = "F64" or
name = "F32"
)
t.getName() = ["I64", "U64", "I32", "U32", "I16", "U16", "I8", "U8", "F64", "F32"]
}
/**

View File

@@ -5,8 +5,8 @@ import cpp
*/
class Task extends Function {
Task() {
exists(FunctionCall taskCreate, string name | name = "taskCreate" or name = "taskSpawn" |
name = taskCreate.getTarget().getName() and
exists(FunctionCall taskCreate |
taskCreate.getTarget().getName() = ["taskCreate", "taskSpawn"] and
this = taskCreate.getArgument(4).(AddressOfExpr).getAddressable()
)
}

View File

@@ -13,38 +13,17 @@ import cpp
import semmle.code.cpp.dataflow.DataFlow
predicate whitelist(Function f) {
exists(string fName |
fName = f.getName() and
(
fName = "ceil" or
fName = "ceilf" or
fName = "ceill" or
fName = "floor" or
fName = "floorf" or
fName = "floorl" or
fName = "nearbyint" or
fName = "nearbyintf" or
fName = "nearbyintl" or
fName = "rint" or
fName = "rintf" or
fName = "rintl" or
fName = "round" or
fName = "roundf" or
fName = "roundl" or
fName = "trunc" or
fName = "truncf" or
fName = "truncl" or
fName.matches("__builtin_%")
)
)
f.getName() =
[
"ceil", "ceilf", "ceill", "floor", "floorf", "floorl", "nearbyint", "nearbyintf",
"nearbyintl", "rint", "rintf", "rintl", "round", "roundf", "roundl", "trunc", "truncf",
"truncl"
] or
f.getName().matches("__builtin_%")
}
predicate whitelistPow(FunctionCall fc) {
(
fc.getTarget().getName() = "pow" or
fc.getTarget().getName() = "powf" or
fc.getTarget().getName() = "powl"
) and
fc.getTarget().getName() = ["pow", "powf", "powl"] and
exists(float value |
value = fc.getArgument(0).getValue().toFloat() and
(value.floor() - value).abs() < 0.001

View File

@@ -29,6 +29,8 @@ class QueryString extends EnvironmentRead {
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSource(Expr source) { source instanceof QueryString }
override predicate isSink(Element tainted) {
exists(PrintStdoutCall call | call.getAnArgument() = tainted)
}

View File

@@ -34,6 +34,10 @@ predicate sqlite_encryption_used() {
}
class Configuration extends TaintTrackingConfiguration {
override predicate isSource(Expr source) {
super.isSource(source) and source instanceof SensitiveExpr
}
override predicate isSink(Element taintedArg) {
exists(SqliteFunctionCall sqliteCall |
taintedArg = sqliteCall.getASource() and

View File

@@ -189,8 +189,7 @@ class InitializationFunction extends Function {
// Field wise assignment to the parameter
any(Assignment e).getLValue() = getAFieldAccess(this.getParameter(i)) or
i =
this
.(MemberFunction)
this.(MemberFunction)
.getAnOverridingFunction+()
.(InitializationFunction)
.initializedParameter() or
@@ -327,52 +326,35 @@ class InitializationFunction extends Function {
// Return value is not a success code but the output functions never fail.
name.matches("_Interlocked%")
or
// Functions that never fail, according to MSDN.
name = "QueryPerformanceCounter"
or
name = "QueryPerformanceFrequency"
or
// Functions that never fail post-Vista, according to MSDN.
name = "InitializeCriticalSectionAndSpinCount"
or
// `rand_s` writes 0 to a non-null argument if it fails, according to MSDN.
name = "rand_s"
or
// IntersectRect initializes the argument regardless of whether the input intersects
name = "IntersectRect"
or
name = "SetRect"
or
name = "UnionRect"
or
// These functions appears to have an incorrect CFG, which leads to false positives
name = "PhysicalToLogicalDPIPoint"
or
name = "LogicalToPhysicalDPIPoint"
or
// Sets NtProductType to default on error
name = "RtlGetNtProductType"
or
// Our CFG is not sophisticated enough to detect that the argument is always initialized
name = "StringCchLengthA"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlMultiByteToUnicodeSize"
or
// All paths init the argument, and always returns SUCCESS.
name = "RtlUnicodeToMultiByteN"
or
// Always initializes argument
name = "RtlGetFirstRange"
or
// Destination range is zeroed out on failure, assuming first two parameters are valid
name = "memcpy_s"
or
// This zeroes the memory unconditionally
name = "SeCreateAccessState"
name =
[
// Functions that never fail, according to MSDN.
"QueryPerformanceCounter", "QueryPerformanceFrequency",
// Functions that never fail post-Vista, according to MSDN.
"InitializeCriticalSectionAndSpinCount",
// `rand_s` writes 0 to a non-null argument if it fails, according to MSDN.
"rand_s",
// IntersectRect initializes the argument regardless of whether the input intersects
"IntersectRect", "SetRect", "UnionRect",
// These functions appears to have an incorrect CFG, which leads to false positives
"PhysicalToLogicalDPIPoint", "LogicalToPhysicalDPIPoint",
// Sets NtProductType to default on error
"RtlGetNtProductType",
// Our CFG is not sophisticated enough to detect that the argument is always initialized
"StringCchLengthA",
// All paths init the argument, and always returns SUCCESS.
"RtlUnicodeToMultiByteSize",
// All paths init the argument, and always returns SUCCESS.
"RtlMultiByteToUnicodeSize",
// All paths init the argument, and always returns SUCCESS.
"RtlUnicodeToMultiByteN",
// Always initializes argument
"RtlGetFirstRange",
// Destination range is zeroed out on failure, assuming first two parameters are valid
"memcpy_s",
// This zeroes the memory unconditionally
"SeCreateAccessState"
]
)
}
}
@@ -475,12 +457,9 @@ class ConditionalInitializationCall extends FunctionCall {
fa.getASuccessor+() = result
) and
result =
this
.getArgument(getTarget(this)
.(ConditionalInitializationFunction)
.conditionallyInitializedParameter(_))
.(AddressOfExpr)
.getOperand()
this.getArgument(getTarget(this)
.(ConditionalInitializationFunction)
.conditionallyInitializedParameter(_)).(AddressOfExpr).getOperand()
}
Variable getStatusVariable() {

View File

@@ -140,12 +140,9 @@ class FopenCreationExpr extends FileCreationExpr {
class FopensCreationExpr extends FileCreationExpr {
FopensCreationExpr() {
exists(string name | name = this.getTarget().getName() |
name = "fopen_s" or
name = "_wfopen_s"
) and
this.getTarget().getName() = ["fopen_s", "_wfopen_s"] and
exists(string mode |
(mode = "w" or mode = "a") and
mode = ["w", "a"] and
this.getArgument(2).getValue().matches(mode + "%")
)
}

View File

@@ -13,9 +13,10 @@ int main(int argc, char **argv)
char buf1[10];
scanf("%s", buf1);
// GOOD, length is specified. The length should be one less than the size of the buffer, since the last character is the NULL terminator.
char buf2[10];
sscanf(buf2, "%9s");
// GOOD, length is specified. The length should be one less than the size of the destination buffer, since the last character is the NULL terminator.
char buf2[20];
char buf3[10];
sscanf(buf2, "%9s", buf3);
// BAD, do not use scanf without specifying a length first
char file[10];

View File

@@ -0,0 +1,19 @@
image::image(int width, int height)
{
int x, y;
// allocate width * height pixels
pixels = new uint32_t[width * height];
// fill width * height pixels
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
pixels[(y * width) + height] = 0;
}
}
// ...
}

View File

@@ -0,0 +1,25 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The result of a multiplication is used in the size of an allocation. If the multiplication can be made to overflow, a much smaller amount of memory may be allocated than the rest of the code expects. This may lead to overflowing writes when the buffer is accessed later.</p>
</overview>
<recommendation>
<p>To fix this issue, ensure that the arithmetic used in the size of an allocation cannot overflow before memory is allocated.</p>
</recommendation>
<example>
<p>In the following example, an array of size <code>width * height</code> is allocated and stored as <code>pixels</code>. If <code>width</code> and <code>height</code> are set such that the multiplication overflows and wraps to a small value (say, 4) then the initialization code that follows the allocation will write beyond the end of the array.</p>
<sample src="AllocMultiplicationOverflow.cpp"/>
</example>
<references>
<li>
Cplusplus.com: <a href="http://www.cplusplus.com/articles/DE18T05o/">Integer overflow</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,40 @@
/**
* @name Multiplication result may overflow and be used in allocation
* @description Using a multiplication result that may overflow in the size of an allocation may lead to buffer overflows when the allocated memory is used.
* @kind path-problem
* @problem.severity warning
* @precision low
* @tags security
* correctness
* external/cwe/cwe-190
* external/cwe/cwe-128
* @id cpp/multiplication-overflow-in-alloc
*/
import cpp
import semmle.code.cpp.models.interfaces.Allocation
import semmle.code.cpp.dataflow.DataFlow
import DataFlow::PathGraph
class MultToAllocConfig extends DataFlow::Configuration {
MultToAllocConfig() { this = "MultToAllocConfig" }
override predicate isSource(DataFlow::Node node) {
// a multiplication of two non-constant expressions
exists(MulExpr me |
me = node.asExpr() and
forall(Expr e | e = me.getAnOperand() | not exists(e.getValue()))
)
}
override predicate isSink(DataFlow::Node node) {
// something that affects an allocation size
node.asExpr() = any(AllocationExpr ae).getSizeExpr().getAChild*()
}
}
from MultToAllocConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink,
"Potentially overflowing value from $@ is used in the size of this allocation.", source,
"multiplication"

View File

@@ -0,0 +1,11 @@
unsigned long sizeArray;
// BAD: let's consider several values, taking ULONG_MAX =18446744073709551615
// sizeArray = 60; (sizeArray - 10) = 50; true
// sizeArray = 10; (sizeArray - 10) = 0; false
// sizeArray = 1; (sizeArray - 10) = 18446744073709551607; true
// sizeArray = 0; (sizeArray - 10) = 18446744073709551606; true
if (sizeArray - 10 > 0)
// GOOD: Prevent overflow by checking the input
if (sizeArray > 10)

View File

@@ -0,0 +1,33 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The code compares the unsigned difference with zero.
It is highly probable that the condition is wrong if the difference expression has the unsigned type.
The condition holds in all the cases when difference is not equal to zero.
It means that we may use condition not equal. But the programmer probably wanted to compare the difference of elements.</p>
<p>False positives include code in which the first difference element is always greater than or equal to the second.
For comparison, ">" such conditions are equivalent to "! =", And are recommended for replacement.
For comparison "> =", the conditions are always true and are recommended to be excluded.</p>
</overview>
<recommendation>
<p>Use a simple comparison of two elements, instead of comparing their difference to zero.</p>
</recommendation>
<example>
<p>The following example demonstrates an erroneous and corrected use of comparison.</p>
<sample src="UnsignedDifferenceExpressionComparedZero.c" />
</example>
<references>
<li>CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/INT02-C.+Understand+integer+conversion+rules">INT02-C. Understand integer conversion rules</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,23 @@
/**
* @name Unsigned difference expression compared to zero
* @description It is highly probable that the condition is wrong if the difference expression has the unsigned type.
* The condition holds in all the cases when difference is not equal to zero. It means that we may use condition not equal.
* But the programmer probably wanted to compare the difference of elements.
* @kind problem
* @id cpp/unsigned-difference-expression-compared-zero
* @problem.severity warning
* @precision medium
* @tags security
* external/cwe/cwe-191
*/
import cpp
import semmle.code.cpp.commons.Exclusions
from RelationalOperation ro, SubExpr sub
where
not isFromMacroDefinition(ro) and
ro.getLesserOperand().getValue().toInt() = 0 and
ro.getGreaterOperand() = sub and
sub.getFullyConverted().getUnspecifiedType().(IntegralType).isUnsigned()
select ro, "Difference in condition is always greater than or equal to zero"

View File

@@ -31,8 +31,7 @@ predicate canonicalName1(Declaration d, string canonical) {
predicate canonicalName2(Declaration d, string canonical) {
canonical =
d
.getName()
d.getName()
.replaceAll("_", "")
.replaceAll("0", "O")
.replaceAll("D", "O")

View File

@@ -35,8 +35,7 @@ private predicate autogeneratedComment(string comment) {
.regexpMatch("(?si).*(" +
// replace `generated` with a regexp that also catches things like
// `auto-generated`.
cond
.replaceAll("generated", "(auto[\\w-]*[\\s/\\*\\r\\n]*)?generated")
cond.replaceAll("generated", "(auto[\\w-]*[\\s/\\*\\r\\n]*)?generated")
// replace `!` with a regexp for end-of-sentence / separator characters.
.replaceAll("!", "[\\.\\?\\!\\-\\;\\,]")
// replace ` ` with a regexp for one or more whitespace characters

View File

@@ -236,9 +236,8 @@ class Class extends UserType {
or
exists(ClassDerivation cd | cd.getBaseClass() = base |
result =
this
.accessOfBaseMemberMulti(cd.getDerivedClass(),
fieldInBase.accessInDirectDerived(cd.getASpecifier().(AccessSpecifier)))
this.accessOfBaseMemberMulti(cd.getDerivedClass(),
fieldInBase.accessInDirectDerived(cd.getASpecifier().(AccessSpecifier)))
)
}

View File

@@ -478,9 +478,8 @@ class AccessHolder extends Declaration, TAccessHolder {
*/
pragma[inline]
predicate canAccessMember(Declaration member, Class derived) {
this
.couldAccessMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier),
derived)
this.couldAccessMember(member.getDeclaringType(), member.getASpecifier().(AccessSpecifier),
derived)
}
/**

View File

@@ -363,20 +363,8 @@ class File extends Container, @file {
*/
class HeaderFile extends File {
HeaderFile() {
exists(string ext | ext = this.getExtension().toLowerCase() |
ext = "h" or
ext = "r" or
/* --- */ ext = "hpp" or
ext = "hxx" or
ext = "h++" or
ext = "hh" or
ext = "hp" or
ext = "tcc" or
ext = "tpp" or
ext = "txx" or
ext = "t++"
/* --- --- */
)
this.getExtension().toLowerCase() =
["h", "r", "hpp", "hxx", "h++", "hh", "hp", "tcc", "tpp", "txx", "t++"]
or
not exists(this.getExtension()) and
exists(Include i | i.getIncludedFile() = this)
@@ -406,7 +394,7 @@ class HeaderFile extends File {
* `File.compiledAsC`.
*/
class CFile extends File {
CFile() { exists(string ext | ext = this.getExtension().toLowerCase() | ext = "c" or ext = "i") }
CFile() { this.getExtension().toLowerCase() = ["c", "i"] }
override string getAPrimaryQlClass() { result = "CFile" }
}
@@ -419,21 +407,10 @@ class CFile extends File {
*/
class CppFile extends File {
CppFile() {
exists(string ext | ext = this.getExtension().toLowerCase() |
/* --- */ ext = "cpp" or
ext = "cxx" or
ext = "c++" or
ext = "cc" or
ext = "cp" or
ext = "icc" or
ext = "ipp" or
ext = "ixx" or
ext = "i++" or
ext = "ii"
/* --- */
// Note: .C files are indistinguishable from .c files on some
// file systems, so we just treat them as CFile's.
)
this.getExtension().toLowerCase() =
["cpp", "cxx", "c++", "cc", "cp", "icc", "ipp", "ixx", "i++", "ii"]
// Note: .C files are indistinguishable from .c files on some
// file systems, so we just treat them as CFile's.
}
override string getAPrimaryQlClass() { result = "CppFile" }

View File

@@ -391,20 +391,30 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
/** Holds if this function has a `noexcept` exception specification. */
predicate isNoExcept() { getADeclarationEntry().isNoExcept() }
/** Gets a function that overloads this one. */
/**
* Gets a function that overloads this one.
*
* Note: if _overrides_ are wanted rather than _overloads_ then
* `MemberFunction::getAnOverridingFunction` should be used instead.
*/
Function getAnOverload() {
result.getName() = getName() and
result.getNamespace() = getNamespace() and
result != this and
// If this function is declared in a class, only consider other
// functions from the same class. Conversely, if this function is not
// declared in a class, only consider other functions not declared in a
// class.
(
if exists(getDeclaringType())
then result.getDeclaringType() = getDeclaringType()
else not exists(result.getDeclaringType())
// If this function is declared in a class, only consider other
// functions from the same class.
exists(string name, Class declaringType |
candGetAnOverloadMember(name, declaringType, this) and
candGetAnOverloadMember(name, declaringType, result)
)
or
// Conversely, if this function is not
// declared in a class, only consider other functions not declared in a
// class.
exists(string name, Namespace namespace |
candGetAnOverloadNonMember(name, namespace, this) and
candGetAnOverloadNonMember(name, namespace, result)
)
) and
result != this and
// Instantiations and specializations don't participate in overload
// resolution.
not (
@@ -445,50 +455,15 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
// ... and likewise for destructors.
this.(Destructor).getADestruction().mayBeGloballyImpure()
else
not exists(string name | this.hasGlobalOrStdName(name) |
// Unless it's a function that we know is side-effect-free, it may
// have side-effects.
name = "strcmp" or
name = "wcscmp" or
name = "_mbscmp" or
name = "strlen" or
name = "wcslen" or
name = "_mbslen" or
name = "_mbslen_l" or
name = "_mbstrlen" or
name = "_mbstrlen_l" or
name = "strnlen" or
name = "strnlen_s" or
name = "wcsnlen" or
name = "wcsnlen_s" or
name = "_mbsnlen" or
name = "_mbsnlen_l" or
name = "_mbstrnlen" or
name = "_mbstrnlen_l" or
name = "strncmp" or
name = "wcsncmp" or
name = "_mbsncmp" or
name = "_mbsncmp_l" or
name = "strchr" or
name = "memchr" or
name = "wmemchr" or
name = "memcmp" or
name = "wmemcmp" or
name = "_memicmp" or
name = "_memicmp_l" or
name = "feof" or
name = "isdigit" or
name = "isxdigit" or
name = "abs" or
name = "fabs" or
name = "labs" or
name = "floor" or
name = "ceil" or
name = "atoi" or
name = "atol" or
name = "atoll" or
name = "atof"
)
// Unless it's a function that we know is side-effect-free, it may
// have side-effects.
not this.hasGlobalOrStdName([
"strcmp", "wcscmp", "_mbscmp", "strlen", "wcslen", "_mbslen", "_mbslen_l", "_mbstrlen",
"_mbstrlen_l", "strnlen", "strnlen_s", "wcsnlen", "wcsnlen_s", "_mbsnlen", "_mbsnlen_l",
"_mbstrnlen", "_mbstrnlen_l", "strncmp", "wcsncmp", "_mbsncmp", "_mbsncmp_l", "strchr",
"memchr", "wmemchr", "memcmp", "wmemcmp", "_memicmp", "_memicmp_l", "feof", "isdigit",
"isxdigit", "abs", "fabs", "labs", "floor", "ceil", "atoi", "atol", "atoll", "atof"
])
}
/**
@@ -497,6 +472,19 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
override AccessHolder getEnclosingAccessHolder() { result = this.getDeclaringType() }
}
pragma[noinline]
private predicate candGetAnOverloadMember(string name, Class declaringType, Function f) {
f.getName() = name and
f.getDeclaringType() = declaringType
}
pragma[noinline]
private predicate candGetAnOverloadNonMember(string name, Namespace namespace, Function f) {
f.getName() = name and
f.getNamespace() = namespace and
not exists(f.getDeclaringType())
}
/**
* A particular declaration or definition of a C/C++ function. For example the
* declaration and definition of `MyFunction` in the following code are each a

View File

@@ -385,7 +385,7 @@ private class DumpFunction extends DumpDeclaration, Function {
private string getACVQualifier() {
result = getASpecifier().getName() and
(result = "const" or result = "volatile")
result = ["const", "volatile"]
}
private string getDeclaratorSuffix() {

View File

@@ -34,8 +34,7 @@ private predicate shouldPrintFunction(Function func) {
bindingset[s]
private string escapeString(string s) {
result =
s
.replaceAll("\\", "\\\\")
s.replaceAll("\\", "\\\\")
.replaceAll("\n", "\\n")
.replaceAll("\r", "\\r")
.replaceAll("\t", "\\t")

View File

@@ -14,11 +14,7 @@ class PackedTimeType extends Type {
}
}
private predicate timeType(string typeName) {
typeName = "_SYSTEMTIME" or
typeName = "SYSTEMTIME" or
typeName = "tm"
}
private predicate timeType(string typeName) { typeName = ["_SYSTEMTIME", "SYSTEMTIME", "tm"] }
/**
* A type that is used to represent times and dates in an 'unpacked' form, that is,

View File

@@ -34,66 +34,87 @@ class AttributeFormattingFunction extends FormattingFunction {
/**
* A standard function such as `vprintf` that has a format parameter
* and a variable argument list of type `va_arg`.
* and a variable argument list of type `va_arg`. `formatParamIndex` indicates
* the format parameter and `type` indicates the type of `vprintf`:
* - `""` is a `vprintf` variant, `outputParamIndex` is `-1`.
* - `"f"` is a `vfprintf` variant, `outputParamIndex` indicates the output stream parameter.
* - `"s"` is a `vsprintf` variant, `outputParamIndex` indicates the output buffer parameter.
* - `"?"` if the type cannot be deteremined. `outputParamIndex` is `-1`.
*/
predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
f.getName().regexpMatch("_?_?va?[fs]?n?w?printf(_s)?(_p)?(_l)?") and
predicate primitiveVariadicFormatter(
TopLevelFunction f, string type, int formatParamIndex, int outputParamIndex
) {
type = f.getName().regexpCapture("_?_?va?([fs]?)n?w?printf(_s)?(_p)?(_l)?", 1) and
(
if f.getName().matches("%\\_l")
then formatParamIndex = f.getNumberOfParameters() - 3
else formatParamIndex = f.getNumberOfParameters() - 2
) and
if type = "" then outputParamIndex = -1 else outputParamIndex = 0 // Conveniently, these buffer parameters are all at index 0.
}
private predicate callsVariadicFormatter(
Function f, string type, int formatParamIndex, int outputParamIndex
) {
// calls a variadic formatter with `formatParamIndex`, `outputParamIndex` linked
exists(FunctionCall fc, int format, int output |
variadicFormatter(fc.getTarget(), type, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
fc.getArgument(output) = f.getParameter(outputParamIndex).getAnAccess()
)
or
// calls a variadic formatter with only `formatParamIndex` linked
exists(FunctionCall fc, string calledType, int format, int output |
variadicFormatter(fc.getTarget(), calledType, format, output) and
fc.getEnclosingFunction() = f and
fc.getArgument(format) = f.getParameter(formatParamIndex).getAnAccess() and
not fc.getArgument(output) = f.getParameter(_).getAnAccess() and
(
calledType = "" and
type = ""
or
calledType != "" and
type = "?" // we probably should have an `outputParamIndex` link but have lost it.
) and
outputParamIndex = -1
)
}
/**
* A standard function such as `vsprintf` that has an output parameter
* and a variable argument list of type `va_arg`.
* Holds if `f` is a function such as `vprintf` that has a format parameter
* and a variable argument list of type `va_arg`. `formatParamIndex` indicates
* the format parameter and `type` indicates the type of `vprintf`:
* - `""` is a `vprintf` variant, `outputParamIndex` is `-1`.
* - `"f"` is a `vfprintf` variant, `outputParamIndex` indicates the output stream parameter.
* - `"s"` is a `vsprintf` variant, `outputParamIndex` indicates the output buffer parameter.
* - `"?"` if the type cannot be deteremined. `outputParamIndex` is `-1`.
*/
private predicate primitiveVariadicFormatterOutput(TopLevelFunction f, int outputParamIndex) {
// note: this might look like the regular expression in `primitiveVariadicFormatter`, but
// there is one important difference: the [fs] part is not optional, as these classify
// the `printf` variants that write to a buffer.
// Conveniently, these buffer parameters are all at index 0.
f.getName().regexpMatch("_?_?va?[fs]n?w?printf(_s)?(_p)?(_l)?") and outputParamIndex = 0
}
private predicate callsVariadicFormatter(Function f, int formatParamIndex) {
exists(FunctionCall fc, int i |
variadicFormatter(fc.getTarget(), i) and
fc.getEnclosingFunction() = f and
fc.getArgument(i) = f.getParameter(formatParamIndex).getAnAccess()
)
}
private predicate callsVariadicFormatterOutput(Function f, int outputParamIndex) {
exists(FunctionCall fc, int i |
fc.getEnclosingFunction() = f and
variadicFormatterOutput(fc.getTarget(), i) and
fc.getArgument(i) = f.getParameter(outputParamIndex).getAnAccess()
)
}
/**
* Holds if `f` is a function such as `vprintf` that takes variable argument list
* of type `va_arg` and writes formatted output to a buffer given as a parameter at
* index `outputParamIndex`, if any.
*/
private predicate variadicFormatterOutput(Function f, int outputParamIndex) {
primitiveVariadicFormatterOutput(f, outputParamIndex)
predicate variadicFormatter(Function f, string type, int formatParamIndex, int outputParamIndex) {
primitiveVariadicFormatter(f, type, formatParamIndex, outputParamIndex)
or
not f.isVarargs() and
callsVariadicFormatterOutput(f, outputParamIndex)
callsVariadicFormatter(f, type, formatParamIndex, outputParamIndex)
}
/**
* A standard function such as `vprintf` that has a format parameter
* and a variable argument list of type `va_arg`.
*
* DEPRECATED: Use the four argument version instead.
*/
deprecated predicate primitiveVariadicFormatter(TopLevelFunction f, int formatParamIndex) {
primitiveVariadicFormatter(f, _, formatParamIndex, _)
}
/**
* Holds if `f` is a function such as `vprintf` that has a format parameter
* (at `formatParamIndex`) and a variable argument list of type `va_arg`.
*
* DEPRECATED: Use the four argument version instead.
*/
predicate variadicFormatter(Function f, int formatParamIndex) {
primitiveVariadicFormatter(f, formatParamIndex)
or
not f.isVarargs() and
callsVariadicFormatter(f, formatParamIndex)
deprecated predicate variadicFormatter(Function f, int formatParamIndex) {
variadicFormatter(f, _, formatParamIndex, _)
}
/**
@@ -103,11 +124,17 @@ predicate variadicFormatter(Function f, int formatParamIndex) {
class UserDefinedFormattingFunction extends FormattingFunction {
override string getAPrimaryQlClass() { result = "UserDefinedFormattingFunction" }
UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _) }
UserDefinedFormattingFunction() { isVarargs() and callsVariadicFormatter(this, _, _, _) }
override int getFormatParameterIndex() { callsVariadicFormatter(this, result) }
override int getFormatParameterIndex() { callsVariadicFormatter(this, _, result, _) }
override int getOutputParameterIndex() { callsVariadicFormatterOutput(this, result) }
override int getOutputParameterIndex(boolean isStream) {
callsVariadicFormatter(this, "f", _, result) and isStream = true
or
callsVariadicFormatter(this, "s", _, result) and isStream = false
}
override predicate isOutputGlobal() { callsVariadicFormatter(this, "", _, _) }
}
/**
@@ -873,6 +900,7 @@ class FormatLiteral extends Literal {
*/
int getNumArgNeeded(int n) {
exists(this.getConvSpecOffset(n)) and
exists(this.getConversionChar(n)) and
result = count(int mode | hasFormatArgumentIndexFor(n, mode))
}
@@ -1089,8 +1117,7 @@ class FormatLiteral extends Literal {
then result = this.getFormat().substring(0, this.getConvSpecOffset(0))
else
result =
this
.getFormat()
this.getFormat()
.substring(this.getConvSpecOffset(n - 1) + this.getConvSpec(n - 1).length(),
this.getConvSpecOffset(n))
}
@@ -1106,8 +1133,7 @@ class FormatLiteral extends Literal {
if n > 0
then
result =
this
.getFormat()
this.getFormat()
.substring(this.getConvSpecOffset(n - 1) + this.getConvSpec(n - 1).length(),
this.getFormat().length())
else result = this.getFormat()

View File

@@ -13,7 +13,7 @@ import Dereferenced
* predicates that implement this analysis.
*/
abstract class DataflowAnnotation extends string {
DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" }
DataflowAnnotation() { this = ["pointer-null", "pointer-valid"] }
/** Holds if this annotation is the default annotation. */
abstract predicate isDefault();
@@ -98,7 +98,7 @@ abstract class DataflowAnnotation extends string {
* respectively.
*/
class NullnessAnnotation extends DataflowAnnotation {
NullnessAnnotation() { this = "pointer-null" or this = "pointer-valid" }
NullnessAnnotation() { this = ["pointer-null", "pointer-valid"] }
override predicate isDefault() { this = "pointer-valid" }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -802,14 +802,9 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) {
exists(TypedContent tc |
this.headUsesContent(tc) and
clearsContent(n, tc.getContent())
)
}
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -280,6 +280,15 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
int accessPathLimit() { result = 5 }
/** The unit type. */
private newtype TUnit = TMkUnit()
/** The trivial type with a single element. */
class Unit extends TUnit {
/** Gets a textual representation of this element. */
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a

View File

@@ -620,7 +620,8 @@ module FlowVar_internal {
private predicate largeVariable(Variable v, int liveBlocks, int defs) {
liveBlocks = strictcount(SubBasicBlock sbb | variableLiveInSBB(sbb, v)) and
defs = strictcount(SubBasicBlock sbb | exists(TBlockVar(sbb, v))) and
liveBlocks * defs > 1000000
// Convert to float to avoid int overflow (32-bit two's complement)
liveBlocks.(float) * defs.(float) > 100000.0
}
/**

View File

@@ -847,8 +847,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
*/
Expr getPlacementPointer() {
result =
this
.getAllocatorCall()
this.getAllocatorCall()
.getArgument(this.getAllocator().(OperatorNewAllocationFunction).getPlacementArgument())
}
}

View File

@@ -160,8 +160,7 @@ predicate ifndefDirective(PreprocessorDirective ppd, string macro) {
ppd instanceof PreprocessorIf and
exists(string head | head = ppd.getHead() |
macro =
head
.replaceAll("(", " ")
head.replaceAll("(", " ")
.replaceAll(")", "")
.replaceAll("\t", " ")
.regexpCapture("[ ]*![ ]*defined[ ]+([^ ]*)[ ]*", 1)

View File

@@ -36,43 +36,33 @@ private predicate predictableInstruction(Instruction instr) {
* library's `returnArgument` predicate.
*/
predicate predictableOnlyFlow(string name) {
name = "strcasestr" or
name = "strchnul" or
name = "strchr" or
name = "strchrnul" or
name = "strcmp" or
name = "strcspn" or
name = "strncmp" or
name = "strndup" or
name = "strnlen" or
name = "strrchr" or
name = "strspn" or
name = "strstr" or
name = "strtod" or
name = "strtof" or
name = "strtol" or
name = "strtoll" or
name = "strtoq" or
name = "strtoul"
name =
[
"strcasestr", "strchnul", "strchr", "strchrnul", "strcmp", "strcspn", "strncmp", "strndup",
"strnlen", "strrchr", "strspn", "strstr", "strtod", "strtof", "strtol", "strtoll", "strtoq",
"strtoul"
]
}
private DataFlow::Node getNodeForSource(Expr source) {
isUserInput(source, _) and
(
result = DataFlow::exprNode(source)
or
// Some of the sources in `isUserInput` are intended to match the value of
// an expression, while others (those modeled below) are intended to match
// the taint that propagates out of an argument, like the `char *` argument
// to `gets`. It's impossible here to tell which is which, but the "access
// to argv" source is definitely not intended to match an output argument,
// and it causes false positives if we let it.
//
// This case goes together with the similar (but not identical) rule in
// `nodeIsBarrierIn`.
result = DataFlow::definitionByReferenceNodeFromArgument(source) and
not argv(source.(VariableAccess).getTarget())
)
result = getNodeForExpr(source)
}
private DataFlow::Node getNodeForExpr(Expr node) {
result = DataFlow::exprNode(node)
or
// Some of the sources in `isUserInput` are intended to match the value of
// an expression, while others (those modeled below) are intended to match
// the taint that propagates out of an argument, like the `char *` argument
// to `gets`. It's impossible here to tell which is which, but the "access
// to argv" source is definitely not intended to match an output argument,
// and it causes false positives if we let it.
//
// This case goes together with the similar (but not identical) rule in
// `nodeIsBarrierIn`.
result = DataFlow::definitionByReferenceNodeFromArgument(node) and
not argv(node.(VariableAccess).getTarget())
}
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {
@@ -216,16 +206,27 @@ private predicate nodeIsBarrierIn(DataFlow::Node node) {
cached
private predicate commonTaintStep(DataFlow::Node fromNode, DataFlow::Node toNode) {
instructionToInstructionTaintStep(fromNode.asInstruction(), toNode.asInstruction())
or
operandToInstructionTaintStep(fromNode.asOperand(), toNode.asInstruction())
or
operandToOperandTaintStep(fromNode.asOperand(), toNode.asOperand())
instructionToOperandTaintStep(fromNode.asInstruction(), toNode.asOperand())
}
private predicate operandToOperandTaintStep(Operand fromOperand, Operand toOperand) {
private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand toOperand) {
// Propagate flow from the definition of an operand to the operand, even when the overlap is inexact.
// We only do this in certain cases:
// 1. The instruction's result must not be conflated, and
// 2. The instruction's result type is one the types where we expect element-to-object flow. Currently
// this is array types and union types. This matches the other two cases of element-to-object flow in
// `DefaultTaintTracking`.
toOperand.getAnyDef() = fromInstr and
not fromInstr.isResultConflated() and
(
fromInstr.getResultType() instanceof ArrayType or
fromInstr.getResultType() instanceof Union
)
or
exists(ReadSideEffectInstruction readInstr |
fromOperand = readInstr.getArgumentOperand() and
fromInstr = readInstr.getArgumentDef() and
toOperand = readInstr.getSideEffectOperand()
)
}
@@ -268,18 +269,18 @@ private predicate operandToInstructionTaintStep(Operand fromOperand, Instruction
outInstr.getPrimaryInstruction() = call
)
)
}
private predicate instructionToInstructionTaintStep(Instruction i1, Instruction i2) {
or
// Flow through pointer dereference
i2.(LoadInstruction).getSourceAddress() = i1
toInstr.(LoadInstruction).getSourceAddressOperand() = fromOperand
or
// Flow through partial reads of arrays and unions
i2.(LoadInstruction).getSourceValueOperand().getAnyDef() = i1 and
not i1.isResultConflated() and
(
i1.getResultType() instanceof ArrayType or
i1.getResultType() instanceof Union
toInstr.(LoadInstruction).getSourceValueOperand() = fromOperand and
exists(Instruction fromInstr | fromInstr = fromOperand.getAnyDef() |
not fromInstr.isResultConflated() and
(
fromInstr.getResultType() instanceof ArrayType or
fromInstr.getResultType() instanceof Union
)
)
or
// Unary instructions tend to preserve enough information in practice that we
@@ -289,63 +290,54 @@ private predicate instructionToInstructionTaintStep(Instruction i1, Instruction
// `FieldAddressInstruction` could cause flow into one field to come out an
// unrelated field. This would happen across function boundaries, where the IR
// would not be able to match loads to stores.
i2.(UnaryInstruction).getUnary() = i1 and
toInstr.(UnaryInstruction).getUnaryOperand() = fromOperand and
(
not i2 instanceof FieldAddressInstruction
not toInstr instanceof FieldAddressInstruction
or
i2.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
toInstr.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
)
or
// Flow out of definition-by-reference
i2.(ChiInstruction).getPartial() = i1.(WriteSideEffectInstruction) and
not i2.isResultConflated()
or
// Flow from an element to an array or union that contains it.
i2.(ChiInstruction).getPartial() = i1 and
not i2.isResultConflated() and
exists(Type t | i2.getResultLanguageType().hasType(t, false) |
toInstr.(ChiInstruction).getPartialOperand() = fromOperand and
not toInstr.isResultConflated() and
exists(Type t | toInstr.getResultLanguageType().hasType(t, false) |
t instanceof Union
or
t instanceof ArrayType
)
or
exists(BinaryInstruction bin |
bin = i2 and
predictableInstruction(i2.getAnOperand().getDef()) and
i1 = i2.getAnOperand().getDef()
bin = toInstr and
predictableInstruction(toInstr.getAnOperand().getDef()) and
fromOperand = toInstr.getAnOperand()
)
or
// This is part of the translation of `a[i]`, where we want taint to flow
// from `a`.
i2.(PointerAddInstruction).getLeft() = i1
or
// Until we have from through indirections across calls, we'll take flow out
// of the parameter and into its indirection.
exists(IRFunction f, Parameter parameter |
i1 = getInitializeParameter(f, parameter) and
i2 = getInitializeIndirection(f, parameter)
)
toInstr.(PointerAddInstruction).getLeftOperand() = fromOperand
or
// Until we have flow through indirections across calls, we'll take flow out
// of the indirection and into the argument.
// When we get proper flow through indirections across calls, this code can be
// moved to `adjusedSink` or possibly into the `DataFlow::ExprNode` class.
exists(ReadSideEffectInstruction read |
read.getAnOperand().(SideEffectOperand).getAnyDef() = i1 and
read.getArgumentDef() = i2
read.getSideEffectOperand() = fromOperand and
read.getArgumentDef() = toInstr
)
}
pragma[noinline]
private InitializeIndirectionInstruction getInitializeIndirection(IRFunction f, Parameter p) {
result.getParameter() = p and
result.getEnclosingIRFunction() = f
}
pragma[noinline]
private InitializeParameterInstruction getInitializeParameter(IRFunction f, Parameter p) {
result.getParameter() = p and
result.getEnclosingIRFunction() = f
or
// Until we have from through indirections across calls, we'll take flow out
// of the parameter and into its indirection.
// `InitializeIndirectionInstruction` only has a single operand: the address of the
// value whose indirection we are initializing. When initializing an indirection of a parameter `p`,
// the IR looks like this:
// ```
// m1 = InitializeParameter[p] : &r1
// r2 = Load[p] : r2, m1
// m3 = InitializeIndirection[p] : &r2
// ```
// So by having flow from `r2` to `m3` we're enabling flow from `m1` to `m3`. This relies on the
// `LoadOperand`'s overlap being exact.
toInstr.(InitializeIndirectionInstruction).getAnOperand() = fromOperand
}
/**
@@ -547,6 +539,9 @@ module TaintedWithPath {
* a characteristic predicate.
*/
class TaintTrackingConfiguration extends TSingleton {
/** Override this to specify which elements are sources in this configuration. */
predicate isSource(Expr source) { exists(getNodeForSource(source)) }
/** Override this to specify which elements are sinks in this configuration. */
abstract predicate isSink(Element e);
@@ -563,7 +558,11 @@ module TaintedWithPath {
private class AdjustedConfiguration extends DataFlow3::Configuration {
AdjustedConfiguration() { this = "AdjustedConfiguration" }
override predicate isSource(DataFlow::Node source) { source = getNodeForSource(_) }
override predicate isSource(DataFlow::Node source) {
exists(TaintTrackingConfiguration cfg, Expr e |
cfg.isSource(e) and source = getNodeForExpr(e)
)
}
override predicate isSink(DataFlow::Node sink) {
exists(TaintTrackingConfiguration cfg | cfg.isSink(adjustedSink(sink)))
@@ -606,7 +605,8 @@ module TaintedWithPath {
exists(AdjustedConfiguration cfg, DataFlow3::Node sourceNode, DataFlow3::Node sinkNode |
cfg.hasFlow(sourceNode, sinkNode)
|
sourceNode = getNodeForSource(e)
sourceNode = getNodeForExpr(e) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSource(e))
or
e = adjustedSink(sinkNode) and
exists(TaintTrackingConfiguration ttCfg | ttCfg.isSink(e))
@@ -652,8 +652,7 @@ module TaintedWithPath {
override predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this
.inner()
this.inner()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
@@ -661,7 +660,7 @@ module TaintedWithPath {
/** A PathNode whose `Element` is a source. It may also be a sink. */
private class InitialPathNode extends EndpointPathNode {
InitialPathNode() { exists(getNodeForSource(this.inner())) }
InitialPathNode() { exists(TaintTrackingConfiguration cfg | cfg.isSource(this.inner())) }
}
/** A PathNode whose `Element` is a sink. It may also be a source. */
@@ -683,14 +682,14 @@ module TaintedWithPath {
// Same for the first node
exists(WrapPathNode sourceNode |
DataFlow3::PathGraph::edges(sourceNode.inner(), b.(WrapPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner())
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner())
)
or
// Finally, handle the case where the path goes directly from a source to a
// sink, meaning that they both need to be translated.
exists(WrapPathNode sinkNode, WrapPathNode sourceNode |
DataFlow3::PathGraph::edges(sourceNode.inner(), sinkNode.inner()) and
sourceNode.inner().getNode() = getNodeForSource(a.(InitialPathNode).inner()) and
sourceNode.inner().getNode() = getNodeForExpr(a.(InitialPathNode).inner()) and
b.(FinalPathNode).inner() = adjustedSink(sinkNode.inner().getNode())
)
}
@@ -713,7 +712,7 @@ module TaintedWithPath {
predicate taintedWithPath(Expr source, Element tainted, PathNode sourceNode, PathNode sinkNode) {
exists(AdjustedConfiguration cfg, DataFlow3::Node flowSource, DataFlow3::Node flowSink |
source = sourceNode.(InitialPathNode).inner() and
flowSource = getNodeForSource(source) and
flowSource = getNodeForExpr(source) and
cfg.hasFlow(flowSource, flowSink) and
tainted = adjustedSink(flowSink) and
tainted = sinkNode.(FinalPathNode).inner()
@@ -735,8 +734,8 @@ module TaintedWithPath {
* through a global variable.
*/
predicate taintedWithoutGlobals(Element tainted) {
exists(PathNode sourceNode, FinalPathNode sinkNode |
sourceNode.(WrapPathNode).inner().getNode() = getNodeForSource(_) and
exists(AdjustedConfiguration cfg, PathNode sourceNode, FinalPathNode sinkNode |
cfg.isSource(sourceNode.(WrapPathNode).inner().getNode()) and
edgesWithoutGlobals+(sourceNode, sinkNode) and
tainted = sinkNode.inner()
)

View File

@@ -802,14 +802,9 @@ abstract class AccessPathFront extends TAccessPathFront {
abstract boolean toBoolNonEmpty();
predicate headUsesContent(TypedContent tc) { this = TFrontHead(tc) }
TypedContent getHead() { this = TFrontHead(result) }
predicate isClearedAt(Node n) {
exists(TypedContent tc |
this.headUsesContent(tc) and
clearsContent(n, tc.getContent())
)
}
predicate isClearedAt(Node n) { clearsContent(n, getHead().getContent()) }
}
class AccessPathFrontNil extends AccessPathFront, TFrontNil {

View File

@@ -503,6 +503,15 @@ predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub impl
int accessPathLimit() { result = 5 }
/** The unit type. */
private newtype TUnit = TMkUnit()
/** The trivial type with a single element. */
class Unit extends TUnit {
/** Gets a textual representation of this element. */
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a

View File

@@ -95,7 +95,7 @@ class Node extends TIRDataFlowNode {
* Gets the uninitialized local variable corresponding to this node, if
* any.
*/
LocalVariable asUninitialized() { none() }
deprecated LocalVariable asUninitialized() { none() }
/**
* Gets an upper bound on the type of this node.

View File

@@ -528,9 +528,9 @@ class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEff
tag instanceof OnlyInstructionTag and
operandTag instanceof BufferSizeOperandTag and
result =
getTranslatedExpr(call
.getArgument(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
.getFullyConverted()).getResult()
getTranslatedExpr(call.getArgument(call.getTarget()
.(SideEffectFunction)
.getParameterSizeIndex(index)).getFullyConverted()).getResult()
}
override CppType getInstructionMemoryOperandType(InstructionTag tag, TypedOperandTag operandTag) {

View File

@@ -14,95 +14,58 @@ private class MallocAllocationFunction extends AllocationFunction {
int sizeArg;
MallocAllocationFunction() {
exists(string name |
hasGlobalOrStdName(name) and
// malloc(size)
(name = "malloc" and sizeArg = 0)
or
hasGlobalName(name) and
(
// ExAllocatePool(type, size)
name = "ExAllocatePool" and sizeArg = 1
or
// ExAllocatePool(type, size, tag)
name = "ExAllocatePoolWithTag" and sizeArg = 1
or
// ExAllocatePoolWithTagPriority(type, size, tag, priority)
name = "ExAllocatePoolWithTagPriority" and sizeArg = 1
or
// ExAllocatePoolWithQuota(type, size)
name = "ExAllocatePoolWithQuota" and sizeArg = 1
or
// ExAllocatePoolWithQuotaTag(type, size, tag)
name = "ExAllocatePoolWithQuotaTag" and sizeArg = 1
or
// IoAllocateMdl(address, size, flag, flag, irp)
name = "IoAllocateMdl" and sizeArg = 1
or
// IoAllocateErrorLogEntry(object, size)
name = "IoAllocateErrorLogEntry" and sizeArg = 1
or
// MmAllocateContiguousMemory(size, maxaddress)
name = "MmAllocateContiguousMemory" and sizeArg = 0
or
// MmAllocateContiguousNodeMemory(size, minaddress, maxaddress, bound, flag, prefer)
name = "MmAllocateContiguousNodeMemory" and sizeArg = 0
or
// MmAllocateContiguousMemorySpecifyCache(size, minaddress, maxaddress, bound, type)
name = "MmAllocateContiguousMemorySpecifyCache" and sizeArg = 0
or
// MmAllocateContiguousMemorySpecifyCacheNode(size, minaddress, maxaddress, bound, type, prefer)
name = "MmAllocateContiguousMemorySpecifyCacheNode" and sizeArg = 0
or
// MmAllocateNonCachedMemory(size)
name = "MmAllocateNonCachedMemory" and sizeArg = 0
or
// MmAllocateMappingAddress(size, tag)
name = "MmAllocateMappingAddress" and sizeArg = 0
or
// MmAllocatePagesForMdl(minaddress, maxaddress, skip, size)
name = "MmAllocatePagesForMdl" and sizeArg = 3
or
// MmAllocatePagesForMdlEx(minaddress, maxaddress, skip, size, type, flags)
name = "MmAllocatePagesForMdlEx" and sizeArg = 3
or
// MmAllocateNodePagesForMdlEx(minaddress, maxaddress, skip, size, type, prefer, flags)
name = "MmAllocateNodePagesForMdlEx" and sizeArg = 3
or
// LocalAlloc(flags, size)
name = "LocalAlloc" and sizeArg = 1
or
// GlobalAlloc(flags, size)
name = "GlobalAlloc" and sizeArg = 1
or
// HeapAlloc(heap, flags, size)
name = "HeapAlloc" and sizeArg = 2
or
// VirtualAlloc(address, size, type, flag)
name = "VirtualAlloc" and sizeArg = 1
or
// CoTaskMemAlloc(size)
name = "CoTaskMemAlloc" and sizeArg = 0
or
// kmem_alloc(size, flags)
name = "kmem_alloc" and sizeArg = 0
or
// kmem_zalloc(size, flags)
name = "kmem_zalloc" and sizeArg = 0
or
// CRYPTO_malloc(size_t num, const char *file, int line)
name = "CRYPTO_malloc" and sizeArg = 0
or
// CRYPTO_zalloc(size_t num, const char *file, int line)
name = "CRYPTO_zalloc" and sizeArg = 0
or
// CRYPTO_secure_malloc(size_t num, const char *file, int line)
name = "CRYPTO_secure_malloc" and sizeArg = 0
or
// CRYPTO_secure_zalloc(size_t num, const char *file, int line)
name = "CRYPTO_secure_zalloc" and sizeArg = 0
)
)
// --- C library allocation
hasGlobalOrStdName("malloc") and // malloc(size)
sizeArg = 0
or
hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"MmAllocateContiguousMemory", // MmAllocateContiguousMemory(size, maxaddress)
"MmAllocateContiguousNodeMemory", // MmAllocateContiguousNodeMemory(size, minaddress, maxaddress, bound, flag, prefer)
"MmAllocateContiguousMemorySpecifyCache", // MmAllocateContiguousMemorySpecifyCache(size, minaddress, maxaddress, bound, type)
"MmAllocateContiguousMemorySpecifyCacheNode", // MmAllocateContiguousMemorySpecifyCacheNode(size, minaddress, maxaddress, bound, type, prefer)
"MmAllocateNonCachedMemory", // MmAllocateNonCachedMemory(size)
"MmAllocateMappingAddress", // MmAllocateMappingAddress(size, tag)
// --- Windows COM allocation
"CoTaskMemAlloc", // CoTaskMemAlloc(size)
// --- Solaris/BSD kernel memory allocator
"kmem_alloc", // kmem_alloc(size, flags)
"kmem_zalloc", // kmem_zalloc(size, flags)
// --- OpenSSL memory allocation
"CRYPTO_malloc", // CRYPTO_malloc(size_t num, const char *file, int line)
"CRYPTO_zalloc", // CRYPTO_zalloc(size_t num, const char *file, int line)
"CRYPTO_secure_malloc", // CRYPTO_secure_malloc(size_t num, const char *file, int line)
"CRYPTO_secure_zalloc" // CRYPTO_secure_zalloc(size_t num, const char *file, int line)
]) and
sizeArg = 0
or
hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"ExAllocatePool", // ExAllocatePool(type, size)
"ExAllocatePoolWithTag", // ExAllocatePool(type, size, tag)
"ExAllocatePoolWithTagPriority", // ExAllocatePoolWithTagPriority(type, size, tag, priority)
"ExAllocatePoolWithQuota", // ExAllocatePoolWithQuota(type, size)
"ExAllocatePoolWithQuotaTag", // ExAllocatePoolWithQuotaTag(type, size, tag)
"IoAllocateMdl", // IoAllocateMdl(address, size, flag, flag, irp)
"IoAllocateErrorLogEntry", // IoAllocateErrorLogEntry(object, size)
// --- Windows Global / Local legacy allocation
"LocalAlloc", // LocalAlloc(flags, size)
"GlobalAlloc", // GlobalAlloc(flags, size)
// --- Windows System Services allocation
"VirtualAlloc" // VirtualAlloc(address, size, type, flag)
]) and
sizeArg = 1
or
hasGlobalName(["HeapAlloc"]) and // HeapAlloc(heap, flags, size)
sizeArg = 2
or
hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"MmAllocatePagesForMdl", // MmAllocatePagesForMdl(minaddress, maxaddress, skip, size)
"MmAllocatePagesForMdlEx", // MmAllocatePagesForMdlEx(minaddress, maxaddress, skip, size, type, flags)
"MmAllocateNodePagesForMdlEx" // MmAllocateNodePagesForMdlEx(minaddress, maxaddress, skip, size, type, prefer, flags)
]) and
sizeArg = 3
}
override int getSizeArg() { result = sizeArg }
@@ -116,16 +79,14 @@ private class AllocaAllocationFunction extends AllocationFunction {
int sizeArg;
AllocaAllocationFunction() {
exists(string name |
hasGlobalName(name) and
(
// alloca(size)
name = "alloca" and sizeArg = 0
or
// __builtin_alloca(size)
name = "__builtin_alloca" and sizeArg = 0
)
)
hasGlobalName([
// --- stack allocation
"alloca", // // alloca(size)
"__builtin_alloca", // __builtin_alloca(size)
"_alloca", // _alloca(size)
"_malloca" // _malloca(size)
]) and
sizeArg = 0
}
override int getSizeArg() { result = sizeArg }
@@ -142,11 +103,10 @@ private class CallocAllocationFunction extends AllocationFunction {
int multArg;
CallocAllocationFunction() {
exists(string name |
hasGlobalOrStdName(name) and
// calloc(num, size)
(name = "calloc" and sizeArg = 1 and multArg = 0)
)
// --- C library allocation
hasGlobalOrStdName("calloc") and // calloc(num, size)
sizeArg = 1 and
multArg = 0
}
override int getSizeArg() { result = sizeArg }
@@ -163,29 +123,26 @@ private class ReallocAllocationFunction extends AllocationFunction {
int reallocArg;
ReallocAllocationFunction() {
exists(string name |
hasGlobalOrStdName(name) and
// realloc(ptr, size)
(name = "realloc" and sizeArg = 1 and reallocArg = 0)
or
hasGlobalName(name) and
(
// LocalReAlloc(ptr, size, flags)
name = "LocalReAlloc" and sizeArg = 1 and reallocArg = 0
or
// GlobalReAlloc(ptr, size, flags)
name = "GlobalReAlloc" and sizeArg = 1 and reallocArg = 0
or
// HeapReAlloc(heap, flags, ptr, size)
name = "HeapReAlloc" and sizeArg = 3 and reallocArg = 2
or
// CoTaskMemRealloc(ptr, size)
name = "CoTaskMemRealloc" and sizeArg = 1 and reallocArg = 0
or
// CRYPTO_realloc(void *addr, size_t num, const char *file, int line);
name = "CRYPTO_realloc" and sizeArg = 1 and reallocArg = 0
)
)
// --- C library allocation
hasGlobalOrStdName("realloc") and // realloc(ptr, size)
sizeArg = 1 and
reallocArg = 0
or
hasGlobalName([
// --- Windows Global / Local legacy allocation
"LocalReAlloc", // LocalReAlloc(ptr, size, flags)
"GlobalReAlloc", // GlobalReAlloc(ptr, size, flags)
// --- Windows COM allocation
"CoTaskMemRealloc", // CoTaskMemRealloc(ptr, size)
// --- OpenSSL memory allocation
"CRYPTO_realloc" // CRYPTO_realloc(void *addr, size_t num, const char *file, int line)
]) and
sizeArg = 1 and
reallocArg = 0
or
hasGlobalName("HeapReAlloc") and // HeapReAlloc(heap, flags, ptr, size)
sizeArg = 3 and
reallocArg = 2
}
override int getSizeArg() { result = sizeArg }
@@ -199,40 +156,20 @@ private class ReallocAllocationFunction extends AllocationFunction {
*/
private class SizelessAllocationFunction extends AllocationFunction {
SizelessAllocationFunction() {
exists(string name |
hasGlobalName(name) and
(
// ExAllocateFromLookasideListEx(list)
name = "ExAllocateFromLookasideListEx"
or
// ExAllocateFromPagedLookasideList(list)
name = "ExAllocateFromPagedLookasideList"
or
// ExAllocateFromNPagedLookasideList(list)
name = "ExAllocateFromNPagedLookasideList"
or
// ExAllocateTimer(callback, context, attributes)
name = "ExAllocateTimer"
or
// IoAllocateWorkItem(object)
name = "IoAllocateWorkItem"
or
// MmMapLockedPagesWithReservedMapping(address, tag, list, type)
name = "MmMapLockedPagesWithReservedMapping"
or
// MmMapLockedPages(list, mode)
name = "MmMapLockedPages"
or
// MmMapLockedPagesSpecifyCache(list, mode, type, address, flag, flag)
name = "MmMapLockedPagesSpecifyCache"
or
// pool_get(pool, flags)
name = "pool_get"
or
// pool_cache_get(pool, flags)
name = "pool_cache_get"
)
)
hasGlobalName([
// --- Windows Memory Management for Windows Drivers
"ExAllocateFromLookasideListEx", // ExAllocateFromLookasideListEx(list)
"ExAllocateFromPagedLookasideList", // ExAllocateFromPagedLookasideList(list)
"ExAllocateFromNPagedLookasideList", // ExAllocateFromNPagedLookasideList(list)
"ExAllocateTimer", // ExAllocateTimer(callback, context, attributes)
"IoAllocateWorkItem", // IoAllocateWorkItem(object)
"MmMapLockedPagesWithReservedMapping", // MmMapLockedPagesWithReservedMapping(address, tag, list, type)
"MmMapLockedPages", // MmMapLockedPages(list, mode)
"MmMapLockedPagesSpecifyCache", // MmMapLockedPagesSpecifyCache(list, mode, type, address, flag, flag)
// --- NetBSD pool manager
"pool_get", // pool_get(pool, flags)
"pool_cache_get" // pool_cache_get(pool, flags)
])
}
}

View File

@@ -13,77 +13,43 @@ private class StandardDeallocationFunction extends DeallocationFunction {
int freedArg;
StandardDeallocationFunction() {
exists(string name |
hasGlobalName(name) and
(
name = "free" and freedArg = 0
or
name = "realloc" and freedArg = 0
or
name = "CRYPTO_free" and freedArg = 0
or
name = "CRYPTO_secure_free" and freedArg = 0
)
or
hasGlobalOrStdName(name) and
(
name = "ExFreePoolWithTag" and freedArg = 0
or
name = "ExFreeToLookasideListEx" and freedArg = 1
or
name = "ExFreeToPagedLookasideList" and freedArg = 1
or
name = "ExFreeToNPagedLookasideList" and freedArg = 1
or
name = "ExDeleteTimer" and freedArg = 0
or
name = "IoFreeMdl" and freedArg = 0
or
name = "IoFreeWorkItem" and freedArg = 0
or
name = "IoFreeErrorLogEntry" and freedArg = 0
or
name = "MmFreeContiguousMemory" and freedArg = 0
or
name = "MmFreeContiguousMemorySpecifyCache" and freedArg = 0
or
name = "MmFreeNonCachedMemory" and freedArg = 0
or
name = "MmFreeMappingAddress" and freedArg = 0
or
name = "MmFreePagesFromMdl" and freedArg = 0
or
name = "MmUnmapReservedMapping" and freedArg = 0
or
name = "MmUnmapLockedPages" and freedArg = 0
or
name = "LocalFree" and freedArg = 0
or
name = "GlobalFree" and freedArg = 0
or
name = "HeapFree" and freedArg = 2
or
name = "VirtualFree" and freedArg = 0
or
name = "CoTaskMemFree" and freedArg = 0
or
name = "SysFreeString" and freedArg = 0
or
name = "LocalReAlloc" and freedArg = 0
or
name = "GlobalReAlloc" and freedArg = 0
or
name = "HeapReAlloc" and freedArg = 2
or
name = "CoTaskMemRealloc" and freedArg = 0
or
name = "kmem_free" and freedArg = 0
or
name = "pool_put" and freedArg = 1
or
name = "pool_cache_put" and freedArg = 1
)
)
hasGlobalName([
// --- C library allocation
"free", "realloc",
// --- OpenSSL memory allocation
"CRYPTO_free", "CRYPTO_secure_free"
]) and
freedArg = 0
or
hasGlobalOrStdName([
// --- Windows Memory Management for Windows Drivers
"ExFreePoolWithTag", "ExDeleteTimer", "IoFreeMdl", "IoFreeWorkItem", "IoFreeErrorLogEntry",
"MmFreeContiguousMemory", "MmFreeContiguousMemorySpecifyCache", "MmFreeNonCachedMemory",
"MmFreeMappingAddress", "MmFreePagesFromMdl", "MmUnmapReservedMapping",
"MmUnmapLockedPages",
// --- Windows Global / Local legacy allocation
"LocalFree", "GlobalFree", "LocalReAlloc", "GlobalReAlloc",
// --- Windows System Services allocation
"VirtualFree",
// --- Windows COM allocation
"CoTaskMemFree", "CoTaskMemRealloc",
// --- Windows Automation
"SysFreeString",
// --- Solaris/BSD kernel memory allocator
"kmem_free"
]) and
freedArg = 0
or
hasGlobalOrStdName([
// --- Windows Memory Management for Windows Drivers
"ExFreeToLookasideListEx", "ExFreeToPagedLookasideList", "ExFreeToNPagedLookasideList",
// --- NetBSD pool manager
"pool_put", "pool_cache_put"
]) and
freedArg = 1
or
hasGlobalOrStdName(["HeapFree", "HeapReAlloc"]) and
freedArg = 2
}
override int getFreedArg() { result = freedArg }

View File

@@ -58,8 +58,7 @@ private class IteratorByTraits extends Iterator {
private FunctionInput getIteratorArgumentInput(Operator op, int index) {
exists(Type t |
t =
op
.getACallToThisFunction()
op.getACallToThisFunction()
.getArgument(index)
.getExplicitlyConverted()
.getType()
@@ -307,11 +306,10 @@ private class IteratorAssignmentMemberOperator extends MemberFunction, TaintFunc
*/
private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetIteratorFunction {
BeginOrEndFunction() {
this
.hasName([
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
"cbefore_begin"
]) and
this.hasName([
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
"cbefore_begin"
]) and
this.getType().getUnspecifiedType() instanceof Iterator
}

View File

@@ -15,13 +15,8 @@ import semmle.code.cpp.models.interfaces.SideEffect
private class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction,
SideEffectFunction {
MemsetFunction() {
hasGlobalName("memset") or
hasGlobalName("wmemset") or
hasGlobalName("bzero") or
hasGlobalName("__builtin_memset") or
hasGlobalName("__builtin_memset_chk") or
hasQualifiedName("std", "memset") or
hasQualifiedName("std", "wmemset")
hasGlobalName(["memset", "wmemset", "bzero", "__builtin_memset", "__builtin_memset_chk"]) or
hasQualifiedName("std", ["memset", "wmemset"])
}
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }

View File

@@ -11,15 +11,12 @@ import semmle.code.cpp.models.interfaces.Alias
/**
* The standard functions `printf`, `wprintf` and their glib variants.
*/
class Printf extends FormattingFunction, AliasFunction {
private class Printf extends FormattingFunction, AliasFunction {
Printf() {
this instanceof TopLevelFunction and
(
hasGlobalOrStdName("printf") or
hasGlobalName("printf_s") or
hasGlobalOrStdName("wprintf") or
hasGlobalName("wprintf_s") or
hasGlobalName("g_printf")
hasGlobalOrStdName(["printf", "wprintf"]) or
hasGlobalName(["printf_s", "wprintf_s", "g_printf"])
) and
not exists(getDefinition().getFile().getRelativePath())
}
@@ -31,6 +28,8 @@ class Printf extends FormattingFunction, AliasFunction {
hasGlobalName("wprintf_s")
}
override predicate isOutputGlobal() { any() }
override predicate parameterNeverEscapes(int n) { n = 0 }
override predicate parameterEscapesOnlyViaReturn(int n) { none() }
@@ -41,12 +40,11 @@ class Printf extends FormattingFunction, AliasFunction {
/**
* The standard functions `fprintf`, `fwprintf` and their glib variants.
*/
class Fprintf extends FormattingFunction {
private class Fprintf extends FormattingFunction {
Fprintf() {
this instanceof TopLevelFunction and
(
hasGlobalOrStdName("fprintf") or
hasGlobalOrStdName("fwprintf") or
hasGlobalOrStdName(["fprintf", "fwprintf"]) or
hasGlobalName("g_fprintf")
) and
not exists(getDefinition().getFile().getRelativePath())
@@ -56,7 +54,7 @@ class Fprintf extends FormattingFunction {
deprecated override predicate isWideCharDefault() { hasGlobalOrStdName("fwprintf") }
override int getOutputParameterIndex() { result = 0 }
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = true }
}
/**
@@ -66,26 +64,18 @@ private class Sprintf extends FormattingFunction {
Sprintf() {
this instanceof TopLevelFunction and
(
// sprintf(dst, format, args...)
hasGlobalOrStdName("sprintf")
hasGlobalOrStdName([
"sprintf", // sprintf(dst, format, args...)
"wsprintf" // wsprintf(dst, format, args...)
])
or
// _sprintf_l(dst, format, locale, args...)
hasGlobalName("_sprintf_l")
or
// __swprintf_l(dst, format, locale, args...)
hasGlobalName("__swprintf_l")
or
// wsprintf(dst, format, args...)
hasGlobalOrStdName("wsprintf")
or
// g_strdup_printf(format, ...)
hasGlobalName("g_strdup_printf")
or
// g_sprintf(dst, format, ...)
hasGlobalName("g_sprintf")
or
// __builtin___sprintf_chk(dst, flag, os, format, ...)
hasGlobalName("__builtin___sprintf_chk")
hasGlobalName([
"_sprintf_l", // _sprintf_l(dst, format, locale, args...)
"__swprintf_l", // __swprintf_l(dst, format, locale, args...)
"g_strdup_printf", // g_strdup_printf(format, ...)
"g_sprintf", // g_sprintf(dst, format, ...)
"__builtin___sprintf_chk" // __builtin___sprintf_chk(dst, flag, os, format, ...)
])
) and
not exists(getDefinition().getFile().getRelativePath())
}
@@ -104,12 +94,13 @@ private class Sprintf extends FormattingFunction {
or
hasGlobalName("__builtin___sprintf_chk") and result = 3
or
getName() != "g_strdup_printf" and
getName() != "__builtin___sprintf_chk" and
not getName() = ["g_strdup_printf", "__builtin___sprintf_chk"] and
result = 1
}
override int getOutputParameterIndex() { not hasGlobalName("g_strdup_printf") and result = 0 }
override int getOutputParameterIndex(boolean isStream) {
not hasGlobalName("g_strdup_printf") and result = 0 and isStream = false
}
override int getFirstFormatArgumentIndex() {
if hasGlobalName("__builtin___sprintf_chk")
@@ -125,26 +116,18 @@ private class SnprintfImpl extends Snprintf {
SnprintfImpl() {
this instanceof TopLevelFunction and
(
hasGlobalOrStdName("snprintf") or // C99 defines snprintf
hasGlobalOrStdName("swprintf") or // The s version of wide-char printf is also always the n version
hasGlobalOrStdName([
"snprintf", // C99 defines snprintf
"swprintf" // The s version of wide-char printf is also always the n version
])
or
// Microsoft has _snprintf as well as several other variations
hasGlobalName("sprintf_s") or
hasGlobalName("snprintf_s") or
hasGlobalName("swprintf_s") or
hasGlobalName("_snprintf") or
hasGlobalName("_snprintf_s") or
hasGlobalName("_snprintf_l") or
hasGlobalName("_snprintf_s_l") or
hasGlobalName("_snwprintf") or
hasGlobalName("_snwprintf_s") or
hasGlobalName("_snwprintf_l") or
hasGlobalName("_snwprintf_s_l") or
hasGlobalName("_sprintf_s_l") or
hasGlobalName("_swprintf_l") or
hasGlobalName("_swprintf_s_l") or
hasGlobalName("g_snprintf") or
hasGlobalName("wnsprintf") or
hasGlobalName("__builtin___snprintf_chk")
hasGlobalName([
"sprintf_s", "snprintf_s", "swprintf_s", "_snprintf", "_snprintf_s", "_snprintf_l",
"_snprintf_s_l", "_snwprintf", "_snwprintf_s", "_snwprintf_l", "_snwprintf_s_l",
"_sprintf_s_l", "_swprintf_l", "_swprintf_s_l", "g_snprintf", "wnsprintf",
"__builtin___snprintf_chk"
])
) and
not exists(getDefinition().getFile().getRelativePath())
}
@@ -164,7 +147,7 @@ private class SnprintfImpl extends Snprintf {
.getSize() > 1
}
override int getOutputParameterIndex() { result = 0 }
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
override int getFirstFormatArgumentIndex() {
exists(string name |
@@ -182,9 +165,7 @@ private class SnprintfImpl extends Snprintf {
override predicate returnsFullFormatLength() {
(
hasGlobalOrStdName("snprintf") or
hasGlobalName("g_snprintf") or
hasGlobalName("__builtin___snprintf_chk") or
hasGlobalName("snprintf_s")
hasGlobalName(["g_snprintf", "__builtin___snprintf_chk", "snprintf_s"])
) and
not exists(getDefinition().getFile().getRelativePath())
}
@@ -198,16 +179,10 @@ private class SnprintfImpl extends Snprintf {
private class StringCchPrintf extends FormattingFunction {
StringCchPrintf() {
this instanceof TopLevelFunction and
(
hasGlobalName("StringCchPrintf") or
hasGlobalName("StringCchPrintfEx") or
hasGlobalName("StringCchPrintf_l") or
hasGlobalName("StringCchPrintf_lEx") or
hasGlobalName("StringCbPrintf") or
hasGlobalName("StringCbPrintfEx") or
hasGlobalName("StringCbPrintf_l") or
hasGlobalName("StringCbPrintf_lEx")
) and
hasGlobalName([
"StringCchPrintf", "StringCchPrintfEx", "StringCchPrintf_l", "StringCchPrintf_lEx",
"StringCbPrintf", "StringCbPrintfEx", "StringCbPrintf_l", "StringCbPrintf_lEx"
]) and
not exists(getDefinition().getFile().getRelativePath())
}
@@ -224,7 +199,7 @@ private class StringCchPrintf extends FormattingFunction {
.getSize() > 1
}
override int getOutputParameterIndex() { result = 0 }
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = false }
override int getSizeParameterIndex() { result = 1 }
}
@@ -232,7 +207,7 @@ private class StringCchPrintf extends FormattingFunction {
/**
* The standard function `syslog`.
*/
class Syslog extends FormattingFunction {
private class Syslog extends FormattingFunction {
Syslog() {
this instanceof TopLevelFunction and
hasGlobalName("syslog") and
@@ -240,4 +215,6 @@ class Syslog extends FormattingFunction {
}
override int getFormatParameterIndex() { result = 1 }
override predicate isOutputGlobal() { any() }
}

View File

@@ -69,10 +69,8 @@ private class StdSequenceContainerData extends TaintFunction {
*/
private class StdSequenceContainerPush extends TaintFunction {
StdSequenceContainerPush() {
this.hasQualifiedName("std", "vector", "push_back") or
this.hasQualifiedName("std", "deque", ["push_back", "push_front"]) or
this.hasQualifiedName("std", "list", ["push_back", "push_front"]) or
this.hasQualifiedName("std", "forward_list", "push_front")
this.hasQualifiedName("std", ["vector", "deque", "list"], "push_back") or
this.hasQualifiedName("std", ["deque", "list", "forward_list"], "push_front")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -87,11 +85,8 @@ private class StdSequenceContainerPush extends TaintFunction {
*/
private class StdSequenceContainerFrontBack extends TaintFunction {
StdSequenceContainerFrontBack() {
this.hasQualifiedName("std", "array", ["front", "back"]) or
this.hasQualifiedName("std", "vector", ["front", "back"]) or
this.hasQualifiedName("std", "deque", ["front", "back"]) or
this.hasQualifiedName("std", "list", ["front", "back"]) or
this.hasQualifiedName("std", "forward_list", "front")
this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "front") or
this.hasQualifiedName("std", ["array", "vector", "deque", "list"], "back")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -107,7 +102,7 @@ private class StdSequenceContainerFrontBack extends TaintFunction {
private class StdSequenceContainerInsert extends TaintFunction {
StdSequenceContainerInsert() {
this.hasQualifiedName("std", ["vector", "deque", "list"], "insert") or
this.hasQualifiedName("std", ["forward_list"], "insert_after")
this.hasQualifiedName("std", "forward_list", "insert_after")
}
/**
@@ -170,24 +165,6 @@ private class StdSequenceContainerAssign extends TaintFunction {
}
}
/**
* The standard container `swap` functions.
*/
private class StdSequenceContainerSwap extends TaintFunction {
StdSequenceContainerSwap() {
this.hasQualifiedName("std", ["array", "vector", "deque", "list", "forward_list"], "swap")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// container1.swap(container2)
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
}
/**
* The standard container functions `at` and `operator[]`.
*/

View File

@@ -102,22 +102,6 @@ private class StdMapTryEmplace extends TaintFunction {
}
}
/**
* The standard map `swap` function.
*/
private class StdMapSwap extends TaintFunction {
StdMapSwap() { this.hasQualifiedName("std", ["map", "unordered_map"], "swap") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// container1.swap(container2)
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
}
/**
* The standard map `merge` function.
*/
@@ -179,9 +163,8 @@ private class StdMapErase extends TaintFunction {
*/
private class StdMapEqualRange extends TaintFunction {
StdMapEqualRange() {
this
.hasQualifiedName("std", ["map", "unordered_map"],
["lower_bound", "upper_bound", "equal_range"])
this.hasQualifiedName("std", ["map", "unordered_map"],
["lower_bound", "upper_bound", "equal_range"])
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {

View File

@@ -60,19 +60,3 @@ private class StdPairConstructor extends Constructor, TaintFunction {
)
}
}
/**
* The standard pair `swap` function.
*/
private class StdPairSwap extends TaintFunction {
StdPairSwap() { this.hasQualifiedName("std", "pair", "swap") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// container1.swap(container2)
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
}

View File

@@ -72,22 +72,6 @@ private class StdSetEmplace extends TaintFunction {
}
}
/**
* The standard set `swap` functions.
*/
private class StdSetSwap extends TaintFunction {
StdSetSwap() { this.hasQualifiedName("std", ["set", "unordered_set"], "swap") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// container1.swap(container2)
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
}
/**
* The standard set `merge` function.
*/
@@ -132,9 +116,8 @@ private class StdSetErase extends TaintFunction {
*/
private class StdSetEqualRange extends TaintFunction {
StdSetEqualRange() {
this
.hasQualifiedName("std", ["set", "unordered_set"],
["lower_bound", "upper_bound", "equal_range"])
this.hasQualifiedName("std", ["set", "unordered_set"],
["lower_bound", "upper_bound", "equal_range"])
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {

View File

@@ -269,25 +269,6 @@ private class StdBasicStringStream extends TemplateClass {
}
}
/**
* The standard functions `std::string.swap` and `std::stringstream::swap`.
*/
private class StdStringSwap extends TaintFunction {
StdStringSwap() {
this = any(StdBasicString s).getAnInstMemberNamed("swap") or
this = any(StdBasicStringStream s).getAnInstMemberNamed("swap")
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
// str1.swap(str2)
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
}
/**
* The `std::string` functions `at` and `operator[]`.
*/

View File

@@ -13,15 +13,16 @@ import semmle.code.cpp.models.interfaces.SideEffect
*/
class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, SideEffectFunction {
StrcatFunction() {
exists(string name | name = getName() |
name = "strcat" or // strcat(dst, src)
name = "strncat" or // strncat(dst, src, max_amount)
name = "wcscat" or // wcscat(dst, src)
name = "_mbscat" or // _mbscat(dst, src)
name = "wcsncat" or // wcsncat(dst, src, max_amount)
name = "_mbsncat" or // _mbsncat(dst, src, max_amount)
name = "_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale)
)
getName() =
[
"strcat", // strcat(dst, src)
"strncat", // strncat(dst, src, max_amount)
"wcscat", // wcscat(dst, src)
"_mbscat", // _mbscat(dst, src)
"wcsncat", // wcsncat(dst, src, max_amount)
"_mbsncat", // _mbsncat(dst, src, max_amount)
"_mbsncat_l" // _mbsncat_l(dst, src, max_amount, locale)
]
}
/**
@@ -45,20 +46,13 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction, Sid
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(string name | name = getName() |
(
name = "strncat" or
name = "wcsncat" or
name = "_mbsncat" or
name = "_mbsncat_l"
) and
input.isParameter(2) and
output.isParameterDeref(0)
or
name = "_mbsncat_l" and
input.isParameter(3) and
output.isParameterDeref(0)
)
getName() = ["strncat", "wcsncat", "_mbsncat", "_mbsncat_l"] and
input.isParameter(2) and
output.isParameterDeref(0)
or
getName() = "_mbsncat_l" and
input.isParameter(3) and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isParameterDeref(0)

View File

@@ -13,25 +13,14 @@ import semmle.code.cpp.models.interfaces.Taint
*/
private class StrdupFunction extends AllocationFunction, ArrayFunction, DataFlowFunction {
StrdupFunction() {
exists(string name |
hasGlobalName(name) and
(
// strdup(str)
name = "strdup"
or
// wcsdup(str)
name = "wcsdup"
or
// _strdup(str)
name = "_strdup"
or
// _wcsdup(str)
name = "_wcsdup"
or
// _mbsdup(str)
name = "_mbsdup"
)
)
hasGlobalName([
// --- C library allocation
"strdup", // strdup(str)
"wcsdup", // wcsdup(str)
"_strdup", // _strdup(str)
"_wcsdup", // _wcsdup(str)
"_mbsdup" // _mbsdup(str)
])
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
@@ -51,8 +40,8 @@ private class StrndupFunction extends AllocationFunction, ArrayFunction, DataFlo
StrndupFunction() {
exists(string name |
hasGlobalName(name) and
// strndup(str, maxlen)
name = "strndup"
// --- C library allocation
name = "strndup" // strndup(str, maxlen)
)
}

View File

@@ -1,8 +1,12 @@
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.Alias
/**
* The standard function `swap`.
* The standard function `swap`. A use of `swap` looks like this:
* ```
* std::swap(obj1, obj2)
* ```
*/
private class Swap extends DataFlowFunction {
Swap() { this.hasQualifiedName("std", "swap") }
@@ -15,3 +19,32 @@ private class Swap extends DataFlowFunction {
output.isParameterDeref(0)
}
}
/**
* A `swap` member function that is used as follows:
* ```
* obj1.swap(obj2)
* ```
*/
private class MemberSwap extends TaintFunction, MemberFunction, AliasFunction {
MemberSwap() {
this.hasName("swap") and
this.getNumberOfParameters() = 1 and
this.getParameter(0).getType().(ReferenceType).getBaseType().getUnspecifiedType() =
getDeclaringType()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isQualifierObject() and
output.isParameterDeref(0)
or
input.isParameterDeref(0) and
output.isQualifierObject()
}
override predicate parameterNeverEscapes(int index) { none() }
override predicate parameterEscapesOnlyViaReturn(int index) { index = 0 }
override predicate parameterIsAlwaysReturned(int index) { index = 0 }
}

View File

@@ -93,16 +93,10 @@ abstract class AllocationExpr extends Expr {
*/
class OperatorNewAllocationFunction extends AllocationFunction {
OperatorNewAllocationFunction() {
exists(string name |
hasGlobalName(name) and
(
// operator new(bytes, ...)
name = "operator new"
or
// operator new[](bytes, ...)
name = "operator new[]"
)
)
hasGlobalName([
"operator new", // operator new(bytes, ...)
"operator new[]" // operator new[](bytes, ...)
])
}
override int getSizeArg() { result = 0 }

View File

@@ -38,16 +38,10 @@ abstract class DeallocationExpr extends Expr {
*/
class OperatorDeleteDeallocationFunction extends DeallocationFunction {
OperatorDeleteDeallocationFunction() {
exists(string name |
hasGlobalName(name) and
(
// operator delete(pointer, ...)
name = "operator delete"
or
// operator delete[](pointer, ...)
name = "operator delete[]"
)
)
hasGlobalName([
"operator delete", // operator delete(pointer, ...)
"operator delete[]" // operator delete[](pointer, ...)
])
}
override int getFreedArg() { result = 0 }

View File

@@ -109,9 +109,25 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
}
/**
* Gets the position at which the output parameter, if any, occurs.
* Gets the position at which the output parameter, if any, occurs. If
* `isStream` is `true`, the output parameter is a stream (that is, this
* function behaves like `fprintf`). If `isStream` is `false`, the output
* parameter is a buffer (that is, this function behaves like `sprintf`).
*/
int getOutputParameterIndex() { none() }
int getOutputParameterIndex(boolean isStream) { none() }
/**
* Gets the position at which the output parameter, if any, occurs.
*
* DEPRECATED: use `getOutputParameterIndex(boolean isStream)` instead.
*/
deprecated int getOutputParameterIndex() { result = getOutputParameterIndex(_) }
/**
* Holds if this function outputs to a global stream such as standard output,
* standard error or a system log. For example `printf`.
*/
predicate isOutputGlobal() { none() }
/**
* Gets the position of the first format argument, corresponding with
@@ -141,18 +157,18 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = getOutputParameterIndex() and
bufParam = getOutputParameterIndex(false) and
countParam = getSizeParameterIndex()
}
override predicate hasArrayWithUnknownSize(int bufParam) {
bufParam = getOutputParameterIndex() and
bufParam = getOutputParameterIndex(false) and
not exists(getSizeParameterIndex())
}
override predicate hasArrayInput(int bufParam) { bufParam = getFormatParameterIndex() }
override predicate hasArrayOutput(int bufParam) { bufParam = getOutputParameterIndex() }
override predicate hasArrayOutput(int bufParam) { bufParam = getOutputParameterIndex(false) }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(int arg |
@@ -161,7 +177,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
arg >= getFirstFormatArgumentIndex()
) and
input.isParameterDeref(arg) and
output.isParameterDeref(getOutputParameterIndex())
output.isParameterDeref(getOutputParameterIndex(_))
)
}
}

View File

@@ -585,6 +585,12 @@ private float addRoundingDownSmall(float x, float small) {
if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small)
}
private predicate lowerBoundableExpr(Expr expr) {
analyzableExpr(expr) and
getUpperBoundsImpl(expr) <= exprMaxVal(expr) and
not exists(getValue(expr).toFloat())
}
/**
* Gets the lower bounds of the expression.
*
@@ -603,41 +609,42 @@ private float addRoundingDownSmall(float x, float small) {
* this predicate.
*/
private float getTruncatedLowerBounds(Expr expr) {
if analyzableExpr(expr)
then
// If the expression evaluates to a constant, then there is no
// need to call getLowerBoundsImpl.
if exists(getValue(expr).toFloat())
then result = getValue(expr).toFloat()
else (
// Some of the bounds computed by getLowerBoundsImpl might
// overflow, so we replace invalid bounds with exprMinVal.
exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) |
if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr)
then
// Apply widening where we might get a combinatorial explosion.
if isRecursiveBinary(expr)
then
result =
max(float widenLB |
widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and
not widenLB > newLB
)
else result = newLB
else result = exprMinVal(expr)
)
or
// The expression might overflow and wrap. If so, the
// lower bound is exprMinVal.
exprMightOverflowPositively(expr) and
result = exprMinVal(expr)
)
else
// The expression is not analyzable, so its lower bound is
// unknown. Note that the call to exprMinVal restricts the
// expressions to just those with arithmetic types. There is no
// need to return results for non-arithmetic expressions.
result = exprMinVal(expr)
// If the expression evaluates to a constant, then there is no
// need to call getLowerBoundsImpl.
analyzableExpr(expr) and
result = getValue(expr).toFloat()
or
// Some of the bounds computed by getLowerBoundsImpl might
// overflow, so we replace invalid bounds with exprMinVal.
exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) |
if exprMinVal(expr) <= newLB and newLB <= exprMaxVal(expr)
then
// Apply widening where we might get a combinatorial explosion.
if isRecursiveBinary(expr)
then
result =
max(float widenLB |
widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and
not widenLB > newLB
)
else result = newLB
else result = exprMinVal(expr)
) and
lowerBoundableExpr(expr)
or
// The expression might overflow and wrap. If so, the
// lower bound is exprMinVal.
analyzableExpr(expr) and
exprMightOverflowPositively(expr) and
not result = getValue(expr).toFloat() and
result = exprMinVal(expr)
or
// The expression is not analyzable, so its lower bound is
// unknown. Note that the call to exprMinVal restricts the
// expressions to just those with arithmetic types. There is no
// need to return results for non-arithmetic expressions.
not analyzableExpr(expr) and
result = exprMinVal(expr)
}
/**

View File

@@ -42,13 +42,11 @@ abstract class BufferAccess extends Expr {
*/
class MemcpyBA extends BufferAccess {
MemcpyBA() {
this.(FunctionCall).getTarget().getName() = "memcpy" or
this.(FunctionCall).getTarget().getName() = "wmemcpy" or
this.(FunctionCall).getTarget().getName() = "memmove" or
this.(FunctionCall).getTarget().getName() = "wmemmove" or
this.(FunctionCall).getTarget().getName() = "mempcpy" or
this.(FunctionCall).getTarget().getName() = "wmempcpy" or
this.(FunctionCall).getTarget().getName() = "RtlCopyMemoryNonTemporal"
this.(FunctionCall).getTarget().getName() =
[
"memcpy", "wmemcpy", "memmove", "wmemmove", "mempcpy", "wmempcpy",
"RtlCopyMemoryNonTemporal"
]
}
override string getName() { result = this.(FunctionCall).getTarget().getName() }
@@ -157,10 +155,7 @@ class MemccpyBA extends BufferAccess {
*/
class MemcmpBA extends BufferAccess {
MemcmpBA() {
this.(FunctionCall).getTarget().getName() = "memcmp" or
this.(FunctionCall).getTarget().getName() = "wmemcmp" or
this.(FunctionCall).getTarget().getName() = "_memicmp" or
this.(FunctionCall).getTarget().getName() = "_memicmp_l"
this.(FunctionCall).getTarget().getName() = ["memcmp", "wmemcmp", "_memicmp", "_memicmp_l"]
}
override string getName() { result = this.(FunctionCall).getTarget().getName() }
@@ -188,10 +183,7 @@ class MemcmpBA extends BufferAccess {
* _swab(src, dest, num)
*/
class SwabBA extends BufferAccess {
SwabBA() {
this.(FunctionCall).getTarget().getName() = "swab" or
this.(FunctionCall).getTarget().getName() = "_swab"
}
SwabBA() { this.(FunctionCall).getTarget().getName() = ["swab", "_swab"] }
override string getName() { result = this.(FunctionCall).getTarget().getName() }
@@ -218,10 +210,7 @@ class SwabBA extends BufferAccess {
* wmemset(dest, value, num)
*/
class MemsetBA extends BufferAccess {
MemsetBA() {
this.(FunctionCall).getTarget().getName() = "memset" or
this.(FunctionCall).getTarget().getName() = "wmemset"
}
MemsetBA() { this.(FunctionCall).getTarget().getName() = ["memset", "wmemset"] }
override string getName() { result = this.(FunctionCall).getTarget().getName() }
@@ -262,10 +251,7 @@ class ZeroMemoryBA extends BufferAccess {
* wmemchr(buffer, value, num)
*/
class MemchrBA extends BufferAccess {
MemchrBA() {
this.(FunctionCall).getTarget().getName() = "memchr" or
this.(FunctionCall).getTarget().getName() = "wmemchr"
}
MemchrBA() { this.(FunctionCall).getTarget().getName() = ["memchr", "wmemchr"] }
override string getName() { result = this.(FunctionCall).getTarget().getName() }

View File

@@ -229,7 +229,7 @@ class SprintfBW extends BufferWriteCall {
result = this.(FormattingFunctionCall).getFormatArgument(_)
}
override Expr getDest() { result = getArgument(f.getOutputParameterIndex()) }
override Expr getDest() { result = getArgument(f.getOutputParameterIndex(false)) }
override int getMaxData() {
exists(FormatLiteral fl |

View File

@@ -168,17 +168,14 @@ class ArrayExecFunctionCall extends FunctionCall {
* for testing purposes.
*/
predicate shellCommandPreface(string cmd, string flag) {
(cmd = "sh" or cmd = "/bin/sh" or cmd = "bash" or cmd = "/bin/bash") and
cmd = ["sh", "/bin/sh", "bash", "/bin/bash"] and
flag = "-c"
or
(
cmd = "cmd" or
cmd = "cmd.exe" or
cmd = "CMD" or
cmd = "CMD.EXE" or
cmd = "%WINDIR%\\system32\\cmd.exe" // used in Juliet tests
) and
(flag = "/c" or flag = "/C")
cmd =
[
"cmd", "cmd.exe", "CMD", "CMD.EXE", "%WINDIR%\\system32\\cmd.exe" // used in Juliet tests
] and
flag = ["/c", "/C"]
}
/**

View File

@@ -8,21 +8,17 @@ import cpp
* Gets the name of an algorithm that is known to be insecure.
*/
string getAnInsecureAlgorithmName() {
result = "DES" or
result = "RC2" or
result = "RC4" or
result = "RC5" or
result = "ARCFOUR" // a variant of RC4
result =
[
"DES", "RC2", "RC4", "RC5", "ARCFOUR" // ARCFOUR is a variant of RC4
]
}
/**
* Gets the name of a hash algorithm that is insecure if it is being used for
* encryption (but it is hard to know when that is happening).
*/
string getAnInsecureHashAlgorithmName() {
result = "SHA1" or
result = "MD5"
}
string getAnInsecureHashAlgorithmName() { result = ["SHA1", "MD5"] }
/**
* Gets the regular expression used for matching strings that look like they
@@ -45,13 +41,7 @@ string getInsecureAlgorithmRegex() {
* Gets the name of an algorithm that is known to be secure.
*/
string getASecureAlgorithmName() {
result = "RSA" or
result = "SHA256" or
result = "CCM" or
result = "GCM" or
result = "AES" or
result = "Blowfish" or
result = "ECIES"
result = ["RSA", "SHA256", "CCM", "GCM", "AES", "Blowfish", "ECIES"]
}
/**

View File

@@ -3,7 +3,6 @@
*/
import cpp
import semmle.code.cpp.models.implementations.Printf
/**
* A function call that writes to a file.
@@ -144,8 +143,8 @@ private predicate fileWrite(Call write, Expr source, Expr dest) {
)
or
// fprintf
s >= f.(Fprintf).getFormatParameterIndex() and
d = f.(Fprintf).getOutputParameterIndex()
s >= f.(FormattingFunction).getFormatParameterIndex() and
d = f.(FormattingFunction).getOutputParameterIndex(true)
)
or
// file stream using '<<', 'put' or 'write'

View File

@@ -59,11 +59,9 @@ private predicate outputWrite(Expr write, Expr source) {
exists(Function f, int arg |
f = write.(Call).getTarget() and source = write.(Call).getArgument(arg)
|
// printf
arg >= f.(Printf).getFormatParameterIndex()
or
// syslog
arg >= f.(Syslog).getFormatParameterIndex()
// printf / syslog
f.(FormattingFunction).isOutputGlobal() and
arg >= f.(FormattingFunction).getFormatParameterIndex()
or
// puts, putchar
(

View File

@@ -17,7 +17,7 @@ predicate printfLikeFunction(Function func, int formatArg) {
formatArg = func.(FormattingFunction).getFormatParameterIndex() and
not func instanceof UserDefinedFormattingFunction
or
primitiveVariadicFormatter(func, formatArg)
primitiveVariadicFormatter(func, _, formatArg, _)
or
exists(ExternalData data |
// TODO Do this \ to / conversion in the toolchain?

View File

@@ -20,36 +20,13 @@ class SecurityOptions extends string {
* name is a pure function of its arguments.
*/
predicate isPureFunction(string name) {
name = "abs" or
name = "atof" or
name = "atoi" or
name = "atol" or
name = "atoll" or
name = "labs" or
name = "strcasestr" or
name = "strcat" or
name = "strchnul" or
name = "strchr" or
name = "strchrnul" or
name = "strcmp" or
name = "strcpy" or
name = "strcspn" or
name = "strdup" or
name = "strlen" or
name = "strncat" or
name = "strncmp" or
name = "strncpy" or
name = "strndup" or
name = "strnlen" or
name = "strrchr" or
name = "strspn" or
name = "strstr" or
name = "strtod" or
name = "strtof" or
name = "strtol" or
name = "strtoll" or
name = "strtoq" or
name = "strtoul"
name =
[
"abs", "atof", "atoi", "atol", "atoll", "labs", "strcasestr", "strcat", "strchnul",
"strchr", "strchrnul", "strcmp", "strcpy", "strcspn", "strdup", "strlen", "strncat",
"strncmp", "strncpy", "strndup", "strnlen", "strrchr", "strspn", "strstr", "strtod",
"strtof", "strtol", "strtoll", "strtoq", "strtoul"
]
}
/**
@@ -73,13 +50,7 @@ class SecurityOptions extends string {
functionCall.getTarget().hasGlobalOrStdName(fname) and
exists(functionCall.getArgument(arg)) and
(
fname = "fread" and arg = 0
or
fname = "fgets" and arg = 0
or
fname = "fgetws" and arg = 0
or
fname = "gets" and arg = 0
fname = ["fread", "fgets", "fgetws", "gets"] and arg = 0
or
fname = "scanf" and arg >= 1
or
@@ -89,16 +60,12 @@ class SecurityOptions extends string {
functionCall.getTarget().hasGlobalName(fname) and
exists(functionCall.getArgument(arg)) and
(
fname = "read" and arg = 1
fname = ["read", "recv", "recvmsg"] and arg = 1
or
fname = "getaddrinfo" and arg = 3
or
fname = "recv" and arg = 1
or
fname = "recvfrom" and
(arg = 1 or arg = 4 or arg = 5)
or
fname = "recvmsg" and arg = 1
)
)
}
@@ -110,8 +77,7 @@ class SecurityOptions extends string {
exists(string fname |
functionCall.getTarget().getName() = fname and
(
fname = "fgets" or
fname = "gets" or
fname = ["fgets", "gets"] or
userInputReturn(fname)
)
)
@@ -132,30 +98,12 @@ class SecurityOptions extends string {
*/
predicate isProcessOperationArgument(string function, int arg) {
// POSIX
function = "system" and arg = 0
or
function = "popen" and arg = 0
or
function = "execl" and arg = 0
or
function = "execlp" and arg = 0
or
function = "execle" and arg = 0
or
function = "execv" and arg = 0
or
function = "execvp" and arg = 0
or
function = "execvpe" and arg = 0
or
function = "dlopen" and arg = 0
function =
["system", "popen", "execl", "execlp", "execle", "execv", "execvp", "execvpe", "dlopen"] and
arg = 0
or
// Windows
function = "LoadLibrary" and arg = 0
or
function = "LoadLibraryA" and arg = 0
or
function = "LoadLibraryW" and arg = 0
function = ["LoadLibrary", "LoadLibraryA", "LoadLibraryW"] and arg = 0
}
/**

View File

@@ -478,7 +478,7 @@ private predicate copyValueBetweenArguments(Function f, int sourceArg, int destA
or
exists(FormattingFunction ff | ff = f |
sourceArg in [ff.getFormatParameterIndex() .. maxArgIndex(f)] and
destArg = ff.getOutputParameterIndex()
destArg = ff.getOutputParameterIndex(false)
)
}

53
cpp/ql/test/README.md Normal file
View File

@@ -0,0 +1,53 @@
# C/C++ CodeQL tests
This document provides additional information about the C/C++ CodeQL Tests located in `cpp/ql/test`. See [Contributing to CodeQL](/CONTRIBUTING.md) for general information about contributing to this repository.
The tests can be run through Visual Studio Code. Advanced users may also use the `codeql test run` command.
## Contributing to the tests
We are keen to have unit tests for all of our QL code.
Every query in `cpp/ql/src` (outside of `cpp/ql/src/experimental`) should have a test in the corresponding subdirectory of `cpp/ql/test/query-tests`. At a minimum, each query test should contain one case that should be detected by the query, and one related case that should not.
For example a simple test for the "Memory is never freed" (`cpp/memory-never-freed`) query might contain the following cases:
```
int *array1, *array2;
array1 = (int *)malloc(sizeof(int) * 100); // BAD: never freed
array2 = (int *)malloc(sizeof(int) * 100); // GOOD
free(array2);
```
Features of the QL libraries in `cpp/ql/src` should also have test coverage, in `cpp/ql/test/library-tests`.
## Copying code
The contents of `cpp/ql/test` should be original - nothing should be copied from other sources. In particular do not copy-paste C/C++ code from third-party projects, your own projects, or the standard C/C++ library implementation of your compiler (regardless of the associated license). As an exception, required declarations may be taken from the following sources where necessary:
- [ISO/IEC Programming languages - C](https://www.iso.org/standard/74528.html) (all versions)
- [ISO/IEC Programming languages - C++](https://www.iso.org/standard/68564.html) (all versions)
- Code from existing queries and tests in this repository.
This includes 'translating QL to C++', that is, writing C/C++ declarations from the information such as parameter names and positions specified in QL classes (when there is enough information to do so).
- Code in the public domain
For example the test above for the "Memory is never freed" (`cpp/memory-never-freed`) query requires the following declarations, taken from [ISO/IEC 9899:2018 - Programming languages - C](https://www.iso.org/standard/74528.html):
```
void *malloc(size_t size);
void free(void *ptr);
```
We also need to write our own definition of `size_t`. Any unsigned integral type will do for our purposes:
```
typedef unsigned int size_t;
```
## Including files
Standard and third-party library header files should not be included in tests by means of `#include` or similar mechanisms. This is because the tests should be independent of platform and library versions installed on the running machine. Standard library declarations may be inserted directly where necessary (see the rules in the section above), but it is generally better to avoid using the standard library at all when possible.
`#include` may be used to include files from the same directory within `cpp/ql/test`. For example the test for "Include header files only" (`cpp/include-non-header`) includes other files in the test directory:
```
#include "test.H"
#include "test.xpm"
#include "test2.c"
```

View File

@@ -0,0 +1,71 @@
/**
* Helper library for implementing data or taint flow inline expectation tests.
* As long as data or taint flow configurations for IR and/or AST based data/taint flow
* are in scope, provides inline expectations tests.
* All sinks that have flow are annotated with `ast` (or respective `ir`) if there
* is a unique source for the flow.
* Otherwise, if there are multiple sources that can reach a given sink, the annotations
* have the form `ast=lineno:column` (or `ir=lineno:column`).
* If a sink is reachable through both AST and IR flow, the annotations have the form
* `ast,ir` or `ast,ir=lineno:column`.
* Intermediate steps from the source to the sink are not annotated.
*/
import cpp
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as ASTDataFlow
import TestUtilities.InlineExpectationsTest
class IRFlowTest extends InlineExpectationsTest {
IRFlowTest() { this = "IRFlowTest" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRDataFlow::Node source, IRDataFlow::Node sink, IRDataFlow::Configuration conf, int n |
tag = "ir" and
conf.hasFlow(source, sink) and
n = strictcount(IRDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = sink.getLocation() and
element = sink.toString()
)
}
}
class ASTFlowTest extends InlineExpectationsTest {
ASTFlowTest() { this = "ASTFlowTest" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(
ASTDataFlow::Node source, ASTDataFlow::Node sink, ASTDataFlow::Configuration conf, int n
|
tag = "ast" and
conf.hasFlow(source, sink) and
n = strictcount(ASTDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = sink.getLocation() and
element = sink.toString()
)
}
}

View File

@@ -0,0 +1,17 @@
edges
| test.cpp:22:17:22:21 | ... * ... | test.cpp:23:33:23:37 | size1 |
nodes
| test.cpp:13:33:13:37 | ... * ... | semmle.label | ... * ... |
| test.cpp:15:31:15:35 | ... * ... | semmle.label | ... * ... |
| test.cpp:19:34:19:38 | ... * ... | semmle.label | ... * ... |
| test.cpp:22:17:22:21 | ... * ... | semmle.label | ... * ... |
| test.cpp:23:33:23:37 | size1 | semmle.label | size1 |
| test.cpp:30:27:30:31 | ... * ... | semmle.label | ... * ... |
| test.cpp:31:27:31:31 | ... * ... | semmle.label | ... * ... |
#select
| test.cpp:13:33:13:37 | ... * ... | test.cpp:13:33:13:37 | ... * ... | test.cpp:13:33:13:37 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:13:33:13:37 | ... * ... | multiplication |
| test.cpp:15:31:15:35 | ... * ... | test.cpp:15:31:15:35 | ... * ... | test.cpp:15:31:15:35 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:15:31:15:35 | ... * ... | multiplication |
| test.cpp:19:34:19:38 | ... * ... | test.cpp:19:34:19:38 | ... * ... | test.cpp:19:34:19:38 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:19:34:19:38 | ... * ... | multiplication |
| test.cpp:23:33:23:37 | size1 | test.cpp:22:17:22:21 | ... * ... | test.cpp:23:33:23:37 | size1 | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:22:17:22:21 | ... * ... | multiplication |
| test.cpp:30:27:30:31 | ... * ... | test.cpp:30:27:30:31 | ... * ... | test.cpp:30:27:30:31 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:30:27:30:31 | ... * ... | multiplication |
| test.cpp:31:27:31:31 | ... * ... | test.cpp:31:27:31:31 | ... * ... | test.cpp:31:27:31:31 | ... * ... | Potentially overflowing value from $@ is used in the size of this allocation. | test.cpp:31:27:31:31 | ... * ... | multiplication |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-190/AllocMultiplicationOverflow.ql

View File

@@ -0,0 +1,32 @@
typedef unsigned long size_t;
void *malloc(size_t size);
int getAnInt();
void test()
{
int x = getAnInt();
int y = getAnInt();
char *buffer1 = (char *)malloc(x + y); // GOOD
char *buffer2 = (char *)malloc(x * y); // BAD
int *buffer3 = (int *)malloc(x * sizeof(int)); // GOOD
int *buffer4 = (int *)malloc(x * y * sizeof(int)); // BAD
if ((x <= 1000) && (y <= 1000))
{
char *buffer5 = (char *)malloc(x * y); // GOOD [FALSE POSITIVE]
}
size_t size1 = x * y;
char *buffer5 = (char *)malloc(size1); // BAD
size_t size2 = x;
size2 *= y;
char *buffer6 = (char *)malloc(size2); // BAD [NOT DETECTED]
char *buffer7 = new char[x * 10]; // GOOD
char *buffer8 = new char[x * y]; // BAD
char *buffer9 = new char[x * x]; // BAD
}

View File

@@ -1,5 +1,10 @@
///// Library routines /////
typedef unsigned long size_t;
void *malloc(size_t size);
size_t strlen(const char *s);
int scanf(const char *format, ...);
int sscanf(const char *str, const char *format, ...);
int fscanf(const char *str, const char *format, ...);
@@ -13,13 +18,23 @@ int main(int argc, char **argv)
char buf1[10];
scanf("%s", buf1);
// GOOD, length is specified
char buf2[10];
sscanf(buf2, "%9s");
// GOOD, length is specified. The length should be one less than the size of the destination buffer, since the last character is the NULL terminator.
char buf2[20];
char buf3[10];
sscanf(buf2, "%9s", buf3);
// BAD, do not use scanf without specifying a length first
char file[10];
fscanf(file, "%s", buf2);
// GOOD, with 'sscanf' the input can be checked first and enough room allocated [FALSE POSITIVE]
if (argc >= 1)
{
char *src = argv[0];
char *dest = (char *)malloc(strlen(src) + 1);
sscanf(src, "%s", dest);
}
return 0;
}

View File

@@ -1,2 +1,3 @@
| MemoryUnsafeFunctionScan.cpp:14:5:14:9 | call to scanf | Dangerous use of one of the scanf functions |
| MemoryUnsafeFunctionScan.cpp:22:5:22:10 | call to fscanf | Dangerous use of one of the scanf functions |
| MemoryUnsafeFunctionScan.cpp:19:5:19:9 | call to scanf | Dangerous use of one of the scanf functions |
| MemoryUnsafeFunctionScan.cpp:28:5:28:10 | call to fscanf | Dangerous use of one of the scanf functions |
| MemoryUnsafeFunctionScan.cpp:36:3:36:8 | call to sscanf | Dangerous use of one of the scanf functions |

View File

@@ -5,8 +5,7 @@ from Compilation c, int i, string s
where
i > 0 and
s =
c
.getArgument(i)
c.getArgument(i)
.replaceAll("\\", "/")
.regexpReplaceAll(".*(/qltest/predefined_macros)", "<tools>$1")
select c.getAFileCompiled().toString(), i, s

View File

@@ -0,0 +1,74 @@
#include "../shared.h"
using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) {
sink(sinkParam); // $ ast,ir=31:28 ast,ir=32:31 ast,ir=34:22 MISSING: ast,ir=28
}
struct {
SinkFunction sinkPtr, notSinkPtr;
} globalStruct;
union {
SinkFunction sinkPtr, notSinkPtr;
} globalUnion;
SinkFunction globalSinkPtr;
void assignGlobals() {
globalStruct.sinkPtr = callsSink;
globalUnion.sinkPtr = callsSink;
globalSinkPtr = callsSink;
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ast,ir
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
}
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); // $ ast,ir=58:10 ast,ir=60:17 ast,ir=61:28 ast,ir=62:29 ast,ir=63:33 SPURIOUS: ast,ir=73:30
}
};
void test_dynamic_cast() {
B* b = new D3();
b->f(getenv("VAR")); // $ ast,ir
((D2*)b)->f(getenv("VAR")); // $ ast,ir
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
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")); // $ SPURIOUS: ast,ir
}

View File

@@ -0,0 +1,88 @@
/**
* This test provides the possibility to annotate elements when they are on a path of a taint flow to a sink.
* This is different when compared to the tests in `../annotate_sink`, where only sink invocations are annotated.
*/
import cpp
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import TestUtilities.InlineExpectationsTest
predicate isSink(Element sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink = call.getAnArgument()
)
}
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
predicate irTaint(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) }
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ir" and
irTaint(source, tainted) and
(
isSink(tainted)
or
exists(Element sink |
isSink(sink) and
irTaint(tainted, sink)
)
) and
n = strictcount(Expr otherSource | irTaint(otherSource, tainted)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}
class ASTTaintTrackingTest extends InlineExpectationsTest {
ASTTaintTrackingTest() { this = "ASTTaintTrackingTest" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ast" and
astTaint(source, tainted) and
(
isSink(tainted)
or
exists(Element sink |
isSink(sink) and
astTaint(tainted, sink)
)
) and
n = strictcount(Expr otherSource | astTaint(otherSource, tainted)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}

View File

@@ -1,4 +1,4 @@
#include "shared.h"
#include "../shared.h"
struct S {
@@ -14,7 +14,7 @@ struct S {
};
void calls_sink_with_argv(const char* a) {
sink(a);
sink(a); // $ ast,ir=96:26 ast,ir=98:18
}
extern int i;
@@ -27,7 +27,7 @@ public:
class DerivedCallsSink : public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p);
sink(p); // $ ir ast=108:10 SPURIOUS: ast=111:10
}
};
@@ -39,7 +39,7 @@ public:
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p);
sink(p); // $ ast,ir
}
};
@@ -65,7 +65,7 @@ public:
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
public:
void g(const char* p) {
sink(p);
sink(p); // $ ast,ir
}
};
@@ -79,7 +79,7 @@ class Derived2 : public Derived1 {
class Derived3 : public Derived2 {
public:
void f(const char* p) override {
sink(p);
sink(p); // $ ast,ir=124:19 ast,ir=126:43 ast,ir=128:44
}
};
@@ -89,41 +89,41 @@ class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
};
int main(int argc, char *argv[]) {
sink(argv[0]);
sink(argv[0]); // $ ast,ir
sink(reinterpret_cast<int>(argv));
sink(reinterpret_cast<int>(argv)); // $ ast,ir
calls_sink_with_argv(argv[1]);
calls_sink_with_argv(argv[1]); // $ ast,ir
char*** p = &argv;
char*** p = &argv; // $ ast,ir
sink(*p[0]);
sink(*p[0]); // $ ast,ir
calls_sink_with_argv(*p[i]);
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir
sink(*(argv + 1));
sink(*(argv + 1)); // $ ast,ir
BaseWithPureVirtual* b = new DerivedCallsSink;
b->f(argv[1]);
b->f(argv[1]); // $ ast,ir
b = new DerivedDoesNotCallSink;
b->f(argv[0]); // no flow [FALSE POSITIVE by AST]
b->f(argv[0]); // $ SPURIOUS: ast
BaseWithPureVirtual* b2 = new DerivesMultiple;
b2->f(argv[i]);
b2->f(argv[i]); // $ ast,ir
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
crtp_not_call_sink.f(argv[0]);
crtp_not_call_sink.f(argv[0]); // clean
CRTP<CRTPCallsSink> crtp_calls_sink;
crtp_calls_sink.f(argv[0]);
crtp_calls_sink.f(argv[0]); // $ ast,ir
Derived1* calls_sink = new Derived3;
calls_sink->f(argv[1]);
calls_sink->f(argv[1]); // $ ast,ir
static_cast<Derived2*>(calls_sink)->f(argv[1]);
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED by IR]
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
}

View File

@@ -1,4 +1,4 @@
#include "shared.h"
#include "../shared.h"
@@ -13,15 +13,15 @@ int main() {
sink(_strdup(getenv("VAR")));
sink(strdup(getenv("VAR")));
sink(unmodeled_function(getenv("VAR")));
sink(_strdup(getenv("VAR"))); // $ ir MISSING: ast
sink(strdup(getenv("VAR"))); // $ ast,ir
sink(unmodeled_function(getenv("VAR"))); // clean by assumption
char untainted_buf[100] = "";
char buf[100] = "VAR = ";
sink(strcat(buf, getenv("VAR")));
sink(strcat(buf, getenv("VAR"))); // $ ast,ir
sink(buf);
sink(buf); // $ ast,ir
sink(untainted_buf); // the two buffers would be conflated if we added flow through all partial chi inputs
return 0;
@@ -37,46 +37,7 @@ void test_indirect_arg_to_model() {
// read side effect.
void *env_pointer = getenv("VAR"); // env_pointer is tainted, not its data.
inet_addr_retval a = inet_addr((const char *)&env_pointer);
sink(a);
}
class B {
public:
virtual void f(const char*) = 0;
};
class D1 : public B {};
class D2 : public D1 {
public:
void f(const char* p) override {}
};
class D3 : public D2 {
public:
void f(const char* p) override {
sink(p);
}
};
void test_dynamic_cast() {
B* b = new D3();
b->f(getenv("VAR")); // tainted
((D2*)b)->f(getenv("VAR")); // tainted
static_cast<D2*>(b)->f(getenv("VAR")); // tainted
dynamic_cast<D2*>(b)->f(getenv("VAR")); // tainted
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // tainted
B* b2 = new D2();
b2->f(getenv("VAR"));
((D2*)b2)->f(getenv("VAR"));
static_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // tainted [FALSE POSITIVE]
sink(a); // $ ast,ir
}
namespace std {
@@ -85,7 +46,7 @@ namespace std {
}
void test_std_move() {
sink(std::move(getenv("VAR")));
sink(std::move(getenv("VAR"))); // $ ir MISSING: ast
}
void flow_to_outparam(char ** ret, char *arg) {
@@ -95,7 +56,7 @@ void flow_to_outparam(char ** ret, char *arg) {
void test_outparams() {
char *p2 = nullptr;
flow_to_outparam(&p2, getenv("VAR"));
sink(p2); // tainted
sink(p2); // $ ir MISSING: ast
}
@@ -123,7 +84,7 @@ struct Point {
int y;
void callSink() {
sink(this->x); // tainted
sink(this->x); // $ ir MISSING: ast
sink(this->y); // not tainted
}
};
@@ -131,7 +92,7 @@ struct Point {
void test_conflated_fields1() {
Point p;
p.x = getenv("VAR")[0];
sink(p.x); // tainted
sink(p.x); // $ ir MISSING: ast
sink(p.y); // not tainted
p.callSink();
}
@@ -156,25 +117,25 @@ void sink(Point);
void test_field_to_obj_taint_object(Point p) {
p.x = getenv("VAR")[0];
sink(p); // not tainted
sink(p.x); // tainted
sink(p.x); // $ ir MISSING: ast
}
void test_field_to_obj_taint_object_addrof(Point p) {
taint_x(&p);
sink(p); // tainted [field -> object]
sink(&p); // tainted [field -> object]
sink(p.x); // tainted
sink(p); // not tainted
sink(&p); // not tainted
sink(p.x); // $ ir MISSING: ast
}
void test_field_to_obj_taint_pointer(Point* pp) {
pp->x = getenv("VAR")[0];
sink(pp); // tainted [field -> object]
sink(pp);// not tainted
sink(*pp); // not tainted
}
void call_sink_on_object(Point* pp) {
sink(pp); // tainted [field -> object]
sink(*pp); // tainted [field -> object]
sink(pp);// not tainted
sink(*pp);// not tainted
}
void test_field_to_obj_taint_call_sink(Point* pp) {
@@ -184,7 +145,7 @@ void test_field_to_obj_taint_call_sink(Point* pp) {
void test_field_to_obj_taint_through_setter(Point* pp) {
taint_x(pp);
sink(pp); // tainted [field -> object]
sink(pp);// not tainted
sink(*pp); // not tainted
}
@@ -200,14 +161,14 @@ void test_field_to_obj_local_variable() {
void test_field_to_obj_taint_array(Point* pp, int i) {
pp[0].x = getenv("VAR")[0];
sink(pp[i]); // not tainted
sink(pp); // tainted [field -> object]
sink(pp);// not tainted
sink(*pp); // not tainted
}
void test_field_to_obj_test_pointer_arith(Point* pp) {
(pp + sizeof(*pp))->x = getenv("VAR")[0];
sink(pp); // tainted [field -> object]
sink(pp + sizeof(*pp)); // tainted [field -> object]
sink(pp);// not tainted
sink(pp + sizeof(*pp));// not tainted
}
void sink(char **);
@@ -225,13 +186,13 @@ void test_pointers1()
ptr3 = buffer;
ptr4 = &ptr3;
sink(buffer); // tainted
sink(ptr1); // tainted
sink(ptr2);
sink(*ptr2); // tainted [NOT DETECTED]
sink(ptr3); // tainted
sink(ptr4);
sink(*ptr4); // tainted [NOT DETECTED]
sink(buffer); // $ ast,ir
sink(ptr1); // $ ast,ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr3); // $ ast,ir
sink(ptr4); // $ SPURIOUS: ast
sink(*ptr4); // $ ast MISSING: ir
}
void test_pointers2()
@@ -247,11 +208,11 @@ void test_pointers2()
ptr3 = buffer;
ptr4 = &ptr3;
sink(buffer); // tainted [NOT DETECTED]
sink(ptr1); // tainted [NOT DETECTED]
sink(ptr2);
sink(*ptr2); // tainted [NOT DETECTED]
sink(ptr3); // tainted [NOT DETECTED]
sink(ptr4);
sink(*ptr4); // tainted [NOT DETECTED]
sink(buffer); // $ MISSING: ast,ir
sink(ptr1); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr3); // $ MISSING: ast,ir
sink(ptr4); // clean
sink(*ptr4); // $ MISSING: ast,ir
}

View File

@@ -1,5 +1,5 @@
#include "shared.h"
#include "../shared.h"
typedef unsigned long size_t;
@@ -41,7 +41,7 @@ namespace std
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT, traits, Allocator>& str);
template<class charT, class traits = char_traits<charT>>
class basic_iostream : public basic_istream<charT, traits>, public basic_ostream<charT, traits> {
@@ -69,11 +69,11 @@ void test_string()
std::string b("123");
std::string c(source());
sink(a); // tainted
sink(b);
sink(c); // tainted
sink(b.c_str());
sink(c.c_str()); // tainted
sink(a); // $ ast,ir
sink(b); // clean
sink(c); // $ ir MISSING: ast
sink(b.c_str()); // clean
sink(c.c_str()); // $ MISSING: ast,ir
}
void test_stringstream()
@@ -88,15 +88,15 @@ void test_stringstream()
ss5 << t;
sink(ss1);
sink(ss2); // tainted
sink(ss3); // tainted [NOT DETECTED]
sink(ss4); // tainted
sink(ss5); // tainted
sink(ss2); // $ ir MISSING: ast
sink(ss3); // $ MISSING: ast,ir
sink(ss4); // $ ir MISSING: ast
sink(ss5); // $ ir MISSING: ast
sink(ss1.str());
sink(ss2.str()); // tainted
sink(ss3.str()); // tainted [NOT DETECTED]
sink(ss4.str()); // tainted
sink(ss5.str()); // tainted
sink(ss2.str()); // $ MISSING: ast,ir
sink(ss3.str()); // $ MISSING: ast,ir
sink(ss4.str()); // $ MISSING: ast,ir
sink(ss5.str()); // $ MISSING: ast,ir
}
void test_stringstream_int(int source)
@@ -106,10 +106,10 @@ void test_stringstream_int(int source)
ss1 << 1234;
ss2 << source;
sink(ss1);
sink(ss2); // tainted [NOT DETECTED]
sink(ss1.str());
sink(ss2.str()); // tainted [NOT DETECTED]
sink(ss1); // clean
sink(ss2); // $ MISSING: ast,ir
sink(ss1.str()); // clean
sink(ss2.str()); // $ MISSING: ast,ir
}
using namespace std;
@@ -123,14 +123,14 @@ void sink(const char *filename, const char *mode);
void test_strings2()
{
string path1 = user_input();
sink(path1.c_str(), "r"); // tainted
sink(path1.c_str(), "r"); // $ MISSING: ast,ir
string path2;
path2 = user_input();
sink(path2.c_str(), "r"); // tainted
sink(path2.c_str(), "r"); // $ MISSING: ast,ir
string path3(user_input());
sink(path3.c_str(), "r"); // tainted
sink(path3.c_str(), "r"); // $ MISSING: ast,ir
}
void test_string3()
@@ -140,8 +140,8 @@ void test_string3()
// convert char * -> std::string
std::string ss(cs);
sink(cs); // tainted
sink(ss); // tainted
sink(cs); // $ ast,ir
sink(ss); // $ ir MISSING: ast
}
void test_string4()
@@ -154,6 +154,6 @@ void test_string4()
// convert back std::string -> char *
cs = ss.c_str();
sink(cs); // tainted [NOT DETECTED]
sink(ss); // tainted
sink(cs); // $ ast MISSING: ir
sink(ss); // $ ir MISSING: ast
}

View File

@@ -0,0 +1,77 @@
/**
* This test provides the usual facilities to annotate taint flow when reaching a sink.
* This is different when compared to the tests in `../annotate_path_to_sink`, where all elements on a taint path to a sink
* are annotated.
*/
import cpp
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import TestUtilities.InlineExpectationsTest
predicate isSink(Element sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink = call.getAnArgument()
)
}
predicate astTaint(Expr source, Element sink) {
ASTTaintTracking::tainted(source, sink) and isSink(sink)
}
predicate irTaint(Expr source, Element sink) {
IRDefaultTaintTracking::tainted(source, sink) and isSink(sink)
}
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ir" and
irTaint(source, tainted) and
n = strictcount(Expr otherSource | irTaint(otherSource, tainted)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}
class ASTTaintTrackingTest extends InlineExpectationsTest {
ASTTaintTrackingTest() { this = "ASTTaintTrackingTest" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ast" and
astTaint(source, tainted) and
n = strictcount(Expr otherSource | astTaint(otherSource, tainted)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}

View File

@@ -1,35 +0,0 @@
#include "shared.h"
using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) {
sink(sinkParam);
}
struct {
SinkFunction sinkPtr, notSinkPtr;
} globalStruct;
union {
SinkFunction sinkPtr, notSinkPtr;
} globalUnion;
SinkFunction globalSinkPtr;
void assignGlobals() {
globalStruct.sinkPtr = callsSink;
globalUnion.sinkPtr = callsSink;
globalSinkPtr = callsSink;
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam [NOT DETECTED]
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // shouldn't reach sinkParam
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam
globalSinkPtr(atoi(getenv("TAINTED"))); // should reach sinkParam
}

View File

@@ -1,6 +0,0 @@
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | (const char *)... | global1 |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:12:10:12:16 | global1 | global1 |
| globals.cpp:13:15:13:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global1 |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | (const char *)... | global2 |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:19:10:19:16 | global2 | global2 |
| globals.cpp:23:15:23:20 | call to getenv | shared.h:5:23:5:31 | sinkparam | global2 |

View File

@@ -1,7 +0,0 @@
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking
from Expr source, Element tainted, string globalVar
where
taintedIncludingGlobalVars(source, tainted, globalVar) and
globalVar != ""
select source, tainted, globalVar

View File

@@ -0,0 +1,43 @@
import cpp
import semmle.code.cpp.security.Security
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import TestUtilities.InlineExpectationsTest
predicate astTaint(Expr source, Element sink, string globalVar) {
ASTTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
}
predicate irTaint(Expr source, Element sink, string globalVar) {
IRDefaultTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
}
class IRGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
IRGlobalDefaultTaintTrackingTest() { this = "IRGlobalDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted |
tag = "ir" and
irTaint(source, tainted, value) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}
class ASTGlobalDefaultTaintTrackingTest extends InlineExpectationsTest {
ASTGlobalDefaultTaintTrackingTest() { this = "ASTGlobalDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted |
tag = "ast" and
astTaint(source, tainted, value) and
location = tainted.getLocation() and
element = tainted.toString()
)
}
}

View File

@@ -1,22 +1,22 @@
#include "shared.h"
char *getenv(const char *name);
void sink(const char *sinkparam); // $ ast,ir=global1 ast,ir=global2
void throughLocal() {
char * local = getenv("VAR");
sink(local); // flow
sink(local);
}
char * global1 = 0;
void readWriteGlobal1() {
sink(global1); // flow
sink(global1); // $ ast,ir=global1
global1 = getenv("VAR");
}
static char * global2 = 0;
void readGlobal2() {
sink(global2); // flow
sink(global2); // $ ast,ir=global2
}
void writeGlobal2() {

View File

@@ -1,380 +0,0 @@
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup |
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... |
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:21 | call to getenv |
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:16:16:28 | (const char *)... |
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | shared.h:13:27:13:32 | string |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:13 | call to strdup |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:8:17:28 | (const char *)... |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:20 | call to getenv |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | defaulttainttracking.cpp:17:15:17:27 | (const char *)... |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:17:15:17:20 | call to getenv | shared.h:12:26:12:31 | string |
| 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 | shared.h:14:38:14:49 | const_string |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:13 | call to strcat |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:8:22:33 | (const char *)... |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:25 | call to getenv |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:20:22:32 | (const char *)... |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | (const char *)... |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | array to pointer conversion |
| 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 | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | shared.h:10:38:10:39 | s2 |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:32:11:32:26 | (unnamed parameter 0) |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:11:38:21 | env_pointer |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:30 | call to getenv |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:38:25:38:37 | (void *)... |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:22:39:22 | a |
| 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:36:39:61 | (const char *)... |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:50:39:61 | & ... |
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:40:10:40:10 | a |
| defaulttainttracking.cpp:64:10:64:15 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | (unnamed parameter 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:72:11:72:16 | call to getenv | defaulttainttracking.cpp:45:20:45:29 | (unnamed parameter 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: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 | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:84:17:84:17 | t |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:16 | call to move |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (const char *)... |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:8:88:32 | (reference dereference) |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:23 | call to getenv |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | (reference to) |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | defaulttainttracking.cpp:88:18:88:30 | temporary object |
| defaulttainttracking.cpp:88:18:88:23 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:91:42:91:44 | arg |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:92:12:92:14 | arg |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:96:11:96:12 | p2 |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:97:27:97:32 | call to getenv |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | (const char *)... |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | defaulttainttracking.cpp:98:10:98:11 | p2 |
| defaulttainttracking.cpp:97:27:97:32 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:7:110:13 | tainted |
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:22 | call to getenv |
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | (int)... |
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:110:17:110:32 | access to array |
| defaulttainttracking.cpp:110:17:110:22 | call to getenv | defaulttainttracking.cpp:111:12:111:18 | tainted |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:126:16:126:16 | x |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:14 | call to getenv |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | (int)... |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:133:9:133:24 | access to array |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | defaulttainttracking.cpp:134:10:134:10 | x |
| defaulttainttracking.cpp:133:9:133:14 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:16 | call to getenv |
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | (int)... |
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:140:11:140:26 | access to array |
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | defaulttainttracking.cpp:166:10:166:10 | x |
| defaulttainttracking.cpp:140:11:140:16 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:14 | call to getenv |
| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | (int)... |
| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:157:9:157:24 | access to array |
| defaulttainttracking.cpp:157:9:157:14 | call to getenv | defaulttainttracking.cpp:159:10:159:10 | x |
| defaulttainttracking.cpp:157:9:157:14 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:16 | call to getenv |
| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | (int)... |
| defaulttainttracking.cpp:170:11:170:16 | call to getenv | defaulttainttracking.cpp:170:11:170:26 | access to array |
| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:16 | call to getenv |
| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | (int)... |
| defaulttainttracking.cpp:181:11:181:16 | call to getenv | defaulttainttracking.cpp:181:11:181:26 | access to array |
| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:16 | call to getenv |
| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | (int)... |
| defaulttainttracking.cpp:195:11:195:16 | call to getenv | defaulttainttracking.cpp:195:11:195:26 | access to array |
| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:18 | call to getenv |
| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | (int)... |
| defaulttainttracking.cpp:201:13:201:18 | call to getenv | defaulttainttracking.cpp:201:13:201:28 | access to array |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:32 | call to getenv |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | (int)... |
| defaulttainttracking.cpp:208:27:208:32 | call to getenv | defaulttainttracking.cpp:208:27:208:42 | access to array |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:8:218:8 | s |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:218:12:218:17 | call to getenv |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:2:224:7 | call to memcpy |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | (const void *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:224:17:224:17 | s |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | array to pointer conversion |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:228:7:228:12 | buffer |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:229:7:229:10 | ptr1 |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | (const char *)... |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | defaulttainttracking.cpp:232:7:232:10 | ptr3 |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| defaulttainttracking.cpp:218:12:218:17 | call to getenv | shared.h:17:36:17:37 | s2 |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:8:240:8 | s |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:240:12:240:17 | call to getenv |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:2:246:7 | call to memcpy |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | (const void *)... |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | defaulttainttracking.cpp:246:16:246:16 | s |
| defaulttainttracking.cpp:240:12:240:17 | call to getenv | shared.h:17:36:17:37 | s2 |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:24:28:27 | call to atoi |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:34 | call to getenv |
| dispatch.cpp:28:29:28:34 | call to getenv | dispatch.cpp:28:29:28:45 | (const char *)... |
| dispatch.cpp:28:29:28:34 | call to getenv | shared.h:8:22:8:25 | nptr |
| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:27:29:30 | call to atoi |
| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:37 | call to getenv |
| dispatch.cpp:29:32:29:37 | call to getenv | dispatch.cpp:29:32:29:48 | (const char *)... |
| dispatch.cpp:29:32:29:37 | call to getenv | shared.h:8:22:8:25 | nptr |
| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam |
| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam |
| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:23:31:26 | call to atoi |
| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:33 | call to getenv |
| dispatch.cpp:31:28:31:33 | call to getenv | dispatch.cpp:31:28:31:44 | (const char *)... |
| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| dispatch.cpp:31:28:31:33 | call to getenv | shared.h:8:22:8:25 | nptr |
| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam |
| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam |
| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:26:32:29 | call to atoi |
| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:36 | call to getenv |
| dispatch.cpp:32:31:32:36 | call to getenv | dispatch.cpp:32:31:32:47 | (const char *)... |
| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| dispatch.cpp:32:31:32:36 | call to getenv | shared.h:8:22:8:25 | nptr |
| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:7:20:7:28 | sinkParam |
| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:8:8:8:16 | sinkParam |
| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:17:34:20 | call to atoi |
| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:27 | call to getenv |
| dispatch.cpp:34:22:34:27 | call to getenv | dispatch.cpp:34:22:34:38 | (const char *)... |
| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:6:15:6:23 | sinkparam |
| dispatch.cpp:34:22:34:27 | call to getenv | shared.h:8:22:8:25 | nptr |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:12:5:16 | local |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:5:20:5:25 | call to getenv |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | (const char *)... |
| globals.cpp:5:20:5:25 | call to getenv | globals.cpp:6:10:6:14 | local |
| globals.cpp:5:20:5:25 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:9:8:9:14 | global1 |
| globals.cpp:13:15:13:20 | call to getenv | globals.cpp:13:15:13:20 | call to getenv |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:16:15:16:21 | global2 |
| globals.cpp:23:15:23:20 | call to getenv | globals.cpp:23:15:23:20 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | shared.h:5:23:5:31 | sinkparam |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:21:29:21:29 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:78:43:104 | (unnamed parameter 0) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:43:114:43:118 | (unnamed parameter 1) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:44:176:44:178 | str |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:62:25:62:30 | call to getenv |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:63:30:63:30 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:64:36:64:36 | s |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:8:68:8 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:68:12:68:17 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:21 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:23 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:70:16:70:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:72:7:72:7 | a |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:74:7:74:7 | c |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:76:7:76:7 | c |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:21 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:23 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:82:16:82:24 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:6:85:17 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:85:9:85:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:15 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:15:86:26 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:23 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:86:18:86:25 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:6:87:19 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:14 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:9:87:16 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:18 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:87:18:87:26 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:6 | call to operator<< |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:6:88:10 | (reference dereference) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:88:9:88:9 | t |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:91:7:91:9 | ss2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:93:7:93:9 | ss4 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (const stringstream)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:94:7:94:9 | ss5 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:96:7:96:9 | ss2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:98:7:98:9 | ss4 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | (const basic_stringstream<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:99:7:99:9 | ss5 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:118:10:118:15 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:16:125:28 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:26 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:125:17:125:28 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:126:7:126:11 | path1 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:128:9:128:13 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:19 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:129:10:129:21 | temporary object |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:130:7:130:11 | path2 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:24 | call to user_input |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:132:15:132:27 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:133:7:133:11 | path3 |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:14:138:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:138:19:138:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:141:17:141:19 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:143:7:143:8 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:144:7:144:8 | ss |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:14:149:15 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:24 | call to source |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:149:19:149:26 | (const char *)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:18 | cs |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:152:17:152:19 | call to basic_string |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | (const basic_string<char, char_traits<char>, allocator<char>>)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:155:7:155:8 | ss |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (const string)... |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | (reference to) |
| stl.cpp:62:25:62:30 | call to getenv | stl.cpp:158:7:158:8 | ss |
| test_diff.cpp:92:10:92:13 | argv | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:6:15:6:23 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 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 | (unnamed parameter 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 | shared.h:5:23:5:31 | sinkparam |
| test_diff.cpp:115:11:115:14 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:24:20:24:29 | (unnamed parameter 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 | shared.h:5:23:5:31 | sinkparam |
| 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 | shared.h:5:23:5:31 | sinkparam |
| 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

@@ -1,5 +0,0 @@
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking
from Expr source, Element tainted
where tainted(source, tainted)
select source, tainted

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