mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
Merge branch 'main' into modelclasses
This commit is contained in:
4
cpp/change-notes/2020-11-05-formatting-function.md
Normal file
4
cpp/change-notes/2020-11-05-formatting-function.md
Normal 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.
|
||||
@@ -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*+")
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 + "%")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -847,8 +847,7 @@ class NewOrNewArrayExpr extends Expr, @any_new_expr {
|
||||
*/
|
||||
Expr getPlacementPointer() {
|
||||
result =
|
||||
this
|
||||
.getAllocatorCall()
|
||||
this.getAllocatorCall()
|
||||
.getArgument(this.getAllocator().(OperatorNewAllocationFunction).getPlacementArgument())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
|
||||
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
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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[]`.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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[]`.
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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(_))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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() }
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
(
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
53
cpp/ql/test/README.md
Normal 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"
|
||||
```
|
||||
71
cpp/ql/test/TestUtilities/dataflow/FlowTestCommon.qll
Normal file
71
cpp/ql/test/TestUtilities/dataflow/FlowTestCommon.qll
Normal 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-190/AllocMultiplicationOverflow.ql
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -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 |
|
||||
@@ -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
Reference in New Issue
Block a user