зеркало из https://github.com/github/codeql.git
Merge branch 'main' into redsun82/swift-open-redirection
This commit is contained in:
Коммит
250ac686a2
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `getaddrinfo` function is now recognized as a flow source.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `ArgvSource` flow source has been generalized to handle cases where the argument vector of `main` is not named `argv`.
|
|
@ -15,6 +15,6 @@ private class Fread extends AliasFunction, RemoteFlowSourceFunction {
|
|||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(0) and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,6 @@ private class GetDelimFunction extends TaintFunction, AliasFunction, SideEffectF
|
|||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(0) and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,10 +49,10 @@ private class FgetsFunction extends DataFlowFunction, TaintFunction, ArrayFuncti
|
|||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(0) and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
or
|
||||
output.isReturnValue() and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
|
||||
|
@ -98,10 +98,10 @@ private class GetsFunction extends DataFlowFunction, ArrayFunction, AliasFunctio
|
|||
|
||||
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(0) and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
or
|
||||
output.isReturnValue() and
|
||||
description = "String read by " + this.getName()
|
||||
description = "string read by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasArrayWithUnknownSize(int bufParam) { bufParam = 0 }
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import semmle.code.cpp.models.interfaces.Taint
|
||||
import semmle.code.cpp.models.interfaces.Alias
|
||||
import semmle.code.cpp.models.interfaces.ArrayFunction
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
|
||||
private class InetNtoa extends TaintFunction {
|
||||
InetNtoa() { hasGlobalName("inet_ntoa") }
|
||||
InetNtoa() { this.hasGlobalName("inet_ntoa") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
|
@ -12,7 +13,7 @@ private class InetNtoa extends TaintFunction {
|
|||
}
|
||||
|
||||
private class InetAton extends TaintFunction, ArrayFunction {
|
||||
InetAton() { hasGlobalName("inet_aton") }
|
||||
InetAton() { this.hasGlobalName("inet_aton") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
|
@ -32,7 +33,7 @@ private class InetAton extends TaintFunction, ArrayFunction {
|
|||
}
|
||||
|
||||
private class InetAddr extends TaintFunction, ArrayFunction, AliasFunction {
|
||||
InetAddr() { hasGlobalName("inet_addr") }
|
||||
InetAddr() { this.hasGlobalName("inet_addr") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
|
@ -51,7 +52,7 @@ private class InetAddr extends TaintFunction, ArrayFunction, AliasFunction {
|
|||
}
|
||||
|
||||
private class InetNetwork extends TaintFunction, ArrayFunction {
|
||||
InetNetwork() { hasGlobalName("inet_network") }
|
||||
InetNetwork() { this.hasGlobalName("inet_network") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
|
@ -64,7 +65,7 @@ private class InetNetwork extends TaintFunction, ArrayFunction {
|
|||
}
|
||||
|
||||
private class InetMakeaddr extends TaintFunction {
|
||||
InetMakeaddr() { hasGlobalName("inet_makeaddr") }
|
||||
InetMakeaddr() { this.hasGlobalName("inet_makeaddr") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
|
@ -76,7 +77,7 @@ private class InetMakeaddr extends TaintFunction {
|
|||
}
|
||||
|
||||
private class InetLnaof extends TaintFunction {
|
||||
InetLnaof() { hasGlobalName("inet_lnaof") }
|
||||
InetLnaof() { this.hasGlobalName("inet_lnaof") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
|
@ -85,7 +86,7 @@ private class InetLnaof extends TaintFunction {
|
|||
}
|
||||
|
||||
private class InetNetof extends TaintFunction {
|
||||
InetNetof() { hasGlobalName("inet_netof") }
|
||||
InetNetof() { this.hasGlobalName("inet_netof") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameter(0) and
|
||||
|
@ -94,7 +95,7 @@ private class InetNetof extends TaintFunction {
|
|||
}
|
||||
|
||||
private class InetPton extends TaintFunction, ArrayFunction {
|
||||
InetPton() { hasGlobalName("inet_pton") }
|
||||
InetPton() { this.hasGlobalName("inet_pton") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
|
@ -114,7 +115,7 @@ private class InetPton extends TaintFunction, ArrayFunction {
|
|||
}
|
||||
|
||||
private class Gethostbyname extends TaintFunction, ArrayFunction {
|
||||
Gethostbyname() { hasGlobalName("gethostbyname") }
|
||||
Gethostbyname() { this.hasGlobalName("gethostbyname") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
|
@ -127,7 +128,7 @@ private class Gethostbyname extends TaintFunction, ArrayFunction {
|
|||
}
|
||||
|
||||
private class Gethostbyaddr extends TaintFunction, ArrayFunction {
|
||||
Gethostbyaddr() { hasGlobalName("gethostbyaddr") }
|
||||
Gethostbyaddr() { this.hasGlobalName("gethostbyaddr") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
(
|
||||
|
@ -142,3 +143,21 @@ private class Gethostbyaddr extends TaintFunction, ArrayFunction {
|
|||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
|
||||
}
|
||||
|
||||
private class Getaddrinfo extends TaintFunction, ArrayFunction, RemoteFlowSourceFunction {
|
||||
Getaddrinfo() { this.hasGlobalName("getaddrinfo") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref([0 .. 2]) and
|
||||
output.isParameterDeref(3)
|
||||
}
|
||||
|
||||
override predicate hasArrayInput(int bufParam) { bufParam in [0, 1] }
|
||||
|
||||
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam in [0, 1] }
|
||||
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(3) and
|
||||
description = "address returned by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ private class Recv extends AliasFunction, ArrayFunction, SideEffectFunction,
|
|||
or
|
||||
this.hasGlobalName("recvfrom") and output.isParameterDeref([4, 5])
|
||||
) and
|
||||
description = "Buffer read by " + this.getName()
|
||||
description = "buffer read by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||
|
|
|
@ -74,7 +74,7 @@ abstract private class ScanfFunctionModel extends ArrayFunction, TaintFunction,
|
|||
private class ScanfModel extends ScanfFunctionModel, LocalFlowSourceFunction instanceof Scanf {
|
||||
override predicate hasLocalFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(any(int i | i >= this.getArgsStartPosition())) and
|
||||
description = "Value read by " + this.getName()
|
||||
description = "value read by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +84,7 @@ private class ScanfModel extends ScanfFunctionModel, LocalFlowSourceFunction ins
|
|||
private class FscanfModel extends ScanfFunctionModel, RemoteFlowSourceFunction instanceof Fscanf {
|
||||
override predicate hasRemoteFlowSource(FunctionOutput output, string description) {
|
||||
output.isParameterDeref(any(int i | i >= this.getArgsStartPosition())) and
|
||||
description = "Value read by " + this.getName()
|
||||
description = "value read by " + this.getName()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ private class Send extends AliasFunction, ArrayFunction, SideEffectFunction, Rem
|
|||
override ParameterIndex getParameterSizeIndex(ParameterIndex i) { i = 1 and result = 2 }
|
||||
|
||||
override predicate hasRemoteFlowSink(FunctionInput input, string description) {
|
||||
input.isParameterDeref(1) and description = "Buffer sent by " + this.getName()
|
||||
input.isParameterDeref(1) and description = "buffer sent by " + this.getName()
|
||||
}
|
||||
|
||||
override predicate hasSocketInput(FunctionInput input) { input.isParameter(0) }
|
||||
|
|
|
@ -89,9 +89,9 @@ private class LocalParameterSource extends LocalFlowSource {
|
|||
|
||||
private class ArgvSource extends LocalFlowSource {
|
||||
ArgvSource() {
|
||||
exists(Parameter argv |
|
||||
argv.hasName("argv") and
|
||||
argv.getFunction().hasGlobalName("main") and
|
||||
exists(Function main, Parameter argv |
|
||||
main.hasGlobalName("main") and
|
||||
main.getParameter(1) = argv and
|
||||
this.asExpr() = argv.getAnAccess()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -116,10 +116,6 @@ class ImproperArrayIndexValidationConfig extends TaintTracking::Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
/** Gets `str` where the first letter has been lowercased. */
|
||||
bindingset[str]
|
||||
string lowerFirst(string str) { result = str.prefix(1).toLowerCase() + str.suffix(1) }
|
||||
|
||||
from
|
||||
ImproperArrayIndexValidationConfig conf, DataFlow::PathNode source, DataFlow::PathNode sink,
|
||||
string sourceType
|
||||
|
@ -128,4 +124,4 @@ where
|
|||
isFlowSource(source.getNode(), sourceType)
|
||||
select sink.getNode(), source, sink,
|
||||
"An array indexing expression depends on $@ that might be outside the bounds of the array.",
|
||||
source.getNode(), lowerFirst(sourceType)
|
||||
source.getNode(), sourceType
|
||||
|
|
|
@ -40,3 +40,13 @@ void test_scanf(FILE *stream, int *d, char *buf) {
|
|||
scanf("%d %s", d, buf); // $ local_source=40:18 local_source=40:21
|
||||
fscanf(stream, "%d %s", d, buf); // $ remote_source=41:27 remote_source=41:30
|
||||
}
|
||||
|
||||
struct addrinfo;
|
||||
|
||||
int getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
|
||||
void test_inet(char *hostname, char *servname, struct addrinfo *hints) {
|
||||
addrinfo *res;
|
||||
int ret = getaddrinfo(hostname, servname, hints, &res); // $ remote_source
|
||||
}
|
||||
|
|
|
@ -163,17 +163,17 @@ subpaths
|
|||
#select
|
||||
| test.cpp:23:12:23:19 | command1 | test.cpp:16:20:16:23 | argv | test.cpp:23:12:23:19 | command1 indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:16:20:16:23 | argv | user input (a command-line argument) | test.cpp:22:13:22:20 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:51:10:51:16 | command | test.cpp:47:21:47:26 | call to getenv | test.cpp:51:10:51:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:47:21:47:26 | call to getenv | user input (an environment variable) | test.cpp:50:11:50:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:62:9:62:16 | fread output argument | user input (String read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:82:9:82:16 | fread output argument | user input (String read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:91:9:91:16 | fread output argument | user input (String read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
|
||||
| test.cpp:65:10:65:16 | command | test.cpp:62:9:62:16 | fread output argument | test.cpp:65:10:65:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:62:9:62:16 | fread output argument | user input (string read by fread) | test.cpp:64:11:64:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:85:32:85:38 | command | test.cpp:82:9:82:16 | fread output argument | test.cpp:85:32:85:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:82:9:82:16 | fread output argument | user input (string read by fread) | test.cpp:84:11:84:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:94:45:94:48 | path | test.cpp:91:9:91:16 | fread output argument | test.cpp:94:45:94:48 | path indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:91:9:91:16 | fread output argument | user input (string read by fread) | test.cpp:93:11:93:14 | strncat output argument | strncat output argument |
|
||||
| test.cpp:108:18:108:22 | call to c_str | test.cpp:106:20:106:25 | call to getenv | test.cpp:108:18:108:22 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:106:20:106:25 | call to getenv | user input (an environment variable) | test.cpp:107:31:107:31 | call to operator+ | call to operator+ |
|
||||
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | Call | Call |
|
||||
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | Call | Call |
|
||||
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:140:9:140:11 | fread output argument | user input (String read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:178:13:178:19 | strncat output argument | strncat output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:180:13:180:19 | strncat output argument | strncat output argument |
|
||||
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
|
||||
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
|
||||
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
|
||||
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string). | test.cpp:140:9:140:11 | fread output argument | user input (string read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:178:13:178:19 | strncat output argument | strncat output argument |
|
||||
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:174:9:174:16 | fread output argument | user input (string read by fread) | test.cpp:180:13:180:19 | strncat output argument | strncat output argument |
|
||||
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:194:9:194:16 | fread output argument | user input (string read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
|
||||
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:194:9:194:16 | fread output argument | user input (string read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
|
||||
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:218:9:218:16 | fread output argument | user input (string read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
|
||||
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl. | test.cpp:218:9:218:16 | fread output argument | user input (string read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
|
||||
|
|
|
@ -6,5 +6,5 @@ nodes
|
|||
| test.cpp:58:25:58:29 | input | semmle.label | input |
|
||||
subpaths
|
||||
#select
|
||||
| test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | This write into buffer 'password' may contain unencrypted data from $@. | test2.cpp:110:3:110:6 | call to gets | user input (String read by gets) |
|
||||
| test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | test2.cpp:110:3:110:6 | call to gets | This write into buffer 'password' may contain unencrypted data from $@. | test2.cpp:110:3:110:6 | call to gets | user input (string read by gets) |
|
||||
| test.cpp:58:3:58:9 | call to sprintf | test.cpp:54:17:54:20 | argv | test.cpp:58:25:58:29 | input | This write into buffer 'passwd' may contain unencrypted data from $@. | test.cpp:54:17:54:20 | argv | user input (a command-line argument) |
|
||||
|
|
|
@ -10195,7 +10195,7 @@ extensions:
|
|||
|
||||
- addsTo:
|
||||
pack: codeql/csharp-all
|
||||
extensible: extNegativeSummaryModel
|
||||
extensible: extNeutralModel
|
||||
data:
|
||||
- ["AssemblyStripper", "AssemblyStripper", "StripAssembly", "(System.String,System.String)", "generated"]
|
||||
- ["Generators", "EventSourceGenerator", "Execute", "(Microsoft.CodeAnalysis.GeneratorExecutionContext)", "generated"]
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
* `namespace; type; subtypes; name; signature; ext; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `namespace; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Negative Summaries:
|
||||
* - Neutrals:
|
||||
* `namespace; type; name; signature; provenance`
|
||||
* A negative summary is used to indicate that there is no flow via a callable.
|
||||
* A neutral is used to indicate that there is no flow via a callable.
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
|
@ -132,30 +132,12 @@ private class SummaryModelCsvInternal extends Unit {
|
|||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Define negative summary models as data extensions instead.
|
||||
*
|
||||
* A unit class for adding additional negative summary model rows.
|
||||
*
|
||||
* Extend this class to add additional negative summary definitions.
|
||||
*/
|
||||
deprecated class NegativeSummaryModelCsv = NegativeSummaryModelCsvInternal;
|
||||
|
||||
private class NegativeSummaryModelCsvInternal extends Unit {
|
||||
/** Holds if `row` specifies a negative summary definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
private predicate sourceModelInternal(string row) { any(SourceModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate summaryModelInternal(string row) { any(SummaryModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate sinkModelInternal(string row) { any(SinkModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate negativeSummaryModelInternal(string row) {
|
||||
any(NegativeSummaryModelCsvInternal s).row(row)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a source model exists for the given parameters.
|
||||
*/
|
||||
|
@ -243,25 +225,16 @@ predicate summaryModel(
|
|||
extSummaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
}
|
||||
|
||||
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
|
||||
extensible predicate extNegativeSummaryModel(
|
||||
/** Holds if a model exists indicating there is no flow for the given parameters. */
|
||||
extensible predicate extNeutralModel(
|
||||
string namespace, string type, string name, string signature, string provenance
|
||||
);
|
||||
|
||||
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
|
||||
predicate negativeSummaryModel(
|
||||
/** Holds if a model exists indicating there is no flow for the given parameters. */
|
||||
predicate neutralModel(
|
||||
string namespace, string type, string name, string signature, string provenance
|
||||
) {
|
||||
exists(string row |
|
||||
negativeSummaryModelInternal(row) and
|
||||
row.splitAt(";", 0) = namespace and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = name and
|
||||
row.splitAt(";", 3) = signature and
|
||||
row.splitAt(";", 4) = provenance
|
||||
)
|
||||
or
|
||||
extNegativeSummaryModel(namespace, type, name, signature, provenance)
|
||||
extNeutralModel(namespace, type, name, signature, provenance)
|
||||
}
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
|
@ -393,8 +366,6 @@ module ModelValidation {
|
|||
sinkModelInternal(row) and expect = 9 and pred = "sink"
|
||||
or
|
||||
summaryModelInternal(row) and expect = 10 and pred = "summary"
|
||||
or
|
||||
negativeSummaryModelInternal(row) and expect = 5 and pred = "negative summary"
|
||||
|
|
||||
exists(int cols |
|
||||
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
|
||||
|
@ -418,9 +389,9 @@ module ModelValidation {
|
|||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
|
||||
pred = "summary"
|
||||
or
|
||||
negativeSummaryModel(namespace, type, name, signature, provenance) and
|
||||
neutralModel(namespace, type, name, signature, provenance) and
|
||||
ext = "" and
|
||||
pred = "negative summary"
|
||||
pred = "neutral"
|
||||
|
|
||||
not namespace.regexpMatch("[a-zA-Z0-9_\\.]+") and
|
||||
result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
|
||||
|
@ -461,7 +432,7 @@ private predicate elementSpec(
|
|||
or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
or
|
||||
negativeSummaryModel(namespace, type, name, signature, _) and ext = "" and subtypes = false
|
||||
neutralModel(namespace, type, name, signature, _) and ext = "" and subtypes = false
|
||||
}
|
||||
|
||||
private predicate elementSpec(
|
||||
|
@ -595,7 +566,7 @@ private Element interpretElement0(
|
|||
)
|
||||
}
|
||||
|
||||
/** Gets the source/sink/summary/negativesummary element corresponding to the supplied parameters. */
|
||||
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
|
||||
Element interpretElement(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
|
|
|
@ -2321,8 +2321,8 @@ module Csv {
|
|||
)
|
||||
}
|
||||
|
||||
/** Computes the first 4 columns for negative CSV rows of `c`. */
|
||||
string asPartialNegativeModel(DotNet::Callable c) {
|
||||
/** Computes the first 4 columns for neutral CSV rows of `c`. */
|
||||
string asPartialNeutralModel(DotNet::Callable c) {
|
||||
exists(string namespace, string type, string name, string parameters |
|
||||
partialModel(c, namespace, type, name, parameters) and
|
||||
result =
|
||||
|
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -121,12 +121,12 @@ predicate summaryElement(Callable c, string input, string output, string kind, b
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
|
||||
*/
|
||||
predicate negativeSummaryElement(Callable c, boolean generated) {
|
||||
predicate neutralElement(Callable c, boolean generated) {
|
||||
exists(string namespace, string type, string name, string signature, string provenance |
|
||||
negativeSummaryModel(namespace, type, name, signature, provenance) and
|
||||
neutralModel(namespace, type, name, signature, provenance) and
|
||||
generated = isGenerated(provenance) and
|
||||
c = interpretElement(namespace, type, false, name, signature, "")
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ private predicate relevant(ExternalApi api) {
|
|||
not api.isUninteresting() and
|
||||
(
|
||||
api.isSupported() or
|
||||
api instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable
|
||||
api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ private import ExternalApi
|
|||
private predicate relevant(ExternalApi api) {
|
||||
not api.isUninteresting() and
|
||||
not api.isSupported() and
|
||||
not api instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable
|
||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
}
|
||||
|
||||
from string info, int usages
|
||||
|
|
|
@ -18,5 +18,5 @@ where
|
|||
c.getTarget().getUnboundDeclaration() = api and
|
||||
not api.isUninteresting() and
|
||||
not api.isSupported() and
|
||||
not api instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable
|
||||
not api instanceof FlowSummaryImpl::Public::NeutralCallable
|
||||
select c, "Call to unsupported external API $@.", api, api.toString()
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* @name Capture negative summary models.
|
||||
* @description Finds negative summary models to be used by other queries.
|
||||
* @name Capture neutral models.
|
||||
* @description Finds neutral models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id cs/utils/model-generator/negative-summary-models
|
||||
* @id cs/utils/model-generator/neutral-models
|
||||
* @tags model-generator
|
||||
*/
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* @name Extract MaD negative summary model rows.
|
||||
* @description This extracts the Models as data negative summary model rows.
|
||||
* @id csharp/utils/modelconverter/generate-data-extensions-negative-summary
|
||||
* @name Extract MaD neutral model rows.
|
||||
* @description This extracts the Models as data neutral model rows.
|
||||
* @id csharp/utils/modelconverter/generate-data-extensions-neutral
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
@ -9,6 +9,6 @@ import semmle.code.csharp.dataflow.ExternalFlow
|
|||
|
||||
from string package, string type, string name, string signature, string provenance
|
||||
where
|
||||
negativeSummaryModel(package, type, name, signature, provenance) and
|
||||
neutralModel(package, type, name, signature, provenance) and
|
||||
provenance != "generated"
|
||||
select package, type, name, signature, provenance order by package, type, name, signature
|
|
@ -58,9 +58,7 @@ private string asSummaryModel(TargetApiSpecific api, string input, string output
|
|||
+ "generated"
|
||||
}
|
||||
|
||||
string asNegativeSummaryModel(TargetApiSpecific api) {
|
||||
result = asPartialNegativeModel(api) + "generated"
|
||||
}
|
||||
string asNeutralModel(TargetApiSpecific api) { result = asPartialNeutralModel(api) + "generated" }
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
|
|
|
@ -68,7 +68,7 @@ class TargetApiSpecific extends DotNet::Callable {
|
|||
|
||||
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
|
||||
|
||||
predicate asPartialNegativeModel = DataFlowPrivate::Csv::asPartialNegativeModel/1;
|
||||
predicate asPartialNeutralModel = DataFlowPrivate::Csv::asPartialNeutralModel/1;
|
||||
|
||||
/**
|
||||
* Holds if `t` is a type that is generally used for bulk data in collection types.
|
||||
|
|
|
@ -85,10 +85,10 @@ string captureFlow(DataFlowTargetApi api) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the negative summary for `api`, if any.
|
||||
* A negative summary is generated, if there does not exist any positive flow.
|
||||
* Gets the neutral model for `api`, if any.
|
||||
* A neutral model is generated, if there does not exist summary model.
|
||||
*/
|
||||
string captureNoFlow(DataFlowTargetApi api) {
|
||||
not exists(captureFlow(api)) and
|
||||
result = asNegativeSummaryModel(api)
|
||||
result = asNeutralModel(api)
|
||||
}
|
||||
|
|
|
@ -11928,7 +11928,7 @@ summary
|
|||
| System;ValueTuple<>;false;ToString;();;Argument[this];ReturnValue;taint;generated |
|
||||
| System;ValueTuple<>;false;ValueTuple;(T1);;Argument[0];Argument[this].Field[System.ValueTuple<>.Item1];value;manual |
|
||||
| System;ValueTuple<>;false;get_Item;(System.Int32);;Argument[this].Field[System.ValueTuple<>.Item1];ReturnValue;value;manual |
|
||||
negativeSummary
|
||||
neutral
|
||||
| Microsoft.CSharp.RuntimeBinder;CSharpArgumentInfo;Create;(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,System.String);generated |
|
||||
| Microsoft.CSharp.RuntimeBinder;RuntimeBinderException;RuntimeBinderException;();generated |
|
||||
| Microsoft.CSharp.RuntimeBinder;RuntimeBinderException;RuntimeBinderException;(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext);generated |
|
||||
|
|
|
@ -6,11 +6,9 @@ private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
|
|||
IncludeAllSummarizedCallable() { exists(this) }
|
||||
}
|
||||
|
||||
private class IncludeNegativeSummarizedCallable extends RelevantNegativeSummarizedCallable {
|
||||
IncludeNegativeSummarizedCallable() {
|
||||
this instanceof FlowSummaryImpl::Public::NegativeSummarizedCallable
|
||||
}
|
||||
private class IncludeNeutralCallable extends RelevantNeutralCallable {
|
||||
IncludeNeutralCallable() { this instanceof FlowSummaryImpl::Public::NeutralCallable }
|
||||
|
||||
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
|
||||
final override string getCallableCsv() { result = Csv::asPartialNegativeModel(this) }
|
||||
final override string getCallableCsv() { result = Csv::asPartialNeutralModel(this) }
|
||||
}
|
||||
|
|
|
@ -10262,4 +10262,4 @@ summary
|
|||
| System;ValueTuple<>;false;ToString;();;Argument[this];ReturnValue;taint;generated |
|
||||
| System;ValueTuple<>;false;ValueTuple;(T1);;Argument[0];Argument[this].Field[System.ValueTuple<>.Item1];value;manual |
|
||||
| System;ValueTuple<>;false;get_Item;(System.Int32);;Argument[this].Field[System.ValueTuple<>.Item1];ReturnValue;value;manual |
|
||||
negativeSummary
|
||||
neutral
|
||||
|
|
|
@ -131,7 +131,7 @@ summary
|
|||
| System.Data.Entity;DbSet<>;false;AttachRange;(System.Collections.Generic.IEnumerable<T>);;Argument[0].Element;Argument[this].Element;value;manual |
|
||||
| System.Data.Entity;DbSet<>;false;Update;(T);;Argument[0];Argument[this].Element;value;manual |
|
||||
| System.Data.Entity;DbSet<>;false;UpdateRange;(System.Collections.Generic.IEnumerable<T>);;Argument[0].Element;Argument[this].Element;value;manual |
|
||||
negativeSummary
|
||||
neutral
|
||||
sourceNode
|
||||
sinkNode
|
||||
| EntityFrameworkCore.cs:72:36:72:40 | "sql" | sql |
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
utils/model-generator/CaptureNegativeSummaryModels.ql
|
|
@ -0,0 +1 @@
|
|||
utils/model-generator/CaptureNeutralModels.ql
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,11 +76,11 @@ predicate summaryElement(
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Note. Negative flow summaries has not been implemented for Go.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the model is autogenerated.
|
||||
* Note. Neutral models have not been implemented for Go.
|
||||
*/
|
||||
predicate negativeSummaryElement(SummarizedCallable c, boolean generated) { none() }
|
||||
predicate neutralElement(SummarizedCallable c, boolean generated) { none() }
|
||||
|
||||
/** Gets the summary component for specification component `c`, if any. */
|
||||
bindingset[c]
|
||||
|
|
|
@ -957,7 +957,7 @@ open class KotlinFileExtractor(
|
|||
val locId = getLocation(f, null)
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
val dispatchReceiver = if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter
|
||||
val parameterTypes = listOfNotNull(extReceiver?.let { erase(it.type) }) + getDefaultsMethodArgTypes(f)
|
||||
val parameterTypes = getDefaultsMethodArgTypes(f)
|
||||
val allParamTypeResults = parameterTypes.mapIndexed { i, paramType ->
|
||||
val paramId = tw.getLabelFor<DbParam>(getValueParameterLabel(id, i))
|
||||
extractValueParameter(paramId, paramType, "p$i", locId, id, i, paramId, isVararg = false, syntheticParameterNames = true, isCrossinline = false, isNoinline = false).also {
|
||||
|
@ -975,6 +975,11 @@ open class KotlinFileExtractor(
|
|||
val methodId = id.cast<DbMethod>()
|
||||
extractMethod(methodId, locId, shortName, erase(f.returnType), paramsSignature, parentId, methodId, origin = null, extractTypeAccess = extractMethodAndParameterTypeAccesses)
|
||||
addModifiers(id, "static")
|
||||
if (extReceiver != null) {
|
||||
val idx = if (dispatchReceiver != null) 1 else 0
|
||||
val extendedType = allParamTypeResults[idx]
|
||||
tw.writeKtExtensionFunctions(methodId, extendedType.javaResult.id, extendedType.kotlinResult.id)
|
||||
}
|
||||
}
|
||||
tw.writeHasLocation(id, locId)
|
||||
if (f.visibility != DescriptorVisibilities.PRIVATE && f.visibility != DescriptorVisibilities.PRIVATE_TO_THIS) {
|
||||
|
@ -1040,8 +1045,8 @@ open class KotlinFileExtractor(
|
|||
val realFnIdxOffset = if (f.extensionReceiverParameter != null) 1 else 0
|
||||
val paramMappings = f.valueParameters.mapIndexed { idx, param -> Triple(param.type, idx + paramIdxOffset, idx + realFnIdxOffset) } +
|
||||
listOfNotNull(
|
||||
dispatchReceiver?.let { Triple(it.type, realFnIdxOffset, -1) },
|
||||
extReceiver?.let { Triple(it.type, 0, 0) }
|
||||
dispatchReceiver?.let { Triple(it.type, 0, -1) },
|
||||
extReceiver?.let { Triple(it.type, if (dispatchReceiver != null) 1 else 0, 0) }
|
||||
)
|
||||
paramMappings.forEach { (type, fromIdx, toIdx) ->
|
||||
extractVariableAccess(tw.getLabelFor<DbParam>(getValueParameterLabel(id, fromIdx)), type, locId, thisCallId, toIdx, id, returnId)
|
||||
|
@ -1184,6 +1189,7 @@ open class KotlinFileExtractor(
|
|||
id
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
// The following parameter order is correct, because member $default methods (where the order would be [dispatchParam], [extensionParam], normalParams) are not extracted here
|
||||
val fParameters = listOfNotNull(extReceiver) + (overriddenAttributes?.valueParameters ?: f.valueParameters)
|
||||
val paramTypes = fParameters.mapIndexed { i, vp ->
|
||||
extractValueParameter(vp, id, i, typeSubstitution, sourceDeclaration, classTypeArgsIncludingOuterClasses, extractTypeAccess = extractMethodAndParameterTypeAccesses, overriddenAttributes?.sourceLoc)
|
||||
|
@ -1793,11 +1799,12 @@ open class KotlinFileExtractor(
|
|||
) ?: pluginContext.irBuiltIns.anyType
|
||||
|
||||
private fun getDefaultsMethodArgTypes(f: IrFunction) =
|
||||
// The $default method has type ([extensionReceiver], [dispatchReceiver], paramTypes..., int, Object)
|
||||
// The $default method has type ([dispatchReceiver], [extensionReceiver], paramTypes..., int, Object)
|
||||
// All parameter types are erased. The trailing int is a mask indicating which parameter values are real
|
||||
// and which should be replaced by defaults. The final Object parameter is apparently always null.
|
||||
(
|
||||
listOfNotNull(if (f.shouldExtractAsStatic) null else f.dispatchReceiverParameter?.type) +
|
||||
listOfNotNull(f.extensionReceiverParameter?.type) +
|
||||
f.valueParameters.map { it.type } +
|
||||
listOf(pluginContext.irBuiltIns.intType, getDefaultsMethodLastArgType(f))
|
||||
).map { erase(it) }
|
||||
|
@ -1816,17 +1823,16 @@ open class KotlinFileExtractor(
|
|||
|
||||
private fun getDefaultsMethodLabel(f: IrFunction): Label<out DbCallable> {
|
||||
val defaultsMethodName = if (f is IrConstructor) "<init>" else getDefaultsMethodName(f)
|
||||
val normalArgTypes = getDefaultsMethodArgTypes(f)
|
||||
val extensionParamType = f.extensionReceiverParameter?.let { erase(it.type) }
|
||||
val argTypes = getDefaultsMethodArgTypes(f)
|
||||
|
||||
val defaultMethodLabelStr = getFunctionLabel(
|
||||
f.parent,
|
||||
maybeParentId = null,
|
||||
defaultsMethodName,
|
||||
normalArgTypes,
|
||||
argTypes,
|
||||
erase(f.returnType),
|
||||
extensionParamType,
|
||||
listOf(),
|
||||
extensionParamType = null, // if there's any, that's included already in argTypes
|
||||
functionTypeParameters = listOf(),
|
||||
classTypeArgsIncludingOuterClasses = null,
|
||||
overridesCollectionsMethod = false,
|
||||
javaSignature = null,
|
||||
|
@ -1886,13 +1892,14 @@ open class KotlinFileExtractor(
|
|||
extensionReceiver: IrExpression?
|
||||
) {
|
||||
var nextIdx = 0
|
||||
if (extensionReceiver != null) {
|
||||
extractExpressionExpr(extensionReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
if (dispatchReceiver != null && !callTarget.shouldExtractAsStatic) {
|
||||
extractExpressionExpr(dispatchReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
|
||||
if (extensionReceiver != null) {
|
||||
extractExpressionExpr(extensionReceiver, enclosingCallable, id, nextIdx++, enclosingStmt)
|
||||
}
|
||||
|
||||
val valueArgsWithDummies = valueArguments.zip(callTarget.valueParameters).map {
|
||||
(expr, param) -> expr ?: IrConstImpl.defaultValueForType(0, 0, param.type)
|
||||
}
|
||||
|
@ -4046,8 +4053,7 @@ open class KotlinFileExtractor(
|
|||
// Use of 'this' in a function where the dispatch receiver is passed like an ordinary parameter,
|
||||
// such as a `$default` static function that substitutes in default arguments as needed.
|
||||
val paramDeclarerId = overriddenAttributes.id ?: useDeclarationParent(thisParamParent, false)
|
||||
val extensionParamOffset = if (thisParamParent.extensionReceiverParameter != null) 1 else 0
|
||||
val replacementParamId = tw.getLabelFor<DbParam>(getValueParameterLabel(paramDeclarerId, replaceWithParamIdx + extensionParamOffset))
|
||||
val replacementParamId = tw.getLabelFor<DbParam>(getValueParameterLabel(paramDeclarerId, replaceWithParamIdx))
|
||||
extractVariableAccess(replacementParamId, e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import java.util.Stack
|
|||
import org.jetbrains.kotlin.ir.IrElement
|
||||
|
||||
class LogCounter() {
|
||||
public val diagnosticCounts = mutableMapOf<String, Int>()
|
||||
public val diagnosticInfo = mutableMapOf<String, Pair<Severity, Int>>()
|
||||
public val diagnosticLimit: Int
|
||||
init {
|
||||
diagnosticLimit = System.getenv("CODEQL_EXTRACTOR_KOTLIN_DIAGNOSTIC_LIMIT")?.toIntOrNull() ?: 100
|
||||
|
@ -114,12 +114,23 @@ open class LoggerBase(val logCounter: LogCounter) {
|
|||
if(diagnosticLoc == null) {
|
||||
" Missing caller information.\n"
|
||||
} else {
|
||||
val count = logCounter.diagnosticCounts.getOrDefault(diagnosticLoc, 0) + 1
|
||||
logCounter.diagnosticCounts[diagnosticLoc] = count
|
||||
val oldInfo = logCounter.diagnosticInfo.getOrDefault(diagnosticLoc, Pair(severity, 0))
|
||||
if(severity != oldInfo.first) {
|
||||
// We don't want to get in a loop, so just emit this
|
||||
// directly without going through the diagnostic
|
||||
// counting machinery
|
||||
if (verbosity >= 1) {
|
||||
val message = "Severity mismatch ($severity vs ${oldInfo.first}) at $diagnosticLoc"
|
||||
emitDiagnostic(tw, Severity.Error, "Inconsistency", message, message)
|
||||
}
|
||||
}
|
||||
val newCount = oldInfo.second + 1
|
||||
val newInfo = Pair(severity, newCount)
|
||||
logCounter.diagnosticInfo[diagnosticLoc] = newInfo
|
||||
when {
|
||||
logCounter.diagnosticLimit <= 0 -> ""
|
||||
count == logCounter.diagnosticLimit -> " Limit reached for diagnostics from $diagnosticLoc.\n"
|
||||
count > logCounter.diagnosticLimit -> return
|
||||
newCount == logCounter.diagnosticLimit -> " Limit reached for diagnostics from $diagnosticLoc.\n"
|
||||
newCount > logCounter.diagnosticLimit -> return
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
@ -189,14 +200,16 @@ open class LoggerBase(val logCounter: LogCounter) {
|
|||
}
|
||||
|
||||
fun printLimitedDiagnosticCounts(tw: TrapWriter) {
|
||||
for((caller, count) in logCounter.diagnosticCounts) {
|
||||
for((caller, info) in logCounter.diagnosticInfo) {
|
||||
val severity = info.first
|
||||
val count = info.second
|
||||
if(count >= logCounter.diagnosticLimit) {
|
||||
// We don't know if this location relates to an error
|
||||
// or a warning, so we just declare hitting the limit
|
||||
// to be an error regardless.
|
||||
val message = "Total of $count diagnostics (reached limit of ${logCounter.diagnosticLimit}) from $caller."
|
||||
if (verbosity >= 1) {
|
||||
emitDiagnostic(tw, Severity.Error, "Limit", message, message)
|
||||
emitDiagnostic(tw, severity, "Limit", message, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The extraction of Kotlin extension methods has been improved when default parameter values are present. The dispatch and extension receiver parameters are extracted in the correct order. The `ExtensionMethod::getExtensionReceiverParameterIndex` predicate has been introduced to facilitate getting the correct extension parameter index.
|
|
@ -14,5 +14,5 @@ extensions:
|
|||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: extNegativeSummaryModel
|
||||
extensible: extNeutralModel
|
||||
data: []
|
|
@ -1861,7 +1861,7 @@ extensions:
|
|||
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: extNegativeSummaryModel
|
||||
extensible: extNeutralModel
|
||||
data:
|
||||
- ["kotlin.annotation", "AnnotationRetention", "valueOf", "(String)", "generated"]
|
||||
- ["kotlin.annotation", "AnnotationRetention", "values", "()", "generated"]
|
||||
|
|
|
@ -676,7 +676,7 @@ extensions:
|
|||
|
||||
- addsTo:
|
||||
pack: codeql/java-all
|
||||
extensible: extNegativeSummaryModel
|
||||
extensible: extNeutralModel
|
||||
data:
|
||||
- ["org.apache.commons.io.charset", "CharsetDecoders", "CharsetDecoders", "()", "generated"]
|
||||
- ["org.apache.commons.io.charset", "CharsetEncoders", "CharsetEncoders", "()", "generated"]
|
||||
|
|
|
@ -1896,7 +1896,8 @@ class VarAccess extends Expr, @varaccess {
|
|||
class ExtensionReceiverAccess extends VarAccess {
|
||||
ExtensionReceiverAccess() {
|
||||
exists(Parameter p |
|
||||
this.getVariable() = p and p.getPosition() = 0 and p.getCallable() instanceof ExtensionMethod
|
||||
this.getVariable() = p and
|
||||
p.isExtensionParameter()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -327,18 +327,8 @@ class Callable extends StmtParent, Member, @callable {
|
|||
this instanceof Method and
|
||||
result instanceof Method and
|
||||
this.getName() + "$default" = result.getName() and
|
||||
extraLeadingParams <= 1 and
|
||||
(
|
||||
if ktExtensionFunctions(this, _, _)
|
||||
then
|
||||
// Both extension receivers are expected to occur at arg0, with any
|
||||
// dispatch receiver inserted afterwards in the $default proxy's parameter list.
|
||||
// Check the extension receiver matches here, and note regular args
|
||||
// are bumped one position to the right.
|
||||
regularParamsStartIdx = extraLeadingParams + 1 and
|
||||
this.getParameterType(0).getErasure() = eraseRaw(result.getParameterType(0))
|
||||
else regularParamsStartIdx = extraLeadingParams
|
||||
) and
|
||||
extraLeadingParams <= 1 and // 0 for static methods, 1 for instance methods
|
||||
regularParamsStartIdx = extraLeadingParams and
|
||||
lastParamType instanceof TypeObject
|
||||
)
|
||||
|
|
||||
|
@ -824,4 +814,19 @@ class ExtensionMethod extends Method {
|
|||
KotlinType getExtendedKotlinType() { result = extendedKotlinType }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "ExtensionMethod" }
|
||||
|
||||
/**
|
||||
* Gets the index of the parameter that is the extension receiver. This is typically index 0. In case of `$default`
|
||||
* extension methods that are defined as members, the index is 1. Index 0 is the dispatch receiver of the `$default`
|
||||
* method.
|
||||
*/
|
||||
int getExtensionReceiverParameterIndex() {
|
||||
if
|
||||
exists(Method src |
|
||||
this = src.getKotlinParameterDefaultsProxy() and
|
||||
src.getNumberOfParameters() = this.getNumberOfParameters() - 3 // 2 extra parameters + 1 dispatch receiver
|
||||
)
|
||||
then result = 1
|
||||
else result = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ class Parameter extends Element, @param, LocalScopeVariable {
|
|||
|
||||
/** Holds if this formal parameter is a parameter representing the dispatch receiver in an extension method. */
|
||||
predicate isExtensionParameter() {
|
||||
this.getPosition() = 0 and this.getCallable() instanceof ExtensionMethod
|
||||
this.getPosition() = this.getCallable().(ExtensionMethod).getExtensionReceiverParameterIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
* `package; type; subtypes; name; signature; ext; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `package; type; subtypes; name; signature; ext; input; output; kind; provenance`
|
||||
* - Negative Summaries:
|
||||
* - Neutrals:
|
||||
* `package; type; name; signature; provenance`
|
||||
* A negative summary is used to indicate that there is no flow via a callable.
|
||||
* A neutral is used to indicate that there is no flow via a callable.
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
|
@ -122,30 +122,12 @@ private class SummaryModelCsvInternal extends Unit {
|
|||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Define negative summary models as data extensions instead.
|
||||
*
|
||||
* A unit class for adding additional negative summary model rows.
|
||||
*
|
||||
* Extend this class to add additional negative summary definitions.
|
||||
*/
|
||||
deprecated class NegativeSummaryModelCsv = NegativeSummaryModelCsvInternal;
|
||||
|
||||
private class NegativeSummaryModelCsvInternal extends Unit {
|
||||
/** Holds if `row` specifies a negative summary definition. */
|
||||
abstract predicate row(string row);
|
||||
}
|
||||
|
||||
private predicate sourceModelInternal(string row) { any(SourceModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate summaryModelInternal(string row) { any(SummaryModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate sinkModelInternal(string row) { any(SinkModelCsvInternal s).row(row) }
|
||||
|
||||
private predicate negativeSummaryModelInternal(string row) {
|
||||
any(NegativeSummaryModelCsvInternal s).row(row)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an experimental source model exists for the given parameters.
|
||||
* This is only for experimental queries.
|
||||
|
@ -313,25 +295,14 @@ predicate summaryModel(
|
|||
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
}
|
||||
|
||||
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
|
||||
extensible predicate extNegativeSummaryModel(
|
||||
/** Holds if a neutral model exists indicating there is no flow for the given parameters. */
|
||||
extensible predicate extNeutralModel(
|
||||
string package, string type, string name, string signature, string provenance
|
||||
);
|
||||
|
||||
/** Holds if a summary model exists indicating there is no flow for the given parameters. */
|
||||
predicate negativeSummaryModel(
|
||||
string package, string type, string name, string signature, string provenance
|
||||
) {
|
||||
exists(string row |
|
||||
negativeSummaryModelInternal(row) and
|
||||
row.splitAt(";", 0) = package and
|
||||
row.splitAt(";", 1) = type and
|
||||
row.splitAt(";", 2) = name and
|
||||
row.splitAt(";", 3) = signature and
|
||||
row.splitAt(";", 4) = provenance
|
||||
)
|
||||
or
|
||||
extNegativeSummaryModel(package, type, name, signature, provenance)
|
||||
/** Holds if a neutral model exists indicating there is no flow for the given parameters. */
|
||||
predicate neutralModel(string package, string type, string name, string signature, string provenance) {
|
||||
extNeutralModel(package, type, name, signature, provenance)
|
||||
}
|
||||
|
||||
private predicate relevantPackage(string package) {
|
||||
|
@ -472,8 +443,6 @@ module ModelValidation {
|
|||
sinkModelInternal(row) and expect = 9 and pred = "sink"
|
||||
or
|
||||
summaryModelInternal(row) and expect = 10 and pred = "summary"
|
||||
or
|
||||
negativeSummaryModelInternal(row) and expect = 5 and pred = "negative summary"
|
||||
|
|
||||
exists(int cols |
|
||||
cols = 1 + max(int n | exists(row.splitAt(";", n))) and
|
||||
|
@ -497,9 +466,9 @@ module ModelValidation {
|
|||
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance) and
|
||||
pred = "summary"
|
||||
or
|
||||
negativeSummaryModel(package, type, name, signature, provenance) and
|
||||
neutralModel(package, type, name, signature, provenance) and
|
||||
ext = "" and
|
||||
pred = "negative summary"
|
||||
pred = "neutral"
|
||||
|
|
||||
not package.regexpMatch("[a-zA-Z0-9_\\.]*") and
|
||||
result = "Dubious package \"" + package + "\" in " + pred + " model."
|
||||
|
@ -541,7 +510,7 @@ private predicate elementSpec(
|
|||
or
|
||||
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
or
|
||||
negativeSummaryModel(package, type, name, signature, _) and ext = "" and subtypes = false
|
||||
neutralModel(package, type, name, signature, _) and ext = "" and subtypes = false
|
||||
}
|
||||
|
||||
private string paramsStringPart(Callable c, int i) {
|
||||
|
@ -590,7 +559,7 @@ private Element interpretElement0(
|
|||
)
|
||||
}
|
||||
|
||||
/** Gets the source/sink/summary/negativesummary element corresponding to the supplied parameters. */
|
||||
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
|
||||
Element interpretElement(
|
||||
string package, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
|
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,8 +120,11 @@ private predicate correspondingKotlinParameterDefaultsArgSpec(
|
|||
exists(int oldArgParsed |
|
||||
oldArgParsed = AccessPathSyntax::AccessPath::parseInt(oldArgNumber.splitAt(",").trim())
|
||||
|
|
||||
if ktExtensionFunctions(originalCallable, _, _) and oldArgParsed = 0
|
||||
then defaultsArgSpec = "Argument[0]"
|
||||
if
|
||||
ktExtensionFunctions(originalCallable, _, _) and
|
||||
ktExtensionFunctions(defaultsCallable, _, _) and
|
||||
oldArgParsed = 0
|
||||
then defaultsArgSpec = "Argument[" + paramOffset + "]" // 1 if dispatch receiver is present, 0 otherwise.
|
||||
else defaultsArgSpec = "Argument[" + (oldArgParsed + paramOffset) + "]" + rest
|
||||
)
|
||||
)
|
||||
|
@ -160,12 +163,12 @@ predicate summaryElement(
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the model is autogenerated.
|
||||
*/
|
||||
predicate negativeSummaryElement(SummarizedCallableBase c, boolean generated) {
|
||||
predicate neutralElement(SummarizedCallableBase c, boolean generated) {
|
||||
exists(string namespace, string type, string name, string signature, string provenance |
|
||||
negativeSummaryModel(namespace, type, name, signature, provenance) and
|
||||
neutralModel(namespace, type, name, signature, provenance) and
|
||||
generated = isGenerated(provenance) and
|
||||
c.asCallable() = interpretElement(namespace, type, false, name, signature, "")
|
||||
)
|
||||
|
|
|
@ -298,8 +298,9 @@ private class PathNormalizeSanitizer extends MethodAccess {
|
|||
* what `getQualifier` actually gets in Java and Kotlin.
|
||||
*/
|
||||
private Expr getVisualQualifier(MethodAccess ma) {
|
||||
if getSourceMethod(ma.getMethod()) instanceof ExtensionMethod
|
||||
then result = ma.getArgument(0)
|
||||
if ma.getMethod() instanceof ExtensionMethod
|
||||
then
|
||||
result = ma.getArgument(ma.getMethod().(ExtensionMethod).getExtensionReceiverParameterIndex())
|
||||
else result = ma.getQualifier()
|
||||
}
|
||||
|
||||
|
@ -310,8 +311,11 @@ private Expr getVisualQualifier(MethodAccess ma) {
|
|||
*/
|
||||
bindingset[argPos]
|
||||
private Argument getVisualArgument(MethodAccess ma, int argPos) {
|
||||
if getSourceMethod(ma.getMethod()) instanceof ExtensionMethod
|
||||
then result = ma.getArgument(argPos + 1)
|
||||
if ma.getMethod() instanceof ExtensionMethod
|
||||
then
|
||||
result =
|
||||
ma.getArgument(argPos + ma.getMethod().(ExtensionMethod).getExtensionReceiverParameterIndex() +
|
||||
1)
|
||||
else result = ma.getArgument(argPos)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ private predicate relevant(ExternalApi api) {
|
|||
not api.isUninteresting() and
|
||||
(
|
||||
api.isSupported() or
|
||||
api = any(FlowSummaryImpl::Public::NegativeSummarizedCallable nsc).asCallable()
|
||||
api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import ExternalApi
|
|||
private predicate relevant(ExternalApi api) {
|
||||
not api.isUninteresting() and
|
||||
not api.isSupported() and
|
||||
not api = any(FlowSummaryImpl::Public::NegativeSummarizedCallable nsc).asCallable()
|
||||
not api = any(FlowSummaryImpl::Public::NeutralCallable nsc).asCallable()
|
||||
}
|
||||
|
||||
from string apiName, int usages
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/**
|
||||
* @name Capture negative summary models.
|
||||
* @description Finds negative summary models to be used by other queries.
|
||||
* @name Capture neutral models.
|
||||
* @description Finds neutral models to be used by other queries.
|
||||
* @kind diagnostic
|
||||
* @id java/utils/model-generator/negative-summary-models
|
||||
* @id java/utils/model-generator/neutral-models
|
||||
* @tags model-generator
|
||||
*/
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
# Tool to regenerate existing framework CSV models.
|
||||
|
||||
from pathlib import Path
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
|
@ -37,7 +36,7 @@ def regenerateModel(lgtmSlug, extractedDb):
|
|||
modelFile = lgtmSlugToModelFile[lgtmSlug]
|
||||
codeQlRoot = findGitRoot()
|
||||
subprocess.check_call([codeQlRoot + "/java/ql/src/utils/model-generator/GenerateFlowModel.py",
|
||||
"--with-summaries", "--with-sinks", "--with-negative-summaries",
|
||||
"--with-summaries", "--with-sinks", "--with-neutrals",
|
||||
extractedDb, modelFile])
|
||||
print("Regenerated " + modelFile)
|
||||
shutil.rmtree(tmpDir)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* @name Extract MaD negative summary model rows.
|
||||
* @description This extracts the Models as data negative summary model rows.
|
||||
* @id java/utils/modelconverter/generate-data-extensions-negative-summary
|
||||
* @name Extract MaD neutral model rows.
|
||||
* @description This extracts the Models as data neutral model rows.
|
||||
* @id java/utils/modelconverter/generate-data-extensions-neutral
|
||||
*/
|
||||
|
||||
import java
|
||||
|
@ -9,6 +9,6 @@ import semmle.code.java.dataflow.ExternalFlow
|
|||
|
||||
from string package, string type, string name, string signature, string provenance
|
||||
where
|
||||
negativeSummaryModel(package, type, name, signature, provenance) and
|
||||
neutralModel(package, type, name, signature, provenance) and
|
||||
provenance != "generated"
|
||||
select package, type, name, signature, provenance order by package, type, name, signature
|
|
@ -58,9 +58,7 @@ private string asSummaryModel(TargetApiSpecific api, string input, string output
|
|||
+ "generated"
|
||||
}
|
||||
|
||||
string asNegativeSummaryModel(TargetApiSpecific api) {
|
||||
result = asPartialNegativeModel(api) + "generated"
|
||||
}
|
||||
string asNeutralModel(TargetApiSpecific api) { result = asPartialNeutralModel(api) + "generated" }
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
|
|
|
@ -131,9 +131,9 @@ string asPartialModel(TargetApiSpecific api) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Computes the first 4 columns for negative CSV rows.
|
||||
* Computes the first 4 columns for neutral CSV rows.
|
||||
*/
|
||||
string asPartialNegativeModel(TargetApiSpecific api) {
|
||||
string asPartialNeutralModel(TargetApiSpecific api) {
|
||||
exists(string type, string name, string parameters |
|
||||
partialModel(api, type, name, parameters) and
|
||||
result =
|
||||
|
|
|
@ -77,10 +77,10 @@ string captureFlow(DataFlowTargetApi api) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the negative summary for `api`, if any.
|
||||
* A negative summary is generated, if there does not exist any positive flow.
|
||||
* Gets the neutral summary for `api`, if any.
|
||||
* A neutral model is generated, if there does not exist any summary model.
|
||||
*/
|
||||
string captureNoFlow(DataFlowTargetApi api) {
|
||||
not exists(captureFlow(api)) and
|
||||
result = asNegativeSummaryModel(api)
|
||||
result = asNeutralModel(api)
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ test.kt:
|
|||
# 45| 5: [BlockStmt] { ... }
|
||||
# 45| 0: [ReturnStmt] return ...
|
||||
# 45| 0: [VarAccess] a
|
||||
# 45| 5: [Method] testExtensionFunction$default
|
||||
# 45| 5: [ExtensionMethod] testExtensionFunction$default
|
||||
# 45| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 45| 0: [Parameter] p0
|
||||
|
@ -116,7 +116,7 @@ test.kt:
|
|||
# 45| 2: [ReturnStmt] return ...
|
||||
# 45| 0: [MethodAccess] testExtensionFunction(...)
|
||||
# 45| -1: [TypeAccess] TestKt
|
||||
# 45| 0: [VarAccess] p0
|
||||
# 45| 0: [ExtensionReceiverAccess] this
|
||||
# 45| 1: [VarAccess] p1
|
||||
# 45| 2: [VarAccess] p2
|
||||
# 45| 3: [VarAccess] p3
|
||||
|
@ -356,9 +356,9 @@ test.kt:
|
|||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [MethodAccess] testMemberExtensionFunction$default(...)
|
||||
# 12| -1: [TypeAccess] Test
|
||||
# 0| 0: [ExtensionReceiverAccess] this
|
||||
# 0| 1: [ThisAccess] Test.this
|
||||
# 0| 0: [ThisAccess] Test.this
|
||||
# 0| 0: [TypeAccess] Test
|
||||
# 0| 1: [ExtensionReceiverAccess] this
|
||||
# 0| 2: [VarAccess] a
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 0| 4: [VarAccess] c
|
||||
|
@ -383,9 +383,9 @@ test.kt:
|
|||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [MethodAccess] testMemberExtensionFunction$default(...)
|
||||
# 12| -1: [TypeAccess] Test
|
||||
# 0| 0: [ExtensionReceiverAccess] this
|
||||
# 0| 1: [ThisAccess] Test.this
|
||||
# 0| 0: [ThisAccess] Test.this
|
||||
# 0| 0: [TypeAccess] Test
|
||||
# 0| 1: [ExtensionReceiverAccess] this
|
||||
# 0| 2: [VarAccess] a
|
||||
# 0| 3: [VarAccess] b
|
||||
# 0| 4: [VarAccess] c
|
||||
|
@ -411,13 +411,13 @@ test.kt:
|
|||
# 12| 5: [BlockStmt] { ... }
|
||||
# 12| 0: [ReturnStmt] return ...
|
||||
# 12| 0: [VarAccess] a
|
||||
# 12| 13: [Method] testMemberExtensionFunction$default
|
||||
# 12| 13: [ExtensionMethod] testMemberExtensionFunction$default
|
||||
# 12| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 12| 0: [Parameter] p0
|
||||
# 12| 0: [TypeAccess] Test2
|
||||
# 12| 1: [Parameter] p1
|
||||
# 12| 0: [TypeAccess] Test
|
||||
# 12| 1: [Parameter] p1
|
||||
# 12| 0: [TypeAccess] Test2
|
||||
# 12| 2: [Parameter] p2
|
||||
# 12| 0: [TypeAccess] int
|
||||
# 12| 3: [Parameter] p3
|
||||
|
@ -456,8 +456,8 @@ test.kt:
|
|||
# 12| 1: [FloatLiteral] 1.0
|
||||
# 12| 2: [ReturnStmt] return ...
|
||||
# 12| 0: [MethodAccess] testMemberExtensionFunction(...)
|
||||
# 12| -1: [VarAccess] p1
|
||||
# 12| 0: [VarAccess] p0
|
||||
# 12| -1: [VarAccess] p0
|
||||
# 12| 0: [ExtensionReceiverAccess] this
|
||||
# 12| 1: [VarAccess] p2
|
||||
# 12| 2: [VarAccess] p3
|
||||
# 12| 3: [VarAccess] p4
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,java.lang.String,double,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction | testMemberExtensionFunction(Test2,int,java.lang.String,double,float,boolean) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction$default | testMemberExtensionFunction$default(Test2,Test,int,java.lang.String,double,float,boolean,int,java.lang.Object) |
|
||||
| test.kt:3:1:14:1 | Test | test.kt:12:3:12:121 | testMemberExtensionFunction$default | testMemberExtensionFunction$default(Test,Test2,int,java.lang.String,double,float,boolean,int,java.lang.Object) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,java.lang.String,double,boolean) |
|
||||
| test.kt:16:1:28:1 | Test2 | test.kt:16:34:28:1 | Test2 | Test2(int,java.lang.String,double,float,boolean) |
|
||||
|
|
|
@ -293,12 +293,47 @@
|
|||
| methods2.kt:8:5:9:5 | Unit | TypeAccess |
|
||||
| methods2.kt:8:27:8:32 | int | TypeAccess |
|
||||
| methods2.kt:8:35:8:40 | int | TypeAccess |
|
||||
| methods3.kt:3:1:3:42 | Unit | TypeAccess |
|
||||
| methods3.kt:3:5:3:7 | int | TypeAccess |
|
||||
| methods3.kt:3:33:3:38 | int | TypeAccess |
|
||||
| methods3.kt:6:5:6:46 | Unit | TypeAccess |
|
||||
| methods3.kt:6:9:6:11 | int | TypeAccess |
|
||||
| methods3.kt:6:37:6:42 | int | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | 0 | IntegerLiteral |
|
||||
| methods3.kt:3:1:3:49 | 1 | IntegerLiteral |
|
||||
| methods3.kt:3:1:3:49 | ... & ... | AndBitwiseExpr |
|
||||
| methods3.kt:3:1:3:49 | ... == ... | EQExpr |
|
||||
| methods3.kt:3:1:3:49 | ...=... | AssignExpr |
|
||||
| methods3.kt:3:1:3:49 | Methods3Kt | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | Object | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | String | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | Unit | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | Unit | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt(...) | MethodAccess |
|
||||
| methods3.kt:3:1:3:49 | int | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | int | TypeAccess |
|
||||
| methods3.kt:3:1:3:49 | p1 | VarAccess |
|
||||
| methods3.kt:3:1:3:49 | p1 | VarAccess |
|
||||
| methods3.kt:3:1:3:49 | p2 | VarAccess |
|
||||
| methods3.kt:3:1:3:49 | this | ExtensionReceiverAccess |
|
||||
| methods3.kt:3:5:3:10 | String | TypeAccess |
|
||||
| methods3.kt:3:36:3:45 | int | TypeAccess |
|
||||
| methods3.kt:3:45:3:45 | 1 | IntegerLiteral |
|
||||
| methods3.kt:6:5:6:45 | 0 | IntegerLiteral |
|
||||
| methods3.kt:6:5:6:45 | 1 | IntegerLiteral |
|
||||
| methods3.kt:6:5:6:45 | ... & ... | AndBitwiseExpr |
|
||||
| methods3.kt:6:5:6:45 | ... == ... | EQExpr |
|
||||
| methods3.kt:6:5:6:45 | ...=... | AssignExpr |
|
||||
| methods3.kt:6:5:6:45 | Class3 | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | Object | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | String | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | Unit | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | Unit | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt(...) | MethodAccess |
|
||||
| methods3.kt:6:5:6:45 | int | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | int | TypeAccess |
|
||||
| methods3.kt:6:5:6:45 | p0 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p2 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p2 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | p3 | VarAccess |
|
||||
| methods3.kt:6:5:6:45 | this | ExtensionReceiverAccess |
|
||||
| methods3.kt:6:9:6:14 | String | TypeAccess |
|
||||
| methods3.kt:6:32:6:41 | int | TypeAccess |
|
||||
| methods3.kt:6:41:6:41 | 1 | IntegerLiteral |
|
||||
| methods4.kt:7:5:7:34 | Unit | TypeAccess |
|
||||
| methods4.kt:7:11:7:29 | InsideNestedTest | TypeAccess |
|
||||
| methods5.kt:3:1:11:1 | Unit | TypeAccess |
|
||||
|
|
|
@ -38,8 +38,10 @@ methods
|
|||
| enumClass.kt:8:3:11:4 | VAL | enumClass.kt:10:14:10:42 | g | g(int) | override, public | |
|
||||
| methods2.kt:0:0:0:0 | Methods2Kt | methods2.kt:4:1:5:1 | fooBarTopLevelMethod | fooBarTopLevelMethod(int,int) | final, public, static | |
|
||||
| methods2.kt:7:1:10:1 | Class2 | methods2.kt:8:5:9:5 | fooBarClassMethod | fooBarClassMethod(int,int) | final, public | |
|
||||
| methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:42 | fooBarTopLevelMethodExt | fooBarTopLevelMethodExt(int,int) | final, public, static | |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:46 | fooBarTopLevelMethodExt | fooBarTopLevelMethodExt(int,int) | final, public | |
|
||||
| methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | fooBarTopLevelMethodExt(java.lang.String,int) | final, public, static | |
|
||||
| methods3.kt:0:0:0:0 | Methods3Kt | methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | fooBarTopLevelMethodExt$default(java.lang.String,int,int,java.lang.Object) | public, static | Compiler generated |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:45 | fooBarMethodExt | fooBarMethodExt(java.lang.String,int) | final, public | |
|
||||
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:6:5:6:45 | fooBarMethodExt$default | fooBarMethodExt$default(foo.bar.Class3,java.lang.String,int,int,java.lang.Object) | public, static | Compiler generated |
|
||||
| methods4.kt:5:3:9:3 | InsideNestedTest | methods4.kt:7:5:7:34 | m | m(foo.bar.NestedTest.InsideNestedTest) | final, public | |
|
||||
| methods5.kt:0:0:0:0 | Methods5Kt | methods5.kt:3:1:11:1 | x | x() | final, public, static | |
|
||||
| methods5.kt:5:3:5:27 | | methods5.kt:5:3:5:27 | a | a(int) | final, public | |
|
||||
|
@ -74,6 +76,15 @@ constructors
|
|||
| methods5.kt:13:1:13:14 | C1 | methods5.kt:13:1:13:14 | C1 | C1() |
|
||||
| methods.kt:5:1:20:1 | Class | methods.kt:5:1:20:1 | Class | Class() |
|
||||
extensions
|
||||
| methods3.kt:3:1:3:42 | fooBarTopLevelMethodExt | file://:0:0:0:0 | int |
|
||||
| methods3.kt:6:5:6:46 | fooBarTopLevelMethodExt | file://:0:0:0:0 | int |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods5.kt:9:3:9:32 | f1 | file:///!unknown-binary-location/foo/bar/C1.class:0:0:0:0 | C1<T1> |
|
||||
extensionsMismatch
|
||||
extensionIndex
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt | 0 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | 1 | file:///modules/java.base/java/lang/String.class:0:0:0:0 | String |
|
||||
| methods5.kt:9:3:9:32 | f1 | 0 | file:///!unknown-binary-location/foo/bar/C1.class:0:0:0:0 | C1<T1> |
|
||||
|
|
|
@ -17,3 +17,19 @@ query predicate constructors(RefType declType, Constructor c, string signature)
|
|||
}
|
||||
|
||||
query predicate extensions(ExtensionMethod m, Type t) { m.getExtendedType() = t and m.fromSource() }
|
||||
|
||||
query predicate extensionsMismatch(Method src, Method def) {
|
||||
src.getKotlinParameterDefaultsProxy() = def and
|
||||
(
|
||||
src instanceof ExtensionMethod and not def instanceof ExtensionMethod
|
||||
or
|
||||
def instanceof ExtensionMethod and not src instanceof ExtensionMethod
|
||||
)
|
||||
}
|
||||
|
||||
query predicate extensionIndex(ExtensionMethod m, int i, Type t) {
|
||||
m.fromSource() and
|
||||
m.getExtensionReceiverParameterIndex() = i and
|
||||
m.getExtendedType() = t and
|
||||
m.getParameter(i).getType() = t
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package foo.bar
|
||||
|
||||
fun Int.fooBarTopLevelMethodExt(x: Int) {}
|
||||
fun String.fooBarTopLevelMethodExt(x: Int = 1) {}
|
||||
|
||||
class Class3 {
|
||||
fun Int.fooBarTopLevelMethodExt(x: Int) {}
|
||||
fun String.fooBarMethodExt(x: Int = 1) {}
|
||||
}
|
||||
|
|
|
@ -32,10 +32,19 @@
|
|||
| methods2.kt:4:1:5:1 | fooBarTopLevelMethod | methods2.kt:4:34:4:39 | y | 1 |
|
||||
| methods2.kt:8:5:9:5 | fooBarClassMethod | methods2.kt:8:27:8:32 | x | 0 |
|
||||
| methods2.kt:8:5:9:5 | fooBarClassMethod | methods2.kt:8:35:8:40 | y | 1 |
|
||||
| methods3.kt:3:1:3:42 | fooBarTopLevelMethodExt | methods3.kt:3:5:3:7 | <this> | 0 |
|
||||
| methods3.kt:3:1:3:42 | fooBarTopLevelMethodExt | methods3.kt:3:33:3:38 | x | 1 |
|
||||
| methods3.kt:6:5:6:46 | fooBarTopLevelMethodExt | methods3.kt:6:9:6:11 | <this> | 0 |
|
||||
| methods3.kt:6:5:6:46 | fooBarTopLevelMethodExt | methods3.kt:6:37:6:42 | x | 1 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | methods3.kt:3:5:3:10 | <this> | 0 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt | methods3.kt:3:36:3:45 | x | 1 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | methods3.kt:3:1:3:49 | p0 | 0 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | methods3.kt:3:1:3:49 | p1 | 1 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | methods3.kt:3:1:3:49 | p2 | 2 |
|
||||
| methods3.kt:3:1:3:49 | fooBarTopLevelMethodExt$default | methods3.kt:3:1:3:49 | p3 | 3 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt | methods3.kt:6:9:6:14 | <this> | 0 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt | methods3.kt:6:32:6:41 | x | 1 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | methods3.kt:6:5:6:45 | p0 | 0 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | methods3.kt:6:5:6:45 | p1 | 1 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | methods3.kt:6:5:6:45 | p2 | 2 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | methods3.kt:6:5:6:45 | p3 | 3 |
|
||||
| methods3.kt:6:5:6:45 | fooBarMethodExt$default | methods3.kt:6:5:6:45 | p4 | 4 |
|
||||
| methods4.kt:7:5:7:34 | m | methods4.kt:7:11:7:29 | x | 0 |
|
||||
| methods5.kt:5:3:5:27 | a | methods5.kt:5:13:5:18 | i | 0 |
|
||||
| methods5.kt:9:3:9:32 | f1 | methods5.kt:9:12:9:17 | <this> | 0 |
|
||||
|
|
|
@ -525,13 +525,13 @@ test.kt:
|
|||
# 21| 0: [MethodAccess] sink(...)
|
||||
# 21| -1: [TypeAccess] TestKt
|
||||
# 21| 0: [VarAccess] y
|
||||
# 19| 3: [Method] f$default
|
||||
# 19| 3: [ExtensionMethod] f$default
|
||||
# 19| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 19| 0: [Parameter] p0
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 1: [Parameter] p1
|
||||
# 19| 0: [TypeAccess] TestExtensionMember
|
||||
# 19| 1: [Parameter] p1
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 2: [Parameter] p2
|
||||
# 19| 0: [TypeAccess] String
|
||||
# 19| 3: [Parameter] p3
|
||||
|
@ -565,8 +565,8 @@ test.kt:
|
|||
# 19| 1: [StringLiteral] "hello world"
|
||||
# 19| 2: [ReturnStmt] return ...
|
||||
# 19| 0: [MethodAccess] f(...)
|
||||
# 19| -1: [VarAccess] p1
|
||||
# 19| 0: [VarAccess] p0
|
||||
# 19| -1: [VarAccess] p0
|
||||
# 19| 0: [ExtensionReceiverAccess] this
|
||||
# 19| 1: [VarAccess] p2
|
||||
# 19| 2: [VarAccess] p3
|
||||
# 19| 3: [VarAccess] p4
|
||||
|
@ -579,8 +579,8 @@ test.kt:
|
|||
# 25| 0: [ExprStmt] <Expr>;
|
||||
# 25| 0: [MethodAccess] f$default(...)
|
||||
# 25| -1: [TypeAccess] TestExtensionMember
|
||||
# 25| 0: [VarAccess] sunk
|
||||
# 25| 1: [ThisAccess] this
|
||||
# 25| 0: [ThisAccess] this
|
||||
# 25| 1: [VarAccess] sunk
|
||||
# 25| 2: [StringLiteral] "extension sunk"
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -589,8 +589,8 @@ test.kt:
|
|||
# 26| 1: [ExprStmt] <Expr>;
|
||||
# 26| 0: [MethodAccess] f$default(...)
|
||||
# 26| -1: [TypeAccess] TestExtensionMember
|
||||
# 26| 0: [VarAccess] sunk
|
||||
# 26| 1: [ThisAccess] this
|
||||
# 26| 0: [ThisAccess] this
|
||||
# 26| 1: [VarAccess] sunk
|
||||
# 26| 2: [StringLiteral] "extension sunk fp"
|
||||
# 26| 3: [StringLiteral] "extension sunk 2"
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -729,13 +729,13 @@ test.kt:
|
|||
# 57| 0: [MethodAccess] sink(...)
|
||||
# 57| -1: [TypeAccess] TestKt
|
||||
# 57| 0: [VarAccess] y
|
||||
# 56| 4: [Method] test$default
|
||||
# 56| 4: [ExtensionMethod] test$default
|
||||
# 56| 3: [TypeAccess] Unit
|
||||
#-----| 4: (Parameters)
|
||||
# 56| 0: [Parameter] p0
|
||||
# 56| 0: [TypeAccess] ExtendMe
|
||||
# 56| 1: [Parameter] p1
|
||||
# 56| 0: [TypeAccess] TestReceiverReferences
|
||||
# 56| 1: [Parameter] p1
|
||||
# 56| 0: [TypeAccess] ExtendMe
|
||||
# 56| 2: [Parameter] p2
|
||||
# 56| 0: [TypeAccess] String
|
||||
# 56| 3: [Parameter] p3
|
||||
|
@ -759,7 +759,7 @@ test.kt:
|
|||
# 56| 1: [MethodAccess] f(...)
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [MethodAccess] g(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [VarAccess] p2
|
||||
# 56| 1: [IfStmt] if (...)
|
||||
# 56| 0: [EQExpr] ... == ...
|
||||
|
@ -773,8 +773,8 @@ test.kt:
|
|||
# 56| 1: [StringLiteral] "hello world"
|
||||
# 56| 2: [ReturnStmt] return ...
|
||||
# 56| 0: [MethodAccess] test(...)
|
||||
# 56| -1: [VarAccess] p1
|
||||
# 56| 0: [VarAccess] p0
|
||||
# 56| -1: [VarAccess] p0
|
||||
# 56| 0: [ExtensionReceiverAccess] this
|
||||
# 56| 1: [VarAccess] p2
|
||||
# 56| 2: [VarAccess] p3
|
||||
# 56| 3: [VarAccess] p4
|
||||
|
@ -787,8 +787,8 @@ test.kt:
|
|||
# 61| 0: [ExprStmt] <Expr>;
|
||||
# 61| 0: [MethodAccess] test$default(...)
|
||||
# 61| -1: [TypeAccess] TestReceiverReferences
|
||||
# 61| 0: [VarAccess] t
|
||||
# 61| 1: [ThisAccess] this
|
||||
# 61| 0: [ThisAccess] this
|
||||
# 61| 1: [VarAccess] t
|
||||
# 61| 2: [StringLiteral] "receiver refs sunk"
|
||||
# 1| 3: [NullLiteral] null
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
@ -797,8 +797,8 @@ test.kt:
|
|||
# 62| 1: [ExprStmt] <Expr>;
|
||||
# 62| 0: [MethodAccess] test$default(...)
|
||||
# 62| -1: [TypeAccess] TestReceiverReferences
|
||||
# 62| 0: [VarAccess] t
|
||||
# 62| 1: [ThisAccess] this
|
||||
# 62| 0: [ThisAccess] this
|
||||
# 62| 1: [VarAccess] t
|
||||
# 62| 2: [StringLiteral] "receiver refs sunk fp"
|
||||
# 62| 3: [StringLiteral] "receiver refs sunk 2"
|
||||
# 1| 4: [NullLiteral] null
|
||||
|
|
|
@ -534,7 +534,7 @@ reflection.kt:
|
|||
# 150| 0: [AddExpr] ... + ...
|
||||
# 150| 0: [VarAccess] x
|
||||
# 150| 1: [VarAccess] y
|
||||
# 150| 20: [Method] extTakesOptionalParam$default
|
||||
# 150| 20: [ExtensionMethod] extTakesOptionalParam$default
|
||||
# 150| 3: [TypeAccess] int
|
||||
#-----| 4: (Parameters)
|
||||
# 150| 0: [Parameter] p0
|
||||
|
@ -561,7 +561,7 @@ reflection.kt:
|
|||
# 150| 1: [ReturnStmt] return ...
|
||||
# 150| 0: [MethodAccess] extTakesOptionalParam(...)
|
||||
# 150| -1: [TypeAccess] ReflectionKt
|
||||
# 150| 0: [VarAccess] p0
|
||||
# 150| 0: [ExtensionReceiverAccess] this
|
||||
# 150| 1: [VarAccess] p1
|
||||
# 150| 2: [VarAccess] p2
|
||||
# 152| 21: [Method] extensionAdaptedParams
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
utils/model-generator/CaptureNegativeSummaryModels.ql
|
|
@ -0,0 +1 @@
|
|||
utils/model-generator/CaptureNeutralModels.ql
|
|
@ -74,8 +74,8 @@ class Converter:
|
|||
summaries = self.getAddsTo("ExtractSummaries.ql", helpers.summaryModelPredicate)
|
||||
sources = self.getAddsTo("ExtractSources.ql", helpers.sourceModelPredicate)
|
||||
sinks = self.getAddsTo("ExtractSinks.ql", helpers.sinkModelPredicate)
|
||||
negativeSummaries = self.getAddsTo("ExtractNegativeSummaries.ql", helpers.negativeSummaryModelPredicate)
|
||||
return merge(sources, sinks, summaries, negativeSummaries)
|
||||
neutrals = self.getAddsTo("ExtractNeutrals.ql", helpers.neutralModelPredicate)
|
||||
return merge(sources, sinks, summaries, neutrals)
|
||||
|
||||
|
||||
def save(self, extensions):
|
||||
|
|
|
@ -30,7 +30,7 @@ class Generator:
|
|||
self.generateSinks = False
|
||||
self.generateSources = False
|
||||
self.generateSummaries = False
|
||||
self.generateNegativeSummaries = False
|
||||
self.generateNeutrals = False
|
||||
self.generateTypeBasedSummaries = False
|
||||
self.dryRun = False
|
||||
self.dirname = "model-generator"
|
||||
|
@ -49,7 +49,7 @@ Which models are generated is controlled by the flags:
|
|||
--with-sinks
|
||||
--with-sources
|
||||
--with-summaries
|
||||
--with-negative-summaries
|
||||
--with-neutrals
|
||||
--with-typebased-summaries (Experimental)
|
||||
If none of these flags are specified, all models are generated except for the type based models.
|
||||
|
||||
|
@ -102,9 +102,9 @@ Requirements: `codeql` should both appear on your path.
|
|||
sys.argv.remove("--with-summaries")
|
||||
generator.generateSummaries = True
|
||||
|
||||
if "--with-negative-summaries" in sys.argv:
|
||||
sys.argv.remove("--with-negative-summaries")
|
||||
generator.generateNegativeSummaries = True
|
||||
if "--with-neutrals" in sys.argv:
|
||||
sys.argv.remove("--with-neutrals")
|
||||
generator.generateNeutrals = True
|
||||
|
||||
if "--with-typebased-summaries" in sys.argv:
|
||||
sys.argv.remove("--with-typebased-summaries")
|
||||
|
@ -114,8 +114,8 @@ Requirements: `codeql` should both appear on your path.
|
|||
sys.argv.remove("--dry-run")
|
||||
generator.dryRun = True
|
||||
|
||||
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNegativeSummaries and not generator.generateTypeBasedSummaries:
|
||||
generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNegativeSummaries = True
|
||||
if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNeutrals and not generator.generateTypeBasedSummaries:
|
||||
generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNeutrals = True
|
||||
|
||||
if len(sys.argv) < 3 or len(sys.argv) > 4:
|
||||
generator.printHelp()
|
||||
|
@ -168,21 +168,15 @@ Requirements: `codeql` should both appear on your path.
|
|||
else:
|
||||
sourceAddsTo = ""
|
||||
|
||||
if self.generateNegativeSummaries:
|
||||
negativeSummaryAddsTo = self.getAddsTo("CaptureNegativeSummaryModels.ql", "extNegativeSummaryModel")
|
||||
if self.generateNeutrals:
|
||||
neutralAddsTo = self.getAddsTo("CaptureNeutralModels.ql", helpers.neutralModelPredicate)
|
||||
else:
|
||||
negativeSummaryAddsTo = ""
|
||||
neutralAddsTo = ""
|
||||
|
||||
return f"""
|
||||
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
|
||||
# Definitions of taint steps in the {self.friendlyname} framework.
|
||||
|
||||
return f"""# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
|
||||
# Definitions of models for the {self.friendlyname} framework.
|
||||
extensions:
|
||||
{sinkAddsTo}
|
||||
{sourceAddsTo}
|
||||
{summaryAddsTo}
|
||||
{negativeSummaryAddsTo}
|
||||
"""
|
||||
{sinkAddsTo}{sourceAddsTo}{summaryAddsTo}{neutralAddsTo}"""
|
||||
|
||||
def makeTypeBasedContent(self):
|
||||
if self.generateTypeBasedSummaries:
|
||||
|
@ -190,13 +184,10 @@ extensions:
|
|||
else:
|
||||
typeBasedSummaryAddsTo = ""
|
||||
|
||||
return f"""
|
||||
# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
|
||||
return f"""# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
|
||||
# Definitions of type based summaries in the {self.friendlyname} framework.
|
||||
|
||||
extensions:
|
||||
{typeBasedSummaryAddsTo}
|
||||
"""
|
||||
{typeBasedSummaryAddsTo}"""
|
||||
|
||||
def save(self, content, target):
|
||||
with open(target, "w") as targetYml:
|
||||
|
|
|
@ -7,7 +7,7 @@ import subprocess
|
|||
summaryModelPredicate = "extSummaryModel"
|
||||
sinkModelPredicate = "extSinkModel"
|
||||
sourceModelPredicate = "extSourceModel"
|
||||
negativeSummaryModelPredicate = "extNegativeSummaryModel"
|
||||
neutralModelPredicate = "extNeutralModel"
|
||||
addsToTemplate = """ - addsTo:
|
||||
pack: {0}
|
||||
extensible: {1}
|
||||
|
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,11 +92,11 @@ predicate summaryElement(
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Note. Negative flow summaries has not been implemented for Python.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
|
||||
* Note. Neutral models have not been implemented for Python.
|
||||
*/
|
||||
predicate negativeSummaryElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
|
||||
predicate neutralElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
|
||||
|
||||
/**
|
||||
* Gets the summary component for specification component `c`, if any.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Calls to `mail` and `inbound_mail` in `ActionMailbox` controllers are now considered sources of remote input.
|
|
@ -7,6 +7,7 @@ private import codeql.ruby.frameworks.ActionCable
|
|||
private import codeql.ruby.frameworks.ActionController
|
||||
private import codeql.ruby.frameworks.ActiveJob
|
||||
private import codeql.ruby.frameworks.ActionMailer
|
||||
private import codeql.ruby.frameworks.ActionMailbox
|
||||
private import codeql.ruby.frameworks.ActiveRecord
|
||||
private import codeql.ruby.frameworks.ActiveResource
|
||||
private import codeql.ruby.frameworks.ActiveStorage
|
||||
|
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,11 +63,11 @@ predicate summaryElement(
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Note. Negative flow summaries has not been implemented for ruby.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
|
||||
* Note. Neutral models have not been implemented for ruby.
|
||||
*/
|
||||
predicate negativeSummaryElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
|
||||
predicate neutralElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
|
||||
|
||||
bindingset[arg]
|
||||
private SummaryComponent interpretElementArg(string arg) {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* Models the `ActionMailbox` library, which is part of Rails.
|
||||
* Version: 7.0.4.
|
||||
*/
|
||||
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.Concepts
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
|
||||
/**
|
||||
* Models the `ActionMailbox` library, which is part of Rails.
|
||||
* Version: 7.0.4.
|
||||
*/
|
||||
module ActionMailbox {
|
||||
private DataFlow::ClassNode controller() {
|
||||
result = DataFlow::getConstant("ActionMailbox").getConstant("Base").getADescendentModule()
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `mail` on the return value of
|
||||
* `ActionMailbox::Base#inbound_email`, or a direct call to
|
||||
* `ActionMailbox::Base#mail`, which is equivalent. The returned object
|
||||
* contains data from the incoming email.
|
||||
*/
|
||||
class Mail extends DataFlow::CallNode {
|
||||
Mail() {
|
||||
this =
|
||||
[
|
||||
controller().getAnInstanceSelf().getAMethodCall("inbound_email").getAMethodCall("mail"),
|
||||
controller().getAnInstanceSelf().getAMethodCall("mail")
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method call on a `Mail::Message` object which may return data from a remote source.
|
||||
*/
|
||||
private class RemoteContent extends DataFlow::CallNode, RemoteFlowSource::Range {
|
||||
RemoteContent() {
|
||||
this =
|
||||
any(Mail m)
|
||||
.(DataFlow::LocalSourceNode)
|
||||
.getAMethodCall([
|
||||
"body", "to", "from", "raw_source", "subject", "from_address",
|
||||
"recipients_addresses", "cc_addresses", "bcc_addresses", "in_reply_to",
|
||||
"references", "reply_to", "raw_envelope", "to_s", "encoded", "header", "bcc", "cc",
|
||||
"text_part", "html_part"
|
||||
])
|
||||
}
|
||||
|
||||
override string getSourceType() { result = "ActionMailbox" }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
messageInstances
|
||||
| action_mailbox.rb:3:5:3:8 | call to mail |
|
||||
| action_mailbox.rb:4:5:4:8 | call to mail |
|
||||
| action_mailbox.rb:6:5:6:10 | call to mail |
|
||||
| action_mailbox.rb:10:5:10:8 | call to mail |
|
||||
| action_mailbox.rb:16:9:16:12 | call to mail |
|
||||
remoteFlowSources
|
||||
| action_mailbox.rb:3:5:3:13 | call to body |
|
||||
| action_mailbox.rb:4:5:4:11 | call to to |
|
||||
| action_mailbox.rb:6:5:6:13 | call to to |
|
||||
| action_mailbox.rb:10:5:10:18 | call to text_part |
|
||||
| action_mailbox.rb:16:9:16:23 | call to raw_source |
|
|
@ -0,0 +1,7 @@
|
|||
private import codeql.ruby.frameworks.ActionMailbox
|
||||
private import codeql.ruby.DataFlow
|
||||
private import codeql.ruby.dataflow.RemoteFlowSources
|
||||
|
||||
query predicate messageInstances(ActionMailbox::Mail c) { any() }
|
||||
|
||||
query predicate remoteFlowSources(RemoteFlowSource r) { any() }
|
|
@ -0,0 +1,24 @@
|
|||
class A < ActionMailbox::Base
|
||||
def process
|
||||
mail.body
|
||||
mail.to
|
||||
m = inbound_email
|
||||
m.mail.to
|
||||
end
|
||||
|
||||
def other_method
|
||||
mail.text_part
|
||||
end
|
||||
end
|
||||
|
||||
class B < A
|
||||
def process
|
||||
mail.raw_source
|
||||
end
|
||||
end
|
||||
|
||||
class C # not a mailbox class
|
||||
def process
|
||||
mail.subject
|
||||
end
|
||||
end
|
|
@ -246,14 +246,14 @@ module Public {
|
|||
predicate isAutoGenerated() { none() }
|
||||
}
|
||||
|
||||
/** A callable with a flow summary stating there is no flow via the callable. */
|
||||
class NegativeSummarizedCallable extends SummarizedCallableBase {
|
||||
NegativeSummarizedCallable() { negativeSummaryElement(this, _) }
|
||||
/** A callable where there is no flow via the callable. */
|
||||
class NeutralCallable extends SummarizedCallableBase {
|
||||
NeutralCallable() { neutralElement(this, _) }
|
||||
|
||||
/**
|
||||
* Holds if the negative summary is auto generated.
|
||||
* Holds if the neutral is auto generated.
|
||||
*/
|
||||
predicate isAutoGenerated() { negativeSummaryElement(this, true) }
|
||||
predicate isAutoGenerated() { neutralElement(this, true) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,9 +1161,9 @@ module Private {
|
|||
string toString() { result = super.toString() }
|
||||
}
|
||||
|
||||
/** A flow summary to include in the `negativeSummary/1` query predicate. */
|
||||
abstract class RelevantNegativeSummarizedCallable instanceof NegativeSummarizedCallable {
|
||||
/** Gets the string representation of this callable used by `summary/1`. */
|
||||
/** A model to include in the `neutral/1` query predicate. */
|
||||
abstract class RelevantNeutralCallable instanceof NeutralCallable {
|
||||
/** Gets the string representation of this callable used by `neutral/1`. */
|
||||
abstract string getCallableCsv();
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
@ -1180,13 +1180,13 @@ module Private {
|
|||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
private string renderProvenanceNegative(NegativeSummarizedCallable c) {
|
||||
private string renderProvenanceNeutral(NeutralCallable c) {
|
||||
if c.isAutoGenerated() then result = "generated" else result = "manual"
|
||||
}
|
||||
|
||||
/**
|
||||
* A query predicate for outputting flow summaries in semi-colon separated format in QL tests.
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance"",
|
||||
* The syntax is: "namespace;type;overrides;name;signature;ext;inputspec;outputspec;kind;provenance",
|
||||
* ext is hardcoded to empty.
|
||||
*/
|
||||
query predicate summary(string csv) {
|
||||
|
@ -1205,14 +1205,14 @@ module Private {
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* Holds if a neutral model `csv` exists (semi-colon separated format). Used for testing purposes.
|
||||
* The syntax is: "namespace;type;name;signature;provenance"",
|
||||
*/
|
||||
query predicate negativeSummary(string csv) {
|
||||
exists(RelevantNegativeSummarizedCallable c |
|
||||
query predicate neutral(string csv) {
|
||||
exists(RelevantNeutralCallable c |
|
||||
csv =
|
||||
c.getCallableCsv() // Callable information
|
||||
+ renderProvenanceNegative(c) // provenance
|
||||
+ renderProvenanceNeutral(c) // provenance
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,11 +71,11 @@ predicate summaryElement(
|
|||
}
|
||||
|
||||
/**
|
||||
* Holds if a negative flow summary exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the summary is autogenerated.
|
||||
* Note. Negative flow summaries has not been implemented for swift.
|
||||
* Holds if a neutral model exists for `c`, which means that there is no
|
||||
* flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
|
||||
* Note. Neutral models have not been implemented for swift.
|
||||
*/
|
||||
predicate negativeSummaryElement(AbstractFunctionDecl c, boolean generated) { none() }
|
||||
predicate neutralElement(AbstractFunctionDecl c, boolean generated) { none() }
|
||||
|
||||
/**
|
||||
* Holds if an external source specification exists for `e` with output specification
|
||||
|
|
Загрузка…
Ссылка в новой задаче