C++/C#/Java/JavaScript/Python: Autoformat set literals.

This commit is contained in:
Anders Schack-Mulligen
2020-11-10 13:32:27 +01:00
parent 26286e534e
commit 89ef6ea4eb
38 changed files with 344 additions and 241 deletions

View File

@@ -50,10 +50,12 @@ class SafeTimeGatheringFunction extends Function {
class TimeConversionFunction extends Function {
TimeConversionFunction() {
this.getQualifiedName() =
["FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
"SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
"TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
"RtlTimeToSecondsSince1970", "_mkgmtime"]
[
"FileTimeToSystemTime", "SystemTimeToFileTime", "SystemTimeToTzSpecificLocalTime",
"SystemTimeToTzSpecificLocalTimeEx", "TzSpecificLocalTimeToSystemTime",
"TzSpecificLocalTimeToSystemTimeEx", "RtlLocalTimeToSystemTime",
"RtlTimeToSecondsSince1970", "_mkgmtime"
]
}
}

View File

@@ -9,12 +9,14 @@ import cpp
class StrcatFunction extends Function {
StrcatFunction() {
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)
[
"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)
]
}
}

View File

@@ -243,8 +243,10 @@ pragma[noinline]
private predicate getWrittenField(Instruction instr, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa =
getFieldInstruction([instr.(StoreInstruction).getDestinationAddress(),
instr.(WriteSideEffectInstruction).getDestinationAddress()]) and
getFieldInstruction([
instr.(StoreInstruction).getDestinationAddress(),
instr.(WriteSideEffectInstruction).getDestinationAddress()
]) and
f = fa.getField() and
c = f.getDeclaringType()
)

View File

@@ -308,8 +308,10 @@ class IteratorAssignmentMemberOperator extends MemberFunction, TaintFunction {
class BeginOrEndFunction extends MemberFunction, TaintFunction, GetIteratorFunction {
BeginOrEndFunction() {
this
.hasName(["begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend",
"before_begin", "cbefore_begin"]) and
.hasName([
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
"cbefore_begin"
]) and
this.getType().getUnspecifiedType() instanceof Iterator
}

View File

@@ -5,9 +5,11 @@ import semmle.code.cpp.models.interfaces.SideEffect
class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideEffectFunction {
PureStrFunction() {
hasGlobalOrStdName(["atof", "atoi", "atol", "atoll", "strcasestr", "strchnul", "strchr",
"strchrnul", "strstr", "strpbrk", "strcmp", "strcspn", "strncmp", "strrchr", "strspn",
"strtod", "strtof", "strtol", "strtoll", "strtoq", "strtoul"])
hasGlobalOrStdName([
"atof", "atoi", "atol", "atoll", "strcasestr", "strchnul", "strchr", "strchrnul", "strstr",
"strpbrk", "strcmp", "strcspn", "strncmp", "strrchr", "strspn", "strtod", "strtof",
"strtol", "strtoll", "strtoq", "strtoul"
])
}
override predicate hasArrayInput(int bufParam) {

View File

@@ -14,20 +14,24 @@ import semmle.code.cpp.models.interfaces.SideEffect
class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, SideEffectFunction {
StrcpyFunction() {
getName() =
["strcpy", // strcpy(dst, src)
"wcscpy", // wcscpy(dst, src)
"_mbscpy", // _mbscpy(dst, src)
"strncpy", // strncpy(dst, src, max_amount)
"_strncpy_l", // _strncpy_l(dst, src, max_amount, locale)
"wcsncpy", // wcsncpy(dst, src, max_amount)
"_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale)
"_mbsncpy", // _mbsncpy(dst, src, max_amount)
"_mbsncpy_l"] // _mbsncpy_l(dst, src, max_amount, locale)
[
"strcpy", // strcpy(dst, src)
"wcscpy", // wcscpy(dst, src)
"_mbscpy", // _mbscpy(dst, src)
"strncpy", // strncpy(dst, src, max_amount)
"_strncpy_l", // _strncpy_l(dst, src, max_amount, locale)
"wcsncpy", // wcsncpy(dst, src, max_amount)
"_wcsncpy_l", // _wcsncpy_l(dst, src, max_amount, locale)
"_mbsncpy", // _mbsncpy(dst, src, max_amount)
"_mbsncpy_l" // _mbsncpy_l(dst, src, max_amount, locale)
]
or
getName() =
["strcpy_s", // strcpy_s(dst, max_amount, src)
"wcscpy_s", // wcscpy_s(dst, max_amount, src)
"_mbscpy_s"] and // _mbscpy_s(dst, max_amount, src)
[
"strcpy_s", // strcpy_s(dst, max_amount, src)
"wcscpy_s", // wcscpy_s(dst, max_amount, src)
"_mbscpy_s" // _mbscpy_s(dst, max_amount, src)
] and
// exclude the 2-parameter template versions
// that find the size of a fixed size destination buffer.
getNumberOfParameters() = 3

View File

@@ -355,9 +355,11 @@ class SnprintfBW extends BufferWriteCall {
class GetsBW extends BufferWriteCall {
GetsBW() {
getTarget().(TopLevelFunction).getName() =
["gets", // gets(dst)
"fgets", // fgets(dst, max_amount, src_stream)
"fgetws"] // fgetws(dst, max_amount, src_stream)
[
"gets", // gets(dst)
"fgets", // fgets(dst, max_amount, src_stream)
"fgetws" // fgetws(dst, max_amount, src_stream)
]
}
/**

View File

@@ -1751,8 +1751,10 @@ class SystemTupleFlow extends LibraryTypeDataFlow, ValueOrRefType {
result =
unique(AccessPath ap |
i in [1 .. count(this.getAMember())] and
ap in [AccessPath::field(this.getField("Item" + i)),
AccessPath::property(this.getProperty("Item" + i))]
ap in [
AccessPath::field(this.getField("Item" + i)),
AccessPath::property(this.getProperty("Item" + i))
]
|
ap
)

View File

@@ -382,7 +382,10 @@ private predicate isParamsArg(Call c, Expr arg, Parameter p) {
p.isParams() and
numArgs = c.getNumberOfArguments() and
arg =
[getImplicitArgument(c, [p.getPosition() .. numArgs - 1]), getExplicitArgument(c, p.getName())]
[
getImplicitArgument(c, [p.getPosition() .. numArgs - 1]),
getExplicitArgument(c, p.getName())
]
|
numArgs > target.getNumberOfParameters()
or

View File

@@ -160,8 +160,9 @@ private module Impl {
/** Returned an expression that is assigned to `f`. */
ExprNode getAssignedValueToField(Field f) {
result.getExpr() in [f.getAnAssignedValue(),
any(AssignOperation a | a.getLValue() = f.getAnAccess())]
result.getExpr() in [
f.getAnAssignedValue(), any(AssignOperation a | a.getLValue() = f.getAnAccess())
]
}
/** Holds if `f` can have any sign. */

View File

@@ -56,10 +56,12 @@ private class StringTaintPreservingMethod extends TaintPreservingCallable {
StringTaintPreservingMethod() {
this.getDeclaringType() instanceof TypeString and
this
.hasName(["concat", "copyValueOf", "endsWith", "format", "formatted", "getBytes", "indent",
"intern", "join", "repeat", "split", "strip", "stripIndent", "stripLeading",
"stripTrailing", "substring", "toCharArray", "toLowerCase", "toString", "toUpperCase",
"trim"])
.hasName([
"concat", "copyValueOf", "endsWith", "format", "formatted", "getBytes", "indent",
"intern", "join", "repeat", "split", "strip", "stripIndent", "stripLeading",
"stripTrailing", "substring", "toCharArray", "toLowerCase", "toString", "toUpperCase",
"trim"
])
}
override predicate returnsTaintFrom(int arg) {

View File

@@ -112,8 +112,10 @@ private predicate taintPreservingQualifierToMethod(Method m) {
// java.util.Map
m
.(MapMethod)
.hasName(["computeIfAbsent", "entrySet", "get", "getOrDefault", "put", "putIfAbsent",
"remove", "replace", "values"])
.hasName([
"computeIfAbsent", "entrySet", "get", "getOrDefault", "put", "putIfAbsent", "remove",
"replace", "values"
])
or
// java.util.Collection
m.(CollectionMethod).hasName(["parallelStream", "stream", "toArray"])
@@ -138,8 +140,10 @@ private predicate taintPreservingQualifierToMethod(Method m) {
// java.util.Deque
m
.(CollectionMethod)
.hasName(["getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast",
"removeFirst", "removeLast"])
.hasName([
"getFirst", "getLast", "peekFirst", "peekLast", "pollFirst", "pollLast", "removeFirst",
"removeLast"
])
or
// java.util.concurrent.BlockingQueue
// covered by Queue: poll(long, TimeUnit)
@@ -166,8 +170,10 @@ private predicate taintPreservingQualifierToMethod(Method m) {
// covered by SortedMap: headMap(K, boolean), subMap(K, boolean, K, boolean), tailMap(K, boolean)
m
.(MapMethod)
.hasName(["ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry",
"lastEntry", "lowerEntry", "pollFirstEntry", "pollLastEntry"])
.hasName([
"ceilingEntry", "descendingMap", "firstEntry", "floorEntry", "higherEntry", "lastEntry",
"lowerEntry", "pollFirstEntry", "pollLastEntry"
])
or
// java.util.Dictionary
m
@@ -273,15 +279,17 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
method.getDeclaringType().hasQualifiedName("java.util", "Collections") and
(
method
.hasName(["checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap",
"checkedNavigableSet", "checkedSet", "checkedSortedMap", "checkedSortedSet",
"enumeration", "list", "max", "min", "singleton", "singletonList",
"synchronizedCollection", "synchronizedList", "synchronizedMap",
"synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet",
"synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection",
"unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap",
"unmodifiableNavigableSet", "unmodifiableSet", "unmodifiableSortedMap",
"unmodifiableSortedSet"]) and
.hasName([
"checkedCollection", "checkedList", "checkedMap", "checkedNavigableMap",
"checkedNavigableSet", "checkedSet", "checkedSortedMap", "checkedSortedSet",
"enumeration", "list", "max", "min", "singleton", "singletonList",
"synchronizedCollection", "synchronizedList", "synchronizedMap",
"synchronizedNavigableMap", "synchronizedNavigableSet", "synchronizedSet",
"synchronizedSortedMap", "synchronizedSortedSet", "unmodifiableCollection",
"unmodifiableList", "unmodifiableMap", "unmodifiableNavigableMap",
"unmodifiableNavigableSet", "unmodifiableSet", "unmodifiableSortedMap",
"unmodifiableSortedSet"
]) and
arg = 0
or
method.hasName(["nCopies", "singletonMap"]) and arg = 1

View File

@@ -264,8 +264,9 @@ private class QueryBuilderAppendMethod extends TaintPreservingCallable {
// appendWhereStandalone(CharSequence inWhere)
// static appendColumns(StringBuilder s, String[] columns)
this
.hasName(["setProjectionMap", "setTables", "appendWhere", "appendWhereStandalone",
"appendColumns"])
.hasName([
"setProjectionMap", "setTables", "appendWhere", "appendWhereStandalone", "appendColumns"
])
}
override predicate transfersTaint(int src, int sink) {

View File

@@ -23,8 +23,10 @@ private predicate fileRead(VarAccess fileAccess, Expr fileReadingExpr) {
filesMethod.getDeclaringType().hasQualifiedName("java.nio.file", "Files") and
fileAccess = ma.getArgument(0) and
filesMethod
.hasName(["readAllBytes", "readAllLines", "readString", "lines", "newBufferedReader",
"newInputStream", "newByteChannel"])
.hasName([
"readAllBytes", "readAllLines", "readString", "lines", "newBufferedReader",
"newInputStream", "newByteChannel"
])
)
)
or

View File

@@ -123,9 +123,11 @@ module Cookie {
class InsecureJsCookie extends Cookie {
InsecureJsCookie() {
this =
[DataFlow::globalVarRef("Cookie"),
DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"),
DataFlow::moduleImport("js-cookie")].getAMemberCall("set")
[
DataFlow::globalVarRef("Cookie"),
DataFlow::globalVarRef("Cookie").getAMemberCall("noConflict"),
DataFlow::moduleImport("js-cookie")
].getAMemberCall("set")
}
override string getKind() { result = "js-cookie" }

View File

@@ -13,9 +13,11 @@ class JsonStringifyCall extends DataFlow::CallNode {
callee = DataFlow::globalVarRef("JSON").getAPropertyRead("stringify") or
callee = DataFlow::moduleMember("json3", "stringify") or
callee =
DataFlow::moduleImport(["json-stringify-safe", "json-stable-stringify", "stringify-object",
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
"js-stringify"]) or
DataFlow::moduleImport([
"json-stringify-safe", "json-stable-stringify", "stringify-object",
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
"js-stringify"
]) or
// require("util").inspect() and similar
callee = DataFlow::moduleMember("util", "inspect") or
callee = DataFlow::moduleImport(["pretty-format", "object-inspect"])

View File

@@ -212,8 +212,10 @@ private predicate isRequire(DataFlow::Node nd) {
imp.getImportedPath().getValue() = "module"
|
baseObj =
[DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))] and
[
DataFlow::destructuredModuleImportNode(imp),
DataFlow::valueNode(imp.getASpecifier().(ImportNamespaceSpecifier))
] and
nd = baseObj.getAPropertyRead("createRequire").getACall()
)
}

View File

@@ -299,8 +299,10 @@ module PromiseFlow {
or
prop = errorProp() and
value =
[promise.getRejectParameter().getACall().getArgument(0),
promise.getExecutor().getExceptionalReturn()]
[
promise.getRejectParameter().getACall().getArgument(0),
promise.getExecutor().getExceptionalReturn()
]
)
or
// promise creation call, e.g. `Promise.resolve`.

View File

@@ -699,8 +699,10 @@ module TaintTracking {
private DataFlow::PropRead getAStaticCaptureRef() {
result =
DataFlow::globalVarRef("RegExp")
.getAPropertyRead(["$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext",
"$&", "$^", "$`"])
.getAPropertyRead([
"$" + [1 .. 9], "input", "lastMatch", "leftContext", "rightContext", "$&", "$^",
"$`"
])
}
/**

View File

@@ -491,8 +491,10 @@ module Express {
RequestInputAccess() {
kind = "parameter" and
this =
[getAQueryObjectReference(DataFlow::TypeTracker::end(), rh),
getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)].getAPropertyRead()
[
getAQueryObjectReference(DataFlow::TypeTracker::end(), rh),
getAParamsObjectReference(DataFlow::TypeTracker::end(), rh)
].getAPropertyRead()
or
exists(DataFlow::SourceNode request | request = rh.getARequestSource().ref() |
kind = "parameter" and

View File

@@ -118,8 +118,10 @@ module Fastify {
.flow()
.(DataFlow::MethodCallNode)
.getOptionArgument(0,
["onRequest", "preParsing", "preValidation", "preHandler", "preSerialization",
"onSend", "onResponse", "handler"])
[
"onRequest", "preParsing", "preValidation", "preHandler", "preSerialization",
"onSend", "onResponse", "handler"
])
else result = getLastArgument().flow()
}
}

View File

@@ -403,16 +403,18 @@ module LodashUnderscore {
call = any(Member member | member.getName() = name).getACall()
|
name =
["find", "filter", "findWhere", "where", "reject", "pluck", "max", "min", "sortBy",
"shuffle", "sample", "toArray", "partition", "compact", "first", "initial", "last",
"rest", "flatten", "without", "difference", "uniq", "unique", "unzip", "transpose",
"object", "chunk", "values", "mapObject", "pick", "omit", "defaults", "clone", "tap",
"identity",
// String category
"camelCase", "capitalize", "deburr", "kebabCase", "lowerCase", "lowerFirst", "pad",
"padEnd", "padStart", "repeat", "replace", "snakeCase", "split", "startCase", "toLower",
"toUpper", "trim", "trimEnd", "trimStart", "truncate", "unescape", "upperCase",
"upperFirst", "words"] and
[
"find", "filter", "findWhere", "where", "reject", "pluck", "max", "min", "sortBy",
"shuffle", "sample", "toArray", "partition", "compact", "first", "initial", "last",
"rest", "flatten", "without", "difference", "uniq", "unique", "unzip", "transpose",
"object", "chunk", "values", "mapObject", "pick", "omit", "defaults", "clone", "tap",
"identity",
// String category
"camelCase", "capitalize", "deburr", "kebabCase", "lowerCase", "lowerFirst", "pad",
"padEnd", "padStart", "repeat", "replace", "snakeCase", "split", "startCase", "toLower",
"toUpper", "trim", "trimEnd", "trimStart", "truncate", "unescape", "upperCase",
"upperFirst", "words"
] and
pred = call.getArgument(0) and
succ = call
or

View File

@@ -798,10 +798,12 @@ private module Redis {
bindingset[argIndex]
predicate argumentIsAmbiguousKey(string method, int argIndex) {
method =
["set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset",
"ltrim", "rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby",
"zinterstore", "hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"] and
[
"set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset", "ltrim",
"rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby", "zinterstore",
"hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"
] and
argIndex = 0
or
method = ["bitop", "hmset", "mset", "msetnx", "geoadd"] and argIndex >= 0

View File

@@ -472,8 +472,10 @@ module NodeJSLib {
result = promisifyAllCall and
pred.flowsTo(promisifyAllCall.getArgument(0)) and
promisifyAllCall =
[DataFlow::moduleMember("bluebird", "promisifyAll"),
DataFlow::moduleImport("util-promisifyall")].getACall()
[
DataFlow::moduleMember("bluebird", "promisifyAll"),
DataFlow::moduleImport("util-promisifyall")
].getACall()
)
)
}
@@ -771,8 +773,10 @@ module NodeJSLib {
* Gets the code to be executed as part of this invocation.
*/
DataFlow::Node getACodeArgument() {
memberName in ["Script", "SourceTextModule", "compileFunction", "runInContext",
"runInNewContext", "runInThisContext"] and
memberName in [
"Script", "SourceTextModule", "compileFunction", "runInContext", "runInNewContext",
"runInThisContext"
] and
// all of the above methods/constructors take the command as their first argument
result = getArgument(0)
}

View File

@@ -569,10 +569,12 @@ private class UseStateStep extends PreCallGraphStep {
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::CallNode call | call = react().getAMemberCall("useState") |
pred =
[call.getArgument(0), // initial state
call.getCallback(0).getReturnNode(), // lazy initial state
call.getAPropertyRead("1").getACall().getArgument(0), // setState invocation
call.getAPropertyRead("1").getACall().getCallback(0).getReturnNode()] and // setState with callback
[
call.getArgument(0), // initial state
call.getCallback(0).getReturnNode(), // lazy initial state
call.getAPropertyRead("1").getACall().getArgument(0), // setState invocation
call.getAPropertyRead("1").getACall().getCallback(0).getReturnNode() // setState with callback
] and
succ = call.getAPropertyRead("0")
or
// Propagate current state into the callback argument of `setState(prevState => { ... })`

View File

@@ -33,8 +33,10 @@ module Vue {
/** Gets the name of a lifecycle hook method. */
private string lifecycleHookName() {
result =
["beforeCreate", "created", "beforeMount", "mounted", "beforeUpdate", "updated", "activated",
"deactivated", "beforeDestroy", "destroyed", "errorCaptured"]
[
"beforeCreate", "created", "beforeMount", "mounted", "beforeUpdate", "updated", "activated",
"deactivated", "beforeDestroy", "destroyed", "errorCaptured"
]
}
/** Gets a value that can be used as a `@Component` decorator. */

View File

@@ -53,8 +53,10 @@ module ImproperCodeSanitization {
|
functionLeaf
.getStringValue()
.regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*",
".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"])
.regexpMatch([
".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*", ".*new Function\\(.*",
"(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"
])
)
)
}

View File

@@ -66,9 +66,11 @@ module IndirectCommandInjection {
exists(string method |
not method =
// the methods that does not return a chained `yargs` object.
["getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions",
"_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands",
"getExitProcess", "locale", "getUsageInstance", "getCommandInstance"]
[
"getContext", "getDemandedOptions", "getDemandedCommands", "getDeprecatedOptions",
"_getParseContext", "getOptions", "getGroups", "getStrict", "getStrictCommands",
"getExitProcess", "locale", "getUsageInstance", "getCommandInstance"
]
|
result = yargs().getAMethodCall(method)
)

View File

@@ -96,8 +96,10 @@ module InsecureDownload {
*/
string unsafeExtension() {
result =
["exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg",
"tar.gz", "zip", "js", "py", "jar", "war"]
[
"exe", "dmg", "pkg", "tar.gz", "zip", "sh", "bat", "cmd", "app", "apk", "msi", "dmg",
"tar.gz", "zip", "js", "py", "jar", "war"
]
}
/**

View File

@@ -105,8 +105,10 @@ module UnsafeShellCommandConstruction {
ArrayAppendEndingInCommandExecutinSink() {
this =
[array.(DataFlow::ArrayCreationNode).getAnElement(),
array.getAMethodCall(["push", "unshift"]).getAnArgument()] and
[
array.(DataFlow::ArrayCreationNode).getAnElement(),
array.getAMethodCall(["push", "unshift"]).getAnArgument()
] and
exists(DataFlow::MethodCallNode joinCall | array.getAMethodCall("join") = joinCall |
joinCall = isExecutedAsShellCommand(DataFlow::TypeBackTracker::end(), sys) and
joinCall.getNumArgument() = 1 and

View File

@@ -86,9 +86,11 @@ predicate stringManipulation(DataFlow::CfgNode nodeFrom, DataFlow::CfgNode nodeT
object = call.getFunction().(AttrNode).getObject(method_name)
|
nodeFrom.getNode() = object and
method_name in ["capitalize", "casefold", "center", "expandtabs", "format", "format_map",
"join", "ljust", "lstrip", "lower", "replace", "rjust", "rstrip", "strip", "swapcase",
"title", "upper", "zfill", "encode", "decode"]
method_name in [
"capitalize", "casefold", "center", "expandtabs", "format", "format_map", "join", "ljust",
"lstrip", "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper",
"zfill", "encode", "decode"
]
or
method_name = "replace" and
nodeFrom.getNode() = call.getArg(1)
@@ -156,8 +158,9 @@ predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
or
// constructor call
exists(CallNode call | call = nodeTo.asCfgNode() |
call.getFunction().(NameNode).getId() in ["list", "set", "frozenset", "dict", "defaultdict",
"tuple"] and
call.getFunction().(NameNode).getId() in [
"list", "set", "frozenset", "dict", "defaultdict", "tuple"
] and
call.getArg(0) = nodeFrom.getNode()
)
or
@@ -169,11 +172,13 @@ predicate containerStep(DataFlow::CfgNode nodeFrom, DataFlow::Node nodeTo) {
or
// methods
exists(CallNode call, string name | call = nodeTo.asCfgNode() |
name in ["copy",
// general
"pop",
// dict
"values", "items", "get", "popitem"] and
name in [
"copy",
// general
"pop",
// dict
"values", "items", "get", "popitem"
] and
call.getFunction().(AttrNode).getObject(name) = nodeFrom.asCfgNode()
)
or

View File

@@ -259,8 +259,9 @@ private module Django {
ObjectsAnnotate() {
node.getFunction() = django::db::models::objects_attr("annotate").asCfgNode() and
django::db::models::expressions::RawSQL::instance(sql).asCfgNode() in [node.getArg(_),
node.getArgByName(_)]
django::db::models::expressions::RawSQL::instance(sql).asCfgNode() in [
node.getArg(_), node.getArgByName(_)
]
}
override DataFlow::Node getSql() { result.asCfgNode() = sql }
@@ -423,18 +424,19 @@ private module Django {
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node http_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["request",
// request
"HttpRequest",
// response
"response", "HttpResponse",
// HttpResponse subclasses
"HttpResponseRedirect", "HttpResponsePermanentRedirect", "HttpResponseNotModified",
"HttpResponseBadRequest", "HttpResponseNotFound", "HttpResponseForbidden",
"HttpResponseNotAllowed", "HttpResponseGone", "HttpResponseServerError",
"JsonResponse",
// HttpResponse-like classes
"StreamingHttpResponse", "FileResponse"] and
attr_name in [
"request",
// request
"HttpRequest",
// response
"response", "HttpResponse",
// HttpResponse subclasses
"HttpResponseRedirect", "HttpResponsePermanentRedirect", "HttpResponseNotModified",
"HttpResponseBadRequest", "HttpResponseNotFound", "HttpResponseForbidden",
"HttpResponseNotAllowed", "HttpResponseGone", "HttpResponseServerError", "JsonResponse",
// HttpResponse-like classes
"StreamingHttpResponse", "FileResponse"
] and
(
t.start() and
result = DataFlow::importNode("django.http" + "." + attr_name)
@@ -576,14 +578,16 @@ private module Django {
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node response_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["HttpResponse",
// HttpResponse subclasses
"HttpResponseRedirect", "HttpResponsePermanentRedirect", "HttpResponseNotModified",
"HttpResponseBadRequest", "HttpResponseNotFound", "HttpResponseForbidden",
"HttpResponseNotAllowed", "HttpResponseGone", "HttpResponseServerError",
"JsonResponse",
// HttpResponse-like classes
"StreamingHttpResponse", "FileResponse"] and
attr_name in [
"HttpResponse",
// HttpResponse subclasses
"HttpResponseRedirect", "HttpResponsePermanentRedirect", "HttpResponseNotModified",
"HttpResponseBadRequest", "HttpResponseNotFound", "HttpResponseForbidden",
"HttpResponseNotAllowed", "HttpResponseGone", "HttpResponseServerError",
"JsonResponse",
// HttpResponse-like classes
"StreamingHttpResponse", "FileResponse"
] and
(
t.start() and
result = DataFlow::importNode("django.http.response" + "." + attr_name)
@@ -1704,25 +1708,27 @@ private module Django {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
nodeFrom = django::http::request::HttpRequest::instance() and
exists(DataFlow::AttrRead read | nodeTo = read and read.getObject() = nodeFrom |
read.getAttributeName() in ["body",
// str / bytes
"path", "path_info", "method", "encoding", "content_type",
// django.http.QueryDict
// TODO: Model QueryDict
"GET", "POST",
// dict[str, str]
"content_params", "COOKIES",
// dict[str, Any]
"META",
// HttpHeaders (case insensitive dict-like)
"headers",
// MultiValueDict[str, UploadedFile]
// TODO: Model MultiValueDict
// TODO: Model UploadedFile
"FILES",
// django.urls.ResolverMatch
// TODO: Model ResolverMatch
"resolver_match"]
read.getAttributeName() in [
"body",
// str / bytes
"path", "path_info", "method", "encoding", "content_type",
// django.http.QueryDict
// TODO: Model QueryDict
"GET", "POST",
// dict[str, str]
"content_params", "COOKIES",
// dict[str, Any]
"META",
// HttpHeaders (case insensitive dict-like)
"headers",
// MultiValueDict[str, UploadedFile]
// TODO: Model MultiValueDict
// TODO: Model UploadedFile
"FILES",
// django.urls.ResolverMatch
// TODO: Model ResolverMatch
"resolver_match"
]
// TODO: Handle calls to methods
// TODO: Handle that a HttpRequest is iterable
)

View File

@@ -168,13 +168,15 @@ private module FabricV2 {
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node fabric_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["connection",
// connection.py
"Connection",
// group.py
"group", "SerialGroup", "ThreadingGroup",
// tasks.py
"tasks", "task"] and
attr_name in [
"connection",
// connection.py
"Connection",
// group.py
"group", "SerialGroup", "ThreadingGroup",
// tasks.py
"tasks", "task"
] and
(
t.start() and
result = DataFlow::importNode("fabric" + "." + attr_name)

View File

@@ -388,40 +388,42 @@ private module FlaskModel {
exists(AttrNode attr |
this.asCfgNode() = attr and attr.getObject(attr_name) = flask::request().asCfgNode()
|
attr_name in ["path",
// str
"full_path", "base_url", "url", "access_control_request_method", "content_encoding",
"content_md5", "content_type", "data", "method", "mimetype", "origin", "query_string",
"referrer", "remote_addr", "remote_user", "user_agent",
// dict
"environ", "cookies", "mimetype_params", "view_args",
// json
"json",
// List[str]
"access_route",
// file-like
"stream", "input_stream",
// MultiDict[str, str]
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict
"args", "values", "form",
// MultiDict[str, FileStorage]
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage
// TODO: FileStorage needs extra taint steps
"files",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.HeaderSet
"access_control_request_headers", "pragma",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Accept
// TODO: Kinda badly modeled for now -- has type List[Tuple[value, quality]], and some extra methods
"accept_charsets", "accept_encodings", "accept_languages", "accept_mimetypes",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Authorization
// TODO: dict subclass with extra attributes like `username` and `password`
"authorization",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.RequestCacheControl
// TODO: has attributes like `no_cache`, and `to_header` method (actually, many of these models do)
"cache_control",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers
// TODO: dict-like with wsgiref.headers.Header compatibility methods
"headers"]
attr_name in [
"path",
// str
"full_path", "base_url", "url", "access_control_request_method", "content_encoding",
"content_md5", "content_type", "data", "method", "mimetype", "origin", "query_string",
"referrer", "remote_addr", "remote_user", "user_agent",
// dict
"environ", "cookies", "mimetype_params", "view_args",
// json
"json",
// List[str]
"access_route",
// file-like
"stream", "input_stream",
// MultiDict[str, str]
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.MultiDict
"args", "values", "form",
// MultiDict[str, FileStorage]
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.FileStorage
// TODO: FileStorage needs extra taint steps
"files",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.HeaderSet
"access_control_request_headers", "pragma",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Accept
// TODO: Kinda badly modeled for now -- has type List[Tuple[value, quality]], and some extra methods
"accept_charsets", "accept_encodings", "accept_languages", "accept_mimetypes",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Authorization
// TODO: dict subclass with extra attributes like `username` and `password`
"authorization",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.RequestCacheControl
// TODO: has attributes like `no_cache`, and `to_header` method (actually, many of these models do)
"cache_control",
// https://werkzeug.palletsprojects.com/en/1.0.x/datastructures/#werkzeug.datastructures.Headers
// TODO: dict-like with wsgiref.headers.Header compatibility methods
"headers"
]
)
or
// methods (needs special handling to track bound-methods -- see `FlaskRequestMethodCallsAdditionalTaintStep` below)

View File

@@ -32,14 +32,16 @@ private module Stdlib {
* For example, using `attr_name = "system"` will get all uses of `os.system`.
*/
private DataFlow::Node os_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["system", "popen", "popen2", "popen3", "popen4",
// exec
"execl", "execle", "execlp", "execlpe", "execv", "execve", "execvp", "execvpe",
// spawn
"spawnl", "spawnle", "spawnlp", "spawnlpe", "spawnv", "spawnve", "spawnvp", "spawnvpe",
"posix_spawn", "posix_spawnp",
// modules
"path"] and
attr_name in [
"system", "popen", "popen2", "popen3", "popen4",
// exec
"execl", "execle", "execlp", "execlpe", "execv", "execve", "execvp", "execvpe",
// spawn
"spawnl", "spawnle", "spawnlp", "spawnlpe", "spawnv", "spawnve", "spawnvp", "spawnvpe",
"posix_spawn", "posix_spawnp",
// modules
"path"
] and
(
t.start() and
result = DataFlow::importNode("os." + attr_name)
@@ -218,8 +220,9 @@ private module Stdlib {
OsSpawnCall() {
exists(string name |
name in ["spawnl", "spawnle", "spawnlp", "spawnlpe", "spawnv", "spawnve", "spawnvp",
"spawnvpe"] and
name in [
"spawnl", "spawnle", "spawnlp", "spawnlpe", "spawnv", "spawnve", "spawnvp", "spawnvpe"
] and
node.getFunction() = os_attr(name).asCfgNode()
)
}
@@ -505,9 +508,11 @@ private module Stdlib {
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node popen2_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["popen2", "popen3", "popen4",
// classes
"Popen3", "Popen4"] and
attr_name in [
"popen2", "popen3", "popen4",
// classes
"Popen3", "Popen4"
] and
(
t.start() and
result = DataFlow::importNode("popen2." + attr_name)
@@ -772,10 +777,12 @@ DataFlow::Node base64() { result = base64(DataFlow::TypeTracker::end()) }
* WARNING: Only holds for a few predefined attributes.
*/
private DataFlow::Node base64_attr(DataFlow::TypeTracker t, string attr_name) {
attr_name in ["b64encode", "b64decode", "standard_b64encode", "standard_b64decode",
"urlsafe_b64encode", "urlsafe_b64decode", "b32encode", "b32decode", "b16encode",
"b16decode", "encodestring", "decodestring", "a85encode", "a85decode", "b85encode",
"b85decode", "encodebytes", "decodebytes"] and
attr_name in [
"b64encode", "b64decode", "standard_b64encode", "standard_b64decode", "urlsafe_b64encode",
"urlsafe_b64decode", "b32encode", "b32decode", "b16encode", "b16decode", "encodestring",
"decodestring", "a85encode", "a85decode", "b85encode", "b85decode", "encodebytes",
"decodebytes"
] and
(
t.start() and
result = DataFlow::importNode("base64" + "." + attr_name)
@@ -815,8 +822,10 @@ private class Base64EncodeCall extends Encoding::Range, DataFlow::CfgNode {
Base64EncodeCall() {
exists(string name |
name in ["b64encode", "standard_b64encode", "urlsafe_b64encode", "b32encode", "b16encode",
"encodestring", "a85encode", "b85encode", "encodebytes"] and
name in [
"b64encode", "standard_b64encode", "urlsafe_b64encode", "b32encode", "b16encode",
"encodestring", "a85encode", "b85encode", "encodebytes"
] and
node.getFunction() = base64_attr(name).asCfgNode()
)
}
@@ -827,7 +836,9 @@ private class Base64EncodeCall extends Encoding::Range, DataFlow::CfgNode {
override string getFormat() {
exists(string name | node.getFunction() = base64_attr(name).asCfgNode() |
name in ["b64encode", "standard_b64encode", "urlsafe_b64encode", "encodestring", "encodebytes"] and
name in [
"b64encode", "standard_b64encode", "urlsafe_b64encode", "encodestring", "encodebytes"
] and
result = "Base64"
or
name = "b32encode" and result = "Base32"
@@ -847,8 +858,10 @@ private class Base64DecodeCall extends Decoding::Range, DataFlow::CfgNode {
Base64DecodeCall() {
exists(string name |
name in ["b64decode", "standard_b64decode", "urlsafe_b64decode", "b32decode", "b16decode",
"decodestring", "a85decode", "b85decode", "decodebytes"] and
name in [
"b64decode", "standard_b64decode", "urlsafe_b64decode", "b32decode", "b16decode",
"decodestring", "a85decode", "b85decode", "decodebytes"
] and
node.getFunction() = base64_attr(name).asCfgNode()
)
}
@@ -861,7 +874,9 @@ private class Base64DecodeCall extends Decoding::Range, DataFlow::CfgNode {
override string getFormat() {
exists(string name | node.getFunction() = base64_attr(name).asCfgNode() |
name in ["b64decode", "standard_b64decode", "urlsafe_b64decode", "decodestring", "decodebytes"] and
name in [
"b64decode", "standard_b64decode", "urlsafe_b64decode", "decodestring", "decodebytes"
] and
result = "Base64"
or
name = "b32decode" and result = "Base32"

View File

@@ -115,15 +115,17 @@ module Werkzeug {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
nodeFrom = werkzeug::datastructures::FileStorage::instance() and
exists(DataFlow::AttrRead read | nodeTo = read |
read.getAttributeName() in ["filename",
// str
"name", "content_type", "mimetype",
// file-like
"stream",
// TODO: werkzeug.datastructures.Headers
"headers",
// dict[str, str]
"mimetype_params"] and
read.getAttributeName() in [
"filename",
// str
"name", "content_type", "mimetype",
// file-like
"stream",
// TODO: werkzeug.datastructures.Headers
"headers",
// dict[str, str]
"mimetype_params"
] and
read.getObject() = nodeFrom
)
}

View File

@@ -8,11 +8,12 @@ abstract class StringKind extends TaintKind {
StringKind() { this = this }
override TaintKind getTaintOfMethodResult(string name) {
name in ["capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust",
"lstrip", "lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper",
"zfill",
/* encode/decode is technically not correct, but close enough */
"encode", "decode"] and
name in [
"capitalize", "casefold", "center", "expandtabs", "format", "format_map", "ljust", "lstrip",
"lower", "replace", "rjust", "rstrip", "strip", "swapcase", "title", "upper", "zfill",
/* encode/decode is technically not correct, but close enough */
"encode", "decode"
] and
result = this
or
name in ["partition", "rpartition", "rsplit", "split", "splitlines"] and

View File

@@ -6,8 +6,9 @@ class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.(DataFlow::CfgNode).getNode().(NameNode).getId() in ["TAINTED_STRING", "TAINTED_BYTES",
"TAINTED_LIST", "TAINTED_DICT"]
source.(DataFlow::CfgNode).getNode().(NameNode).getId() in [
"TAINTED_STRING", "TAINTED_BYTES", "TAINTED_LIST", "TAINTED_DICT"
]
}
override predicate isSink(DataFlow::Node sink) {