Merge branch 'main' into redsun82/swift-open-redirection

This commit is contained in:
Paolo Tranquilli 2022-12-12 08:46:23 +01:00 коммит произвёл GitHub
Родитель a93e361aca e0f1b38439
Коммит 250ac686a2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
84 изменённых файлов: 565 добавлений и 399 удалений

Просмотреть файл

@ -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