From e45a31744f31acf3dc27c2602ab23210c1b48bf5 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Sun, 9 Jul 2023 04:17:35 +0200
Subject: [PATCH 01/32] Initial commit
---
.../security/CommandInjectionExtensions.qll | 50 +++++++++++++++++++
.../swift/security/CommandInjectionQuery.qll | 27 ++++++++++
2 files changed, 77 insertions(+)
create mode 100644 swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
create mode 100644 swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
new file mode 100644
index 00000000000..a553ab08955
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
@@ -0,0 +1,50 @@
+/**
+ * Provides classes and predicates for reasoning about system
+ * commands built from user-controlled sources (that is, command injection
+ * vulnerabilities).
+ */
+
+import swift
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.dataflow.ExternalFlow
+
+/**
+ * A dataflow sink for command injection vulnerabilities.
+ */
+abstract class CommandInjectionSink extends DataFlow::Node { }
+
+/**
+ * A barrier for command injection vulnerabilities.
+ */
+abstract class CommandInjectionBarrier extends DataFlow::Node { }
+
+/**
+ * A unit class for adding additional flow steps.
+ */
+class CommandInjectionAdditionalFlowStep extends Unit {
+ /**
+ * Holds if the step from `node1` to `node2` should be considered a flow
+ * step for paths related to command injection vulnerabilities.
+ */
+ abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
+}
+
+/** An expression of type `Process`. */
+private class ProcessRef extends Expr {
+ ProcessRef() {
+ this.getType() instanceof ProcessType or
+ this.getType() = any(OptionalType t | t.getBaseType() instanceof ProcessType)
+ }
+}
+
+/** The type `Process`. */
+private class ProcessType extends NominalType {
+ ProcessType() { this.getFullName() = "Process" }
+}
+
+/**
+ * A sink defined in a CSV model.
+ */
+private class DefaultCommandInjectionSink extends CommandInjectionSink {
+ DefaultCommandInjectionSink() { sinkNode(this, "command-injection") }
+}
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
new file mode 100644
index 00000000000..520794a365e
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
@@ -0,0 +1,27 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about system
+ * commands built from user-controlled sources (that is, Command injection
+ * vulnerabilities).
+ */
+
+import swift
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.dataflow.TaintTracking
+import codeql.swift.dataflow.FlowSources
+import codeql.swift.security.CommandInjectionExtensions
+
+/**
+ * A taint configuration for tainted data that reaches a Command Injection sink.
+ */
+module CommandInjectionConfig implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
+
+ predicate isSink(DataFlow::Node node) { node instanceof CommandInjectionSink }
+
+ predicate isBarrier(DataFlow::Node barrier) { barrier instanceof CommandInjectionBarrier }
+}
+
+/**
+ * Detect taint flow of tainted data that reaches a Command Injection sink.
+ */
+module CommandInjectionFlow = TaintTracking::Global;
From cea3477ac204424b1ecdc05f14a8ec894c9c12d5 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Wed, 12 Jul 2023 02:13:07 +0200
Subject: [PATCH 02/32] Qhelp and examples
---
.../security/CommandInjectionExtensions.qll | 19 +++++++-
.../2023-07-12-command-injection.md | 4 ++
.../Security/CWE-078/CommandInjection.qhelp | 45 +++++++++++++++++++
.../Security/CWE-078/CommandInjection.ql | 21 +++++++++
.../CWE-078/CommandInjectionBad.swift | 5 +++
.../CWE-078/CommandInjectionGood.swift | 13 ++++++
6 files changed, 106 insertions(+), 1 deletion(-)
create mode 100644 swift/ql/src/change-notes/2023-07-12-command-injection.md
create mode 100644 swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
create mode 100644 swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
create mode 100644 swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift
create mode 100644 swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
index a553ab08955..5c34a2b9a85 100644
--- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
@@ -42,9 +42,26 @@ private class ProcessType extends NominalType {
ProcessType() { this.getFullName() = "Process" }
}
+/**
+ * A `DataFlow::Node` that is an expression stored with the Realm database
+ * library.
+ */
+private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node {
+ ProcessSink() {
+ // any write into a class derived from `Process` is a sink. For
+ // example in `Process.launchPath = sensitive` the post-update node corresponding
+ // with `Process.launchPath` is a sink.
+ exists(NominalType t, Expr e |
+ t.getABaseType*().getUnderlyingType().getName() = "Process" and
+ e.getFullyConverted() = this.asExpr() and
+ e.getFullyConverted().getType() = t
+ )
+ }
+}
+
/**
* A sink defined in a CSV model.
*/
private class DefaultCommandInjectionSink extends CommandInjectionSink {
- DefaultCommandInjectionSink() { sinkNode(this, "command-injection") }
+ DefaultCommandInjectionSink() { sinkNode(this, "command-line-injection") }
}
diff --git a/swift/ql/src/change-notes/2023-07-12-command-injection.md b/swift/ql/src/change-notes/2023-07-12-command-injection.md
new file mode 100644
index 00000000000..2befc7592b9
--- /dev/null
+++ b/swift/ql/src/change-notes/2023-07-12-command-injection.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added new query "Command injection" (`swift/command-line-injection`). The query finds places where user input is used to execute system commands without proper escaping.
\ No newline at end of file
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp b/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
new file mode 100644
index 00000000000..80ebda716e0
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
@@ -0,0 +1,45 @@
+
+
+
+
+
+Constructing a system command with unsanitized user input is dangerous,
+since a malicious user to execute code.
+
+
+
+
+
+If possible, use hard-coded string literals to specify the command to run. Instead of interpreting
+user input directly as command names, examine the input and then choose among hard-coded string
+literals.
+
+
+If this is not possible, then add sanitization code to verify that the user input is safe before
+using it.
+
+
+
+
+
+The following examples execute code from user input without
+sanitizing it first:
+
+
+
+If user input is used to construct a regular expression it should be checked
+first. This ensures that the user cannot insert characters that have special
+meanings.
+
+
+
+
+
+
+OWASP:
+Command Injection.
+
+
+
\ No newline at end of file
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
new file mode 100644
index 00000000000..c81b13af10f
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
@@ -0,0 +1,21 @@
+/**
+ * @name System command built from user-controlled sources
+ * @description Building a system command from user-controlled sources is vulnerable to insertion of malicious code by the user.
+ * @kind path-problem
+ * @problem.severity error
+ * @security-severity 9.8
+ * @precision high
+ * @id swift/command-line-injection
+ * @tags security
+ * external/cwe/cwe-078
+ */
+
+import swift
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.security.CommandInjectionQuery
+import CommandInjectionFlow::PathGraph
+
+from CommandInjectionFlow::PathNode sourceNode, CommandInjectionFlow::PathNode sinkNode
+where CommandInjectionFlow::flowPath(sourceNode, sinkNode)
+select sinkNode.getNode(), sourceNode, sinkNode, "This command depends on a $@.",
+ sourceNode.getNode(), "user-provided value"
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift b/swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift
new file mode 100644
index 00000000000..ffdaaf907ca
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift
@@ -0,0 +1,5 @@
+var task = Process()
+task.launchPath = "/bin/bash"
+task.arguments = ["-c", userControlledString] // BAD
+
+task.launch()
\ No newline at end of file
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift b/swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift
new file mode 100644
index 00000000000..3482718eeac
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift
@@ -0,0 +1,13 @@
+func validateCommand(_ command: String) -> String? {
+ let allowedCommands = ["ls -l", "pwd", "echo"]
+ if allowedCommands.contains(command) {
+ return command
+ }
+ return nil
+}
+
+var task = Process()
+task.launchPath = "/bin/bash"
+task.arguments = ["-c", validateCommand(userControlledString)] // GOOD
+
+task.launch()
\ No newline at end of file
From d7d9ffc449b6d0f76702c937ce734f1b8071a233 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Wed, 12 Jul 2023 16:44:17 +0200
Subject: [PATCH 03/32] Doc error
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
---
.../lib/codeql/swift/security/CommandInjectionExtensions.qll | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
index 5c34a2b9a85..bbcbe244daa 100644
--- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
@@ -43,8 +43,7 @@ private class ProcessType extends NominalType {
}
/**
- * A `DataFlow::Node` that is an expression stored with the Realm database
- * library.
+ * A `DataFlow::Node` that is written into a `Process` object.
*/
private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node {
ProcessSink() {
From c9fadd98f47fe8c5a050c6baed4fa53782b5a6b3 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Wed, 12 Jul 2023 16:48:27 +0200
Subject: [PATCH 04/32] Support `CommandInjectionAdditionalFlowStep` and fix
doc errors
---
.../lib/codeql/swift/security/CommandInjectionExtensions.qll | 2 +-
swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll | 4 ++++
swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp | 4 ++--
swift/ql/src/queries/Security/CWE-078/CommandInjection.ql | 1 +
4 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
index bbcbe244daa..fee86714cf2 100644
--- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
@@ -62,5 +62,5 @@ private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node
* A sink defined in a CSV model.
*/
private class DefaultCommandInjectionSink extends CommandInjectionSink {
- DefaultCommandInjectionSink() { sinkNode(this, "command-line-injection") }
+ DefaultCommandInjectionSink() { sinkNode(this, "command-injection") }
}
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
index 520794a365e..4b67932209d 100644
--- a/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll
@@ -19,6 +19,10 @@ module CommandInjectionConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node node) { node instanceof CommandInjectionSink }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof CommandInjectionBarrier }
+
+ predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ any(CommandInjectionAdditionalFlowStep s).step(nodeFrom, nodeTo)
+ }
}
/**
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp b/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
index 80ebda716e0..ab9562af12c 100644
--- a/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
@@ -6,7 +6,7 @@
Constructing a system command with unsanitized user input is dangerous,
-since a malicious user to execute code.
+since a malicious user may be able to craft input that executes arbitrary code.
@@ -29,7 +29,7 @@ sanitizing it first:
-If user input is used to construct a regular expression it should be checked
+If user input is used to construct a command it should be checked
first. This ensures that the user cannot insert characters that have special
meanings.
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
index c81b13af10f..148676e1ac3 100644
--- a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
@@ -8,6 +8,7 @@
* @id swift/command-line-injection
* @tags security
* external/cwe/cwe-078
+ * external/cwe/cwe-088
*/
import swift
From 378313332be8e3c8d473f89260bf27da665ba7ac Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Fri, 14 Jul 2023 20:55:24 +0200
Subject: [PATCH 05/32] Fix sink
---
.../security/CommandInjectionExtensions.qll | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
index fee86714cf2..26e8782a799 100644
--- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
+++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll
@@ -29,6 +29,25 @@ class CommandInjectionAdditionalFlowStep extends Unit {
abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
}
+private class ProcessSink2 extends CommandInjectionSink instanceof DataFlow::Node {
+ ProcessSink2() {
+ exists(AssignExpr assign, ProcessHost s |
+ assign.getDest() = s and
+ this.asExpr() = assign.getSource()
+ )
+ or
+ exists(AssignExpr assign, ProcessHost s, ArrayExpr a |
+ assign.getDest() = s and
+ a = assign.getSource() and
+ this.asExpr() = a.getAnElement()
+ )
+ }
+}
+
+private class ProcessHost extends MemberRefExpr {
+ ProcessHost() { this.getBase() instanceof ProcessRef }
+}
+
/** An expression of type `Process`. */
private class ProcessRef extends Expr {
ProcessRef() {
From bc4724b1fb374766e523c5bfdedd37cf104a6def Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 17 Jul 2023 09:40:41 +0100
Subject: [PATCH 06/32] Swift: Test the customurlschemes fields that inherit
taint.
---
.../dataflow/flowsources/FlowSourcesInline.ql | 25 ++++-
.../flowsources/customurlschemes.swift | 98 ++++++++++++++++---
2 files changed, 110 insertions(+), 13 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
index 71e6055b7d4..507f3582936 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
+++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
@@ -1,6 +1,16 @@
import swift
import TestUtilities.InlineExpectationsTest
import FlowConfig
+import codeql.swift.dataflow.TaintTracking
+import codeql.swift.dataflow.DataFlow
+
+module TaintReachConfiguration implements DataFlow::ConfigSig {
+ predicate isSource(DataFlow::Node src) { src instanceof FlowSource }
+
+ predicate isSink(DataFlow::Node sink) { any() }
+}
+
+module TaintReachFlow = TaintTracking::Global;
string describe(FlowSource source) {
source instanceof RemoteFlowSource and result = "remote"
@@ -9,7 +19,7 @@ string describe(FlowSource source) {
}
module FlowSourcesTest implements TestSig {
- string getARelevantTag() { result = "source" }
+ string getARelevantTag() { result = ["source", "tainted"] }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(FlowSource source |
@@ -20,6 +30,19 @@ module FlowSourcesTest implements TestSig {
value = describe(source)
)
}
+
+ predicate hasOptionalResult(Location location, string element, string tag, string value) {
+ // this is not really what the "flowsources" test is about, but sometimes it's helpful to
+ // confirm that taint reaches certain obvious points in the flow source test code.
+ exists(DataFlow::Node n |
+ TaintReachFlow::flowTo(n) and
+ location = n.getLocation() and
+ location.getFile().getBaseName() != "" and
+ element = n.toString() and
+ tag = "tainted" and
+ value = ""
+ )
+ }
}
import MakeTest
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
index 4a300dcd217..aeffb78c19c 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
+++ b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
@@ -26,12 +26,24 @@ protocol UIApplicationDelegate {
}
class UIScene {
- class ConnectionOptions {}
+ class ConnectionOptions {
+ var userActivities: Set { get { return Set() } }
+ var urlContexts: Set { get { return Set() } }
+ }
}
class UISceneSession {}
-class NSUserActivity {}
+class NSUserActivity: Hashable {
+ static func == (lhs: NSUserActivity, rhs: NSUserActivity) -> Bool {
+ return true;
+ }
+
+ func hash(into hasher: inout Hasher) {}
+
+ var webpageURL: URL? { get { return nil } set { } }
+ var referrerURL: URL? { get { return nil } set { } }
+}
class UIOpenURLContext: Hashable {
static func == (lhs: UIOpenURLContext, rhs: UIOpenURLContext) -> Bool {
@@ -39,6 +51,8 @@ class UIOpenURLContext: Hashable {
}
func hash(into hasher: inout Hasher) {}
+
+ var url: URL { get { return URL() } }
}
protocol UISceneDelegate {
@@ -64,28 +78,88 @@ class AppDelegate: UIApplicationDelegate {
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
- launchOptions?[.url] // $ source=remote
+ _ = launchOptions?[.url] // $ source=remote
return true
}
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]?) -> Bool {
- launchOptions?[.url] // $ source=remote
+ _ = launchOptions?[.url] // $ source=remote
return true
}
}
class SceneDelegate : UISceneDelegate {
- func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
- func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
- func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
- func scene(_: UIScene, openURLContexts: Set) {} // $ source=remote
+ func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
+ for userActivity in options.userActivities {
+ let x = userActivity.webpageURL
+ x // $ MISSING: tainted
+ let y = userActivity.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ for urlContext in options.urlContexts {
+ let z = urlContext.url
+ z // $ MISSING: tainted
+ }
+ }
+
+ func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
+ let x = `continue`.webpageURL
+ x // $ tainted
+ let y = `continue`.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
+ let x = didUpdate.webpageURL
+ x // $ tainted
+ let y = didUpdate.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
+ for openURLContext in openURLContexts {
+ let x = openURLContext.url
+ x // $ MISSING: tainted
+ }
+ }
}
class Extended {}
extension Extended : UISceneDelegate {
- func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {} // $ source=remote
- func scene(_: UIScene, continue: NSUserActivity) {} // $ source=remote
- func scene(_: UIScene, didUpdate: NSUserActivity) {} // $ source=remote
- func scene(_: UIScene, openURLContexts: Set) {} // $ source=remote
+ func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
+ for userActivity in options.userActivities {
+ let x = userActivity.webpageURL
+ x // $ MISSING: tainted
+ let y = userActivity.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ for urlContext in options.urlContexts {
+ let z = urlContext.url
+ z // $ MISSING: tainted
+ }
+ }
+
+ func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
+ let x = `continue`.webpageURL
+ x // $ tainted
+ let y = `continue`.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
+ let x = didUpdate.webpageURL
+ x // $ tainted
+ let y = didUpdate.referrerURL
+ y // $ MISSING: tainted
+ }
+
+ func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
+ for openURLContext in openURLContexts {
+ let x = openURLContext.url
+ x // $ MISSING: tainted
+ }
+ }
}
From eca2c21af50666ecd59e304e8d8e496869da6878 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Sat, 15 Jul 2023 21:54:21 +0100
Subject: [PATCH 07/32] Swift: Model referrerURL.
---
.../swift/frameworks/StandardLibrary/CustomUrlSchemes.qll | 2 +-
.../dataflow/flowsources/customurlschemes.swift | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/CustomUrlSchemes.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/CustomUrlSchemes.qll
index e217de4478d..3e2e8f76714 100644
--- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/CustomUrlSchemes.qll
+++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/CustomUrlSchemes.qll
@@ -81,7 +81,7 @@ private class UserActivityUrlInheritTaint extends TaintInheritingContent,
{
UserActivityUrlInheritTaint() {
this.getField().getEnclosingDecl().asNominalTypeDecl().getName() = "NSUserActivity" and
- this.getField().getName() = "webpageURL"
+ this.getField().getName() = ["webpageURL", "referrerURL"]
}
}
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
index aeffb78c19c..b26a411c2de 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
+++ b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
@@ -107,14 +107,14 @@ class SceneDelegate : UISceneDelegate {
let x = `continue`.webpageURL
x // $ tainted
let y = `continue`.referrerURL
- y // $ MISSING: tainted
+ y // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
x // $ tainted
let y = didUpdate.referrerURL
- y // $ MISSING: tainted
+ y // $ tainted
}
func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
@@ -146,14 +146,14 @@ extension Extended : UISceneDelegate {
let x = `continue`.webpageURL
x // $ tainted
let y = `continue`.referrerURL
- y // $ MISSING: tainted
+ y // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
x // $ tainted
let y = didUpdate.referrerURL
- y // $ MISSING: tainted
+ y // $ tainted
}
func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
From 70a9fe39748b29c800ecac5a9260ab9fc4f756b8 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 17 Jul 2023 15:31:49 +0100
Subject: [PATCH 08/32] Swift: Change note.
---
.../change-notes/2023-07-17-nsuseractivity-referrer-url.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 swift/ql/lib/change-notes/2023-07-17-nsuseractivity-referrer-url.md
diff --git a/swift/ql/lib/change-notes/2023-07-17-nsuseractivity-referrer-url.md b/swift/ql/lib/change-notes/2023-07-17-nsuseractivity-referrer-url.md
new file mode 100644
index 00000000000..03e90b39c05
--- /dev/null
+++ b/swift/ql/lib/change-notes/2023-07-17-nsuseractivity-referrer-url.md
@@ -0,0 +1,5 @@
+---
+category: minorAnalysis
+---
+
+* Added taint flow for `NSUserActivity.referrerURL`.
From 05cb429635ef8b50eaf0fd0a5f3260151d880c88 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 17 Jul 2023 15:59:18 +0100
Subject: [PATCH 09/32] Swift: Add CfgConsistency.expected.
---
.../dataflow/flowsources/CONSISTENCY/CfgConsistency.expected | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
new file mode 100644
index 00000000000..9a45a9ab720
--- /dev/null
+++ b/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
@@ -0,0 +1,3 @@
+deadEnd
+| customurlschemes.swift:92:59:92:76 | options |
+| customurlschemes.swift:131:59:131:76 | options |
From 00e0e5a61a9570b19ede598668ca6eb074ddedbf Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 19 Jul 2023 11:36:09 +0200
Subject: [PATCH 10/32] Java: Add taint step for InputStream wrappers
---
java/ql/lib/semmle/code/java/JDK.qll | 48 ++++++++++
.../code/java/dataflow/RangeAnalysis.qll | 2 +-
.../library-tests/dataflow/stream-read/A.java | 87 +++++++++++++++++++
.../dataflow/stream-read/test.expected | 2 +
.../dataflow/stream-read/test.ql | 2 +
5 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 java/ql/test/library-tests/dataflow/stream-read/A.java
create mode 100644 java/ql/test/library-tests/dataflow/stream-read/test.expected
create mode 100644 java/ql/test/library-tests/dataflow/stream-read/test.ql
diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll
index 156cbbc0f93..59c132e16c9 100644
--- a/java/ql/lib/semmle/code/java/JDK.qll
+++ b/java/ql/lib/semmle/code/java/JDK.qll
@@ -4,6 +4,7 @@
import Member
import semmle.code.java.security.ExternalProcess
+private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
// --- Standard types ---
@@ -177,6 +178,11 @@ class TypeObjectInputStream extends RefType {
TypeObjectInputStream() { this.hasQualifiedName("java.io", "ObjectInputStream") }
}
+/** The class `java.io.InputStream`. */
+class TypeInputStream extends RefType {
+ TypeInputStream() { this.hasQualifiedName("java.io", "InputStream") }
+}
+
/** The class `java.nio.file.Paths`. */
class TypePaths extends Class {
TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") }
@@ -197,6 +203,48 @@ class TypeFile extends Class {
TypeFile() { this.hasQualifiedName("java.io", "File") }
}
+/**
+ * A taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
+ * to a class instance expression of the type extending `InputStream`.
+ *
+ * This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
+ * normally only happen in anonymous classes.
+ */
+private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ exists(Method m, AnonymousClass wrapper |
+ m.hasName("read") and
+ m.getDeclaringType() = wrapper and
+ wrapper.getASourceSupertype+() instanceof TypeInputStream
+ |
+ n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
+ n2.asExpr() = wrapper.getClassInstanceExpr()
+ )
+ }
+}
+
+/**
+ * A taint step from an `InputStream` argument of the constructor of an `InputStream` subtype
+ * to the call of the constructor, only if the argument is assigned to a class field.
+ *
+ * This models how it's assumed that an `InputStream` wrapper is tainted by the wrapped stream,
+ * and is a workaround to low `fieldFlowBranchLimit`s in dataflow configurations.
+ */
+private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ exists(ClassInstanceExpr cc, Argument a, AssignExpr ae |
+ cc.getConstructedType().getASourceSupertype+() instanceof TypeInputStream and
+ cc.getAnArgument() = a and
+ cc.getCallee().getParameter(a.getParameterPos()).getAnAccess() = ae.getRhs() and
+ ae.getDest().(FieldWrite).getField().getType().(RefType).getASourceSupertype*() instanceof
+ TypeInputStream
+ |
+ n1.asExpr() = a and
+ n2.asExpr() = cc
+ )
+ }
+}
+
// --- Standard methods ---
/**
* DEPRECATED: Any constructor of class `java.lang.ProcessBuilder`.
diff --git a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
index c061f559251..53c0a83a536 100644
--- a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
@@ -757,7 +757,7 @@ private predicate baseBound(Expr e, int b, boolean upper) {
or
exists(Method read |
e.(MethodAccess).getMethod().overrides*(read) and
- read.getDeclaringType().hasQualifiedName("java.io", "InputStream") and
+ read.getDeclaringType() instanceof TypeInputStream and
read.hasName("read") and
read.getNumberOfParameters() = 0
|
diff --git a/java/ql/test/library-tests/dataflow/stream-read/A.java b/java/ql/test/library-tests/dataflow/stream-read/A.java
new file mode 100644
index 00000000000..a1b208a898a
--- /dev/null
+++ b/java/ql/test/library-tests/dataflow/stream-read/A.java
@@ -0,0 +1,87 @@
+import java.io.InputStream;
+import java.io.IOException;
+
+public class A {
+
+ private static InputStream source() {
+ return null;
+ }
+
+ private static void sink(Object s) {}
+
+ static class MyStream extends InputStream {
+ private InputStream wrapped;
+
+ MyStream(InputStream wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return wrapped.read(b);
+ }
+ }
+
+ public static void testSeveralWrappers() {
+ InputStream src = source();
+ InputStream wrapper1 = new MyStream(src);
+ sink(wrapper1); // $ hasTaintFlow
+ InputStream wrapper2 = new MyStream(wrapper1);
+ sink(wrapper2); // $ hasTaintFlow
+ InputStream wrapper3 = new MyStream(wrapper2);
+ sink(wrapper3); // $ hasTaintFlow
+
+ InputStream wrapper4 = new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return wrapper3.read(b);
+
+ }
+ };
+ sink(wrapper4); // $ hasTaintFlow
+ }
+
+ public static void testAnonymous() throws Exception {
+ InputStream wrapper = new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ InputStream in = source();
+ return in.read(b);
+ }
+ };
+ sink(wrapper); // $ hasTaintFlow
+ }
+
+ public static void testAnonymousVarCapture() throws Exception {
+ InputStream in = source();
+ InputStream wrapper = new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return in.read(b);
+
+ }
+ };
+ sink(wrapper); // $ hasTaintFlow
+ }
+
+}
diff --git a/java/ql/test/library-tests/dataflow/stream-read/test.expected b/java/ql/test/library-tests/dataflow/stream-read/test.expected
new file mode 100644
index 00000000000..48de9172b36
--- /dev/null
+++ b/java/ql/test/library-tests/dataflow/stream-read/test.expected
@@ -0,0 +1,2 @@
+failures
+testFailures
diff --git a/java/ql/test/library-tests/dataflow/stream-read/test.ql b/java/ql/test/library-tests/dataflow/stream-read/test.ql
new file mode 100644
index 00000000000..50e3f8d2f7d
--- /dev/null
+++ b/java/ql/test/library-tests/dataflow/stream-read/test.ql
@@ -0,0 +1,2 @@
+import TestUtilities.InlineFlowTest
+import DefaultFlowTest
From 5330ce12cc1be4080af977698dee4c00b9a491da Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 19 Jul 2023 11:36:57 +0200
Subject: [PATCH 11/32] Use new TypeInputStream
---
.../semmle/code/java/dataflow/internal/TaintTrackingUtil.qll | 4 ++--
java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll | 2 +-
.../code/java/frameworks/javaee/ejb/EJBRestrictions.qll | 2 +-
.../semmle/code/java/frameworks/spring/SpringController.qll | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll
index c992f92ee8a..6f8dbb1771b 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll
@@ -239,7 +239,7 @@ private class BulkData extends RefType {
this.(Array).getElementType().(PrimitiveType).hasName(["byte", "char"])
or
exists(RefType t | this.getASourceSupertype*() = t |
- t.hasQualifiedName("java.io", "InputStream") or
+ t instanceof TypeInputStream or
t.hasQualifiedName("java.nio", "ByteBuffer") or
t.hasQualifiedName("java.lang", "Readable") or
t.hasQualifiedName("java.io", "DataInput") or
@@ -259,7 +259,7 @@ private class BulkData extends RefType {
private predicate inputStreamWrapper(Constructor c, int argi) {
not c.fromSource() and
c.getParameterType(argi) instanceof BulkData and
- c.getDeclaringType().getASourceSupertype+().hasQualifiedName("java.io", "InputStream")
+ c.getDeclaringType().getASourceSupertype+() instanceof TypeInputStream
}
/** An object construction that preserves the data flow status of any of its arguments. */
diff --git a/java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll b/java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll
index c22f77725a1..64f26685b68 100644
--- a/java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll
+++ b/java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll
@@ -102,7 +102,7 @@ private module Dispatch {
or
t instanceof Interface and not t.fromSource()
or
- t.hasQualifiedName("java.io", "InputStream")
+ t instanceof TypeInputStream
or
t.hasQualifiedName("java.io", "Serializable")
or
diff --git a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll
index 8df603c5d6a..461a7dc8208 100644
--- a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll
@@ -317,7 +317,7 @@ class SystemSetInputStreamMethod extends Method {
SystemSetInputStreamMethod() {
this.hasName("setIn") and
this.getNumberOfParameters() = 1 and
- this.getParameter(0).getType().(RefType).hasQualifiedName("java.io", "InputStream") and
+ this.getParameter(0).getType() instanceof TypeInputStream and
this.getDeclaringType()
.getAnAncestor()
.getSourceDeclaration()
diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll
index d40d1608969..f2611d6e2d1 100644
--- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll
@@ -237,7 +237,7 @@ class SpringRequestMappingParameter extends Parameter {
private predicate isExplicitlyTaintedInput() {
// InputStream or Reader parameters allow access to the body of a request
- this.getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "InputStream") or
+ this.getType().(RefType).getAnAncestor() instanceof TypeInputStream or
this.getType().(RefType).getAnAncestor().hasQualifiedName("java.io", "Reader") or
// The SpringServletInputAnnotations allow access to the URI, request parameters, cookie values and the body of the request
this.getAnAnnotation() instanceof SpringServletInputAnnotation or
From 3a6665b0ed9af96ad504652dd8f506a50cf63228 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 19 Jul 2023 12:51:00 +0200
Subject: [PATCH 12/32] Add change note
---
.../lib/change-notes/2023-07-19-inputstream-wrapper-steps.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 java/ql/lib/change-notes/2023-07-19-inputstream-wrapper-steps.md
diff --git a/java/ql/lib/change-notes/2023-07-19-inputstream-wrapper-steps.md b/java/ql/lib/change-notes/2023-07-19-inputstream-wrapper-steps.md
new file mode 100644
index 00000000000..aaeacf93e34
--- /dev/null
+++ b/java/ql/lib/change-notes/2023-07-19-inputstream-wrapper-steps.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added more dataflow steps for `java.io.InputStream`s that wrap other `java.io.InputStream`s.
From 0156fcc381f37f7773bd576ddf4277398f45f59d Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 11:18:55 +0200
Subject: [PATCH 13/32] Apply suggestions from code review
Co-authored-by: Anders Schack-Mulligen
---
java/ql/lib/semmle/code/java/JDK.qll | 6 +++---
.../library-tests/dataflow/stream-read/A.java | 18 ++++++++++++++++++
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll
index 59c132e16c9..c0c388f9308 100644
--- a/java/ql/lib/semmle/code/java/JDK.qll
+++ b/java/ql/lib/semmle/code/java/JDK.qll
@@ -232,10 +232,10 @@ private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
*/
private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- exists(ClassInstanceExpr cc, Argument a, AssignExpr ae |
+ exists(ClassInstanceExpr cc, Argument a, AssignExpr ae, int pos |
cc.getConstructedType().getASourceSupertype+() instanceof TypeInputStream and
- cc.getAnArgument() = a and
- cc.getCallee().getParameter(a.getParameterPos()).getAnAccess() = ae.getRhs() and
+ cc.getArgument(pragma[only_bind_into](pos)) = a and
+ cc.getCallee().getParameter(pragma[only_bind_into](pos)).getAnAccess() = ae.getRhs() and
ae.getDest().(FieldWrite).getField().getType().(RefType).getASourceSupertype*() instanceof
TypeInputStream
|
diff --git a/java/ql/test/library-tests/dataflow/stream-read/A.java b/java/ql/test/library-tests/dataflow/stream-read/A.java
index a1b208a898a..e66b99400d2 100644
--- a/java/ql/test/library-tests/dataflow/stream-read/A.java
+++ b/java/ql/test/library-tests/dataflow/stream-read/A.java
@@ -84,4 +84,22 @@ public class A {
sink(wrapper); // $ hasTaintFlow
}
+ public static InputStream wrapStream(InputStream in) {
+ return new InputStream() {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return in.read(b);
+ }
+ };
+ }
+
+ public static void testWrapCall() {
+ sink(wrapStream(null)); // no flow
+ sink(wrapStream(source())); // $ hasTaintFlow
+ }
}
From 1de68457aebe91818669d27a56353d8024c88a17 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 11:18:17 +0200
Subject: [PATCH 14/32] Move steps to InputStream.qll
---
java/ql/lib/semmle/code/java/JDK.qll | 43 -----------------
.../semmle/code/java/dataflow/FlowSteps.qll | 2 +-
.../code/java/frameworks/InputStream.qll | 47 +++++++++++++++++++
3 files changed, 48 insertions(+), 44 deletions(-)
create mode 100644 java/ql/lib/semmle/code/java/frameworks/InputStream.qll
diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll
index c0c388f9308..6372b22c8f4 100644
--- a/java/ql/lib/semmle/code/java/JDK.qll
+++ b/java/ql/lib/semmle/code/java/JDK.qll
@@ -4,7 +4,6 @@
import Member
import semmle.code.java.security.ExternalProcess
-private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
// --- Standard types ---
@@ -203,48 +202,6 @@ class TypeFile extends Class {
TypeFile() { this.hasQualifiedName("java.io", "File") }
}
-/**
- * A taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
- * to a class instance expression of the type extending `InputStream`.
- *
- * This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
- * normally only happen in anonymous classes.
- */
-private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
- override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- exists(Method m, AnonymousClass wrapper |
- m.hasName("read") and
- m.getDeclaringType() = wrapper and
- wrapper.getASourceSupertype+() instanceof TypeInputStream
- |
- n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
- n2.asExpr() = wrapper.getClassInstanceExpr()
- )
- }
-}
-
-/**
- * A taint step from an `InputStream` argument of the constructor of an `InputStream` subtype
- * to the call of the constructor, only if the argument is assigned to a class field.
- *
- * This models how it's assumed that an `InputStream` wrapper is tainted by the wrapped stream,
- * and is a workaround to low `fieldFlowBranchLimit`s in dataflow configurations.
- */
-private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
- override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- exists(ClassInstanceExpr cc, Argument a, AssignExpr ae, int pos |
- cc.getConstructedType().getASourceSupertype+() instanceof TypeInputStream and
- cc.getArgument(pragma[only_bind_into](pos)) = a and
- cc.getCallee().getParameter(pragma[only_bind_into](pos)).getAnAccess() = ae.getRhs() and
- ae.getDest().(FieldWrite).getField().getType().(RefType).getASourceSupertype*() instanceof
- TypeInputStream
- |
- n1.asExpr() = a and
- n2.asExpr() = cc
- )
- }
-}
-
// --- Standard methods ---
/**
* DEPRECATED: Any constructor of class `java.lang.ProcessBuilder`.
diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll
index 1619965f0f0..fef69bec7fd 100644
--- a/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll
@@ -20,11 +20,11 @@ private module Frameworks {
private import semmle.code.java.frameworks.Guice
private import semmle.code.java.frameworks.IoJsonWebToken
private import semmle.code.java.frameworks.jackson.JacksonSerializability
+ private import semmle.code.java.frameworks.InputStream
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.ratpack.RatpackExec
private import semmle.code.java.frameworks.stapler.Stapler
- private import semmle.code.java.JDK
}
/**
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
new file mode 100644
index 00000000000..e0c524bd1a4
--- /dev/null
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -0,0 +1,47 @@
+/** Provides definitions related to `java.io.InputStream`. */
+
+import java
+private import semmle.code.java.dataflow.DataFlow
+private import semmle.code.java.dataflow.FlowSteps
+
+/**
+ * A taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
+ * to a class instance expression of the type extending `InputStream`.
+ *
+ * This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
+ * normally only happen in anonymous classes.
+ */
+private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ exists(Method m, AnonymousClass wrapper |
+ m.hasName("read") and
+ m.getDeclaringType() = wrapper and
+ wrapper.getASourceSupertype+() instanceof TypeInputStream
+ |
+ n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
+ n2.asExpr() = wrapper.getClassInstanceExpr()
+ )
+ }
+}
+
+/**
+ * A taint step from an `InputStream` argument of the constructor of an `InputStream` subtype
+ * to the call of the constructor, only if the argument is assigned to a class field.
+ *
+ * This models how it's assumed that an `InputStream` wrapper is tainted by the wrapped stream,
+ * and is a workaround to low `fieldFlowBranchLimit`s in dataflow configurations.
+ */
+private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ exists(ClassInstanceExpr cc, Argument a, AssignExpr ae, int pos |
+ cc.getConstructedType().getASourceSupertype+() instanceof TypeInputStream and
+ cc.getArgument(pragma[only_bind_into](pos)) = a and
+ cc.getCallee().getParameter(pragma[only_bind_into](pos)).getAnAccess() = ae.getRhs() and
+ ae.getDest().(FieldWrite).getField().getType().(RefType).getASourceSupertype*() instanceof
+ TypeInputStream
+ |
+ n1.asExpr() = a and
+ n2.asExpr() = cc
+ )
+ }
+}
From f054f738368b6819c66b41b716dde9ce586f23cb Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 12:00:33 +0200
Subject: [PATCH 15/32] Apply suggestions from code review
Co-authored-by: Anders Schack-Mulligen
---
java/ql/lib/semmle/code/java/frameworks/InputStream.qll | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
index e0c524bd1a4..2f40220855a 100644
--- a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -13,13 +13,17 @@ private import semmle.code.java.dataflow.FlowSteps
*/
private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- exists(Method m, AnonymousClass wrapper |
+ exists(Method m, NestedClass wrapper |
m.hasName("read") and
m.getDeclaringType() = wrapper and
wrapper.getASourceSupertype+() instanceof TypeInputStream
|
n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
- n2.asExpr() = wrapper.getClassInstanceExpr()
+ n2.asExpr()
+ .(ClassInstanceExpr)
+ .getConstructedType()
+ .getASourceSupertype*()
+ .getSourceDeclaration() = wrapper
)
}
}
From 226103b246784f739dae09e049844809fe88de41 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 12:01:26 +0200
Subject: [PATCH 16/32] Add local class test
---
.../library-tests/dataflow/stream-read/A.java | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/java/ql/test/library-tests/dataflow/stream-read/A.java b/java/ql/test/library-tests/dataflow/stream-read/A.java
index e66b99400d2..2ca284f483d 100644
--- a/java/ql/test/library-tests/dataflow/stream-read/A.java
+++ b/java/ql/test/library-tests/dataflow/stream-read/A.java
@@ -102,4 +102,21 @@ public class A {
sink(wrapStream(null)); // no flow
sink(wrapStream(source())); // $ hasTaintFlow
}
+
+ public static void testLocalClass() {
+ InputStream in = source();
+
+ class LocalInputStream extends InputStream {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return in.read(b);
+ }
+ }
+ sink(new LocalInputStream()); // $ hasTaintFlow
+ }
}
From cc5a404149ed29fe432ec59e9793f73bcf017515 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 13:51:21 +0200
Subject: [PATCH 17/32] Add more test cases
---
.../library-tests/dataflow/stream-read/A.java | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/java/ql/test/library-tests/dataflow/stream-read/A.java b/java/ql/test/library-tests/dataflow/stream-read/A.java
index 2ca284f483d..705977757a1 100644
--- a/java/ql/test/library-tests/dataflow/stream-read/A.java
+++ b/java/ql/test/library-tests/dataflow/stream-read/A.java
@@ -103,7 +103,24 @@ public class A {
sink(wrapStream(source())); // $ hasTaintFlow
}
- public static void testLocalClass() {
+ public static void testLocal() {
+
+ class LocalInputStream extends InputStream {
+ @Override
+ public int read() throws IOException {
+ return 0;
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ InputStream in = source();
+ return in.read(b);
+ }
+ }
+ sink(new LocalInputStream()); // $ hasTaintFlow
+ }
+
+ public static void testLocalVarCapture() {
InputStream in = source();
class LocalInputStream extends InputStream {
From 36ff54b48b30076d7cb624549f537d9de36c1a01 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 13:53:12 +0200
Subject: [PATCH 18/32] Convert jump step into local step
Note that this has FNs in the test cases where the source is used locally in the nested classes' methods
---
.../code/java/frameworks/InputStream.qll | 34 ++++++++++++++-----
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
index 2f40220855a..27d7da1b03a 100644
--- a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -3,27 +3,36 @@
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
+private import semmle.code.java.dataflow.SSA
+private import semmle.code.java.dataflow.TaintTracking
/**
- * A taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
+ * A local taint step from the definition of a captured variable, the capturer of which
+ * updates the `bytes[]` parameter in an override of the `InputStream.read` method,
* to a class instance expression of the type extending `InputStream`.
*
- * This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
- * normally only happen in anonymous classes.
+ * This models how a subtype of `InputStream` could be tainted by capturing tainted variables in
+ * the definition of its methods.
*/
-private class InputStreamWrapperAnonymousStep extends AdditionalTaintStep {
+private class InputStreamWrapperCapturedLocalStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- exists(Method m, NestedClass wrapper |
- m.hasName("read") and
+ exists(InputStreamRead m, NestedClass wrapper, SsaVariable captured, SsaImplicitInit capturer |
+ wrapper.getASourceSupertype+() instanceof TypeInputStream and
m.getDeclaringType() = wrapper and
- wrapper.getASourceSupertype+() instanceof TypeInputStream
- |
- n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
+ capturer.captures(captured) and
+ TaintTracking::localTaint(DataFlow::exprNode(capturer.getAFirstUse()),
+ any(DataFlow::PostUpdateNode pun |
+ pun.getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess()
+ )) and
n2.asExpr()
.(ClassInstanceExpr)
.getConstructedType()
.getASourceSupertype*()
.getSourceDeclaration() = wrapper
+ |
+ n1.asExpr() = captured.(SsaExplicitUpdate).getDefiningExpr().(VariableAssign).getSource()
+ or
+ captured.(SsaImplicitInit).isParameterDefinition(n1.asParameter())
)
}
}
@@ -49,3 +58,10 @@ private class InputStreamWrapperConstructorStep extends AdditionalTaintStep {
)
}
}
+
+private class InputStreamRead extends Method {
+ InputStreamRead() {
+ this.hasName("read") and
+ this.getDeclaringType().getASourceSupertype*() instanceof TypeInputStream
+ }
+}
From d3b3af8ae666fdc5d235dcc867a77f1fd6fa6328 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 13:54:09 +0200
Subject: [PATCH 19/32] Re-adds jump step
Note that this causes FP flow in the call context test cases
---
.../code/java/frameworks/InputStream.qll | 23 +++++++++++++++++++
.../library-tests/dataflow/stream-read/A.java | 2 +-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
index 27d7da1b03a..8f37ecc24ea 100644
--- a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -6,6 +6,29 @@ private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dataflow.TaintTracking
+/**
+ * A jump taint step from an update of the `bytes[]` parameter in an override of the `InputStream.read` method
+ * to a class instance expression of the type extending `InputStream`.
+ *
+ * This models how a subtype of `InputStream` could be tainted by the definition of its methods, which will
+ * normally only happen in nested classes.
+ */
+private class InputStreamWrapperCapturedJumpStep extends AdditionalTaintStep {
+ override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ exists(InputStreamRead m, NestedClass wrapper |
+ m.getDeclaringType() = wrapper and
+ wrapper.getASourceSupertype+() instanceof TypeInputStream
+ |
+ n1.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = m.getParameter(0).getAnAccess() and
+ n2.asExpr()
+ .(ClassInstanceExpr)
+ .getConstructedType()
+ .getASourceSupertype*()
+ .getSourceDeclaration() = wrapper
+ )
+ }
+}
+
/**
* A local taint step from the definition of a captured variable, the capturer of which
* updates the `bytes[]` parameter in an override of the `InputStream.read` method,
diff --git a/java/ql/test/library-tests/dataflow/stream-read/A.java b/java/ql/test/library-tests/dataflow/stream-read/A.java
index 705977757a1..779f95bcefa 100644
--- a/java/ql/test/library-tests/dataflow/stream-read/A.java
+++ b/java/ql/test/library-tests/dataflow/stream-read/A.java
@@ -99,7 +99,7 @@ public class A {
}
public static void testWrapCall() {
- sink(wrapStream(null)); // no flow
+ sink(wrapStream(null)); // $ SPURIOUS: hasTaintFlow
sink(wrapStream(source())); // $ hasTaintFlow
}
From 4e7438ac5c8319386ee26ed914d1f4ba0e52fee8 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 14:15:16 +0200
Subject: [PATCH 20/32] Make sure that InputStreamWrapperCapturedLocalStep is
indeed local
---
java/ql/lib/semmle/code/java/frameworks/InputStream.qll | 1 +
1 file changed, 1 insertion(+)
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
index 8f37ecc24ea..fe433831386 100644
--- a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -39,6 +39,7 @@ private class InputStreamWrapperCapturedJumpStep extends AdditionalTaintStep {
*/
private class InputStreamWrapperCapturedLocalStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
+ n1.getEnclosingCallable() = n2.getEnclosingCallable() and
exists(InputStreamRead m, NestedClass wrapper, SsaVariable captured, SsaImplicitInit capturer |
wrapper.getASourceSupertype+() instanceof TypeInputStream and
m.getDeclaringType() = wrapper and
From 6c0d47f122dfcad898c5b114b2836fbb01296297 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Fri, 21 Jul 2023 15:42:12 +0200
Subject: [PATCH 21/32] Update
java/ql/lib/semmle/code/java/frameworks/InputStream.qll
Co-authored-by: Anders Schack-Mulligen
---
java/ql/lib/semmle/code/java/frameworks/InputStream.qll | 1 -
1 file changed, 1 deletion(-)
diff --git a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
index fe433831386..8f37ecc24ea 100644
--- a/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/InputStream.qll
@@ -39,7 +39,6 @@ private class InputStreamWrapperCapturedJumpStep extends AdditionalTaintStep {
*/
private class InputStreamWrapperCapturedLocalStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
- n1.getEnclosingCallable() = n2.getEnclosingCallable() and
exists(InputStreamRead m, NestedClass wrapper, SsaVariable captured, SsaImplicitInit capturer |
wrapper.getASourceSupertype+() instanceof TypeInputStream and
m.getDeclaringType() = wrapper and
From 374c157afea86bf6d71f33b6b51837ff2aa27ea0 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 24 Jul 2023 19:17:51 +0100
Subject: [PATCH 22/32] Swift: Update the taint aspect of the flowsources test
to use sinks like the regular taint test.
---
.../dataflow/flowsources/FlowSourcesInline.ql | 28 ++++++++-------
.../flowsources/customurlschemes.swift | 34 ++++++++++---------
2 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
index 507f3582936..0aa66486d99 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
+++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
@@ -4,13 +4,18 @@ import FlowConfig
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.DataFlow
-module TaintReachConfiguration implements DataFlow::ConfigSig {
+module TestConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src instanceof FlowSource }
- predicate isSink(DataFlow::Node sink) { any() }
+ predicate isSink(DataFlow::Node sink) {
+ exists(CallExpr sinkCall |
+ sinkCall.getStaticTarget().getName().matches("sink%") and
+ sinkCall.getAnArgument().getExpr() = sink.asExpr()
+ )
+ }
}
-module TaintReachFlow = TaintTracking::Global;
+module TestFlow = TaintTracking::Global;
string describe(FlowSource source) {
source instanceof RemoteFlowSource and result = "remote"
@@ -29,16 +34,13 @@ module FlowSourcesTest implements TestSig {
tag = "source" and
value = describe(source)
)
- }
-
- predicate hasOptionalResult(Location location, string element, string tag, string value) {
- // this is not really what the "flowsources" test is about, but sometimes it's helpful to
- // confirm that taint reaches certain obvious points in the flow source test code.
- exists(DataFlow::Node n |
- TaintReachFlow::flowTo(n) and
- location = n.getLocation() and
- location.getFile().getBaseName() != "" and
- element = n.toString() and
+ or
+ exists(DataFlow::Node source, DataFlow::Node sink |
+ // this is not really what the "flowsources" test is about, but sometimes it's helpful to
+ // have sinks and confirm that taint reaches obvious points in the flow source test code.
+ TestFlow::flow(source, sink) and
+ location = sink.getLocation() and
+ element = sink.toString() and
tag = "tainted" and
value = ""
)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
index b26a411c2de..eb50c15824b 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
+++ b/swift/ql/test/library-tests/dataflow/flowsources/customurlschemes.swift
@@ -62,6 +62,8 @@ protocol UISceneDelegate {
func scene(_: UIScene, openURLContexts: Set)
}
+func sink(arg: Any) {}
+
// --- tests ---
class AppDelegate: UIApplicationDelegate {
@@ -92,35 +94,35 @@ class SceneDelegate : UISceneDelegate {
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
for userActivity in options.userActivities {
let x = userActivity.webpageURL
- x // $ MISSING: tainted
+ sink(arg: x) // $ MISSING: tainted
let y = userActivity.referrerURL
- y // $ MISSING: tainted
+ sink(arg: y) // $ MISSING: tainted
}
for urlContext in options.urlContexts {
let z = urlContext.url
- z // $ MISSING: tainted
+ sink(arg: z) // $ MISSING: tainted
}
}
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
let x = `continue`.webpageURL
- x // $ tainted
+ sink(arg: x) // $ tainted
let y = `continue`.referrerURL
- y // $ tainted
+ sink(arg: y) // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
- x // $ tainted
+ sink(arg: x) // $ tainted
let y = didUpdate.referrerURL
- y // $ tainted
+ sink(arg: y) // $ tainted
}
func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
for openURLContext in openURLContexts {
let x = openURLContext.url
- x // $ MISSING: tainted
+ sink(arg: x) // $ MISSING: tainted
}
}
}
@@ -131,35 +133,35 @@ extension Extended : UISceneDelegate {
func scene(_: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) { // $ source=remote
for userActivity in options.userActivities {
let x = userActivity.webpageURL
- x // $ MISSING: tainted
+ sink(arg: x) // $ MISSING: tainted
let y = userActivity.referrerURL
- y // $ MISSING: tainted
+ sink(arg: y) // $ MISSING: tainted
}
for urlContext in options.urlContexts {
let z = urlContext.url
- z // $ MISSING: tainted
+ sink(arg: z) // $ MISSING: tainted
}
}
func scene(_: UIScene, continue: NSUserActivity) { // $ source=remote
let x = `continue`.webpageURL
- x // $ tainted
+ sink(arg: x) // $ tainted
let y = `continue`.referrerURL
- y // $ tainted
+ sink(arg: y) // $ tainted
}
func scene(_: UIScene, didUpdate: NSUserActivity) { // $ source=remote
let x = didUpdate.webpageURL
- x // $ tainted
+ sink(arg: x) // $ tainted
let y = didUpdate.referrerURL
- y // $ tainted
+ sink(arg: y) // $ tainted
}
func scene(_: UIScene, openURLContexts: Set) { // $ source=remote
for openURLContext in openURLContexts {
let x = openURLContext.url
- x // $ MISSING: tainted
+ sink(arg: x) // $ MISSING: tainted
}
}
}
From 44d785fabf6433857d13c907b2db19f7ae697c41 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 27 Jul 2023 15:37:13 +0100
Subject: [PATCH 23/32] Swift: Make QL-for-QL happy.
---
.../library-tests/dataflow/flowsources/FlowSourcesInline.ql | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
index 0aa66486d99..25b3b327a70 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
+++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
@@ -35,10 +35,10 @@ module FlowSourcesTest implements TestSig {
value = describe(source)
)
or
- exists(DataFlow::Node source, DataFlow::Node sink |
+ exists(DataFlow::Node sink |
// this is not really what the "flowsources" test is about, but sometimes it's helpful to
// have sinks and confirm that taint reaches obvious points in the flow source test code.
- TestFlow::flow(source, sink) and
+ TestFlow::flow(_, sink) and
location = sink.getLocation() and
element = sink.toString() and
tag = "tainted" and
From 3eb1bac9df99f0ad2e90094a65d3a436b71a442b Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 27 Jul 2023 16:11:59 +0100
Subject: [PATCH 24/32] Swift: Update consistency test failure (line numbers).
---
.../dataflow/flowsources/CONSISTENCY/CfgConsistency.expected | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected b/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
index 9a45a9ab720..ac216c004f2 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
+++ b/swift/ql/test/library-tests/dataflow/flowsources/CONSISTENCY/CfgConsistency.expected
@@ -1,3 +1,3 @@
deadEnd
-| customurlschemes.swift:92:59:92:76 | options |
-| customurlschemes.swift:131:59:131:76 | options |
+| customurlschemes.swift:94:59:94:76 | options |
+| customurlschemes.swift:133:59:133:76 | options |
From d0a912fb025f75c0762fec39bd857b2f1dbb9752 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Thu, 27 Jul 2023 22:45:05 +0200
Subject: [PATCH 25/32] Update
swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
---
swift/ql/src/queries/Security/CWE-078/CommandInjection.ql | 1 +
1 file changed, 1 insertion(+)
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
index 148676e1ac3..eb501556b29 100644
--- a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
@@ -9,6 +9,7 @@
* @tags security
* external/cwe/cwe-078
* external/cwe/cwe-088
+ * external/cwe/cwe-088
*/
import swift
From d9800c7bb63a5246fc77a986e9273a91082deb22 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Thu, 27 Jul 2023 22:45:50 +0200
Subject: [PATCH 26/32] Update CommandInjection.ql
---
swift/ql/src/queries/Security/CWE-078/CommandInjection.ql | 1 -
1 file changed, 1 deletion(-)
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
index eb501556b29..148676e1ac3 100644
--- a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
+++ b/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
@@ -9,7 +9,6 @@
* @tags security
* external/cwe/cwe-078
* external/cwe/cwe-088
- * external/cwe/cwe-088
*/
import swift
From 2a49219127c4d0b289901ee8e062049ee560fc17 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Fri, 28 Jul 2023 00:15:33 +0200
Subject: [PATCH 27/32] Move query to experimental
---
.../Security/CWE-078/CommandInjection.qhelp | 0
.../Security/CWE-078/CommandInjection.ql | 0
.../Security/CWE-078/CommandInjectionBad.swift | 0
.../Security/CWE-078/CommandInjectionGood.swift | 0
4 files changed, 0 insertions(+), 0 deletions(-)
rename swift/ql/src/{queries => experimental}/Security/CWE-078/CommandInjection.qhelp (100%)
rename swift/ql/src/{queries => experimental}/Security/CWE-078/CommandInjection.ql (100%)
rename swift/ql/src/{queries => experimental}/Security/CWE-078/CommandInjectionBad.swift (100%)
rename swift/ql/src/{queries => experimental}/Security/CWE-078/CommandInjectionGood.swift (100%)
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp
similarity index 100%
rename from swift/ql/src/queries/Security/CWE-078/CommandInjection.qhelp
rename to swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjection.ql b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
similarity index 100%
rename from swift/ql/src/queries/Security/CWE-078/CommandInjection.ql
rename to swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift b/swift/ql/src/experimental/Security/CWE-078/CommandInjectionBad.swift
similarity index 100%
rename from swift/ql/src/queries/Security/CWE-078/CommandInjectionBad.swift
rename to swift/ql/src/experimental/Security/CWE-078/CommandInjectionBad.swift
diff --git a/swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift b/swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift
similarity index 100%
rename from swift/ql/src/queries/Security/CWE-078/CommandInjectionGood.swift
rename to swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift
From 90ac5b905b89aa92f8b14a97945a3ad0e902ed40 Mon Sep 17 00:00:00 2001
From: Maiky <76447395+maikypedia@users.noreply.github.com>
Date: Fri, 28 Jul 2023 00:21:02 +0200
Subject: [PATCH 28/32]
---
swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
index 148676e1ac3..98d68d0a101 100644
--- a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
+++ b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
@@ -19,4 +19,4 @@ import CommandInjectionFlow::PathGraph
from CommandInjectionFlow::PathNode sourceNode, CommandInjectionFlow::PathNode sinkNode
where CommandInjectionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This command depends on a $@.",
- sourceNode.getNode(), "user-provided value"
+ sourceNode.getNode(), "user-provided value"
\ No newline at end of file
From 0bc75ea9b79c26be985c4a162932b1ccb020cb88 Mon Sep 17 00:00:00 2001
From: Jeroen Ketema
Date: Sat, 29 Jul 2023 18:44:28 +0200
Subject: [PATCH 29/32] C++: Add forgotten parentheses in ternary IR test
Without the parentheses, the expressions are parsed as `a ? x : (y = val)`.
---
.../library-tests/ir/ir/PrintAST.expected | 125 ++++++------
cpp/ql/test/library-tests/ir/ir/ir.cpp | 6 +-
.../ir/ir/operand_locations.expected | 185 +++++++++---------
.../test/library-tests/ir/ir/raw_ir.expected | 158 +++++++--------
4 files changed, 242 insertions(+), 232 deletions(-)
diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
index 3f4a29c59c6..1e79068390e 100644
--- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
+++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected
@@ -15030,25 +15030,28 @@ ir.cpp:
# 1999| Value = [Literal] 5
# 1999| ValueCategory = prvalue
# 2000| getStmt(3): [ExprStmt] ExprStmt
-# 2000| getExpr(): [ConditionalExpr] ... ? ... : ...
+# 2000| getExpr(): [AssignExpr] ... = ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
-# 2000| getCondition(): [VariableAccess] a
-# 2000| Type = [BoolType] bool
-# 2000| ValueCategory = prvalue(load)
-# 2000| getThen(): [VariableAccess] x
+# 2000| getLValue(): [ConditionalExpr] ... ? ... : ...
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
-# 2000| getElse(): [AssignExpr] ... = ...
-# 2000| Type = [IntType] int
-# 2000| ValueCategory = lvalue
-# 2000| getLValue(): [VariableAccess] y
+# 2000| getCondition(): [VariableAccess] a
+# 2000| Type = [BoolType] bool
+# 2000| ValueCategory = prvalue(load)
+# 2000| getThen(): [VariableAccess] x
# 2000| Type = [IntType] int
# 2000| ValueCategory = lvalue
-# 2000| getRValue(): [Literal] 7
+# 2000| getElse(): [VariableAccess] y
# 2000| Type = [IntType] int
-# 2000| Value = [Literal] 7
-# 2000| ValueCategory = prvalue
+# 2000| ValueCategory = lvalue
+# 2000| getRValue(): [Literal] 7
+# 2000| Type = [IntType] int
+# 2000| Value = [Literal] 7
+# 2000| ValueCategory = prvalue
+# 2000| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
+# 2000| Type = [IntType] int
+# 2000| ValueCategory = lvalue
# 2001| getStmt(4): [ReturnStmt] return ...
# 2003| [CopyAssignmentOperator] TernaryPodObj& TernaryPodObj::operator=(TernaryPodObj const&)
# 2003| :
@@ -15151,31 +15154,34 @@ ir.cpp:
# 2010| getExpr(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
-# 2010| getLValue(): [VariableAccess] z
+# 2010| getLValue(): [AssignExpr] ... = ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = lvalue
-# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
-# 2010| Type = [Struct] TernaryPodObj
-# 2010| ValueCategory = prvalue
-# 2010| getCondition(): [VariableAccess] a
-# 2010| Type = [BoolType] bool
-# 2010| ValueCategory = prvalue(load)
-# 2010| getThen(): [VariableAccess] x
+# 2010| getLValue(): [VariableAccess] z
# 2010| Type = [Struct] TernaryPodObj
-# 2010| ValueCategory = prvalue(load)
-# 2010| getElse(): [AssignExpr] ... = ...
+# 2010| ValueCategory = lvalue
+# 2010| getRValue(): [ConditionalExpr] ... ? ... : ...
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue
-# 2010| getLValue(): [VariableAccess] y
-# 2010| Type = [Struct] TernaryPodObj
-# 2010| ValueCategory = lvalue
-# 2010| getRValue(): [Literal] 0
-# 2010| Type = [Struct] TernaryPodObj
-# 2010| Value = [Literal] 0
-# 2010| ValueCategory = prvalue
-# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2010| getCondition(): [VariableAccess] a
+# 2010| Type = [BoolType] bool
+# 2010| ValueCategory = prvalue(load)
+# 2010| getThen(): [VariableAccess] x
# 2010| Type = [Struct] TernaryPodObj
# 2010| ValueCategory = prvalue(load)
+# 2010| getElse(): [VariableAccess] y
+# 2010| Type = [Struct] TernaryPodObj
+# 2010| ValueCategory = prvalue(load)
+# 2010| getRValue(): [Literal] 0
+# 2010| Type = [Struct] TernaryPodObj
+# 2010| Value = [Literal] 0
+# 2010| ValueCategory = prvalue
+# 2010| getLValue().getFullyConverted(): [ParenthesisExpr] (...)
+# 2010| Type = [Struct] TernaryPodObj
+# 2010| ValueCategory = lvalue
+# 2010| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
+# 2010| Type = [Struct] TernaryPodObj
+# 2010| ValueCategory = prvalue(load)
# 2011| getStmt(4): [ReturnStmt] return ...
# 2013| [CopyAssignmentOperator] TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
# 2013| :
@@ -15339,38 +15345,38 @@ ir.cpp:
# 2021| getExpr(): [FunctionCall] call to operator=
# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
# 2021| ValueCategory = prvalue
-# 2021| getQualifier(): [VariableAccess] z
-# 2021| Type = [Struct] TernaryNonPodObj
-# 2021| ValueCategory = lvalue
-# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
-# 2021| Type = [Struct] TernaryNonPodObj
-# 2021| ValueCategory = lvalue
-# 2021| getCondition(): [VariableAccess] a
-# 2021| Type = [BoolType] bool
-# 2021| ValueCategory = prvalue(load)
-# 2021| getThen(): [VariableAccess] x
+# 2021| getQualifier(): [FunctionCall] call to operator=
+# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
+# 2021| ValueCategory = prvalue
+# 2021| getQualifier(): [VariableAccess] z
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
-# 2021| getElse(): [FunctionCall] call to operator=
-# 2021| Type = [LValueReferenceType] TernaryNonPodObj &
-# 2021| ValueCategory = prvalue
-# 2021| getQualifier(): [VariableAccess] y
+# 2021| getArgument(0): [ConditionalExpr] ... ? ... : ...
+# 2021| Type = [Struct] TernaryNonPodObj
+# 2021| ValueCategory = lvalue
+# 2021| getCondition(): [VariableAccess] a
+# 2021| Type = [BoolType] bool
+# 2021| ValueCategory = prvalue(load)
+# 2021| getThen(): [VariableAccess] x
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
-# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
-# 2021| Type = [VoidType] void
-# 2021| ValueCategory = prvalue
-# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
-# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
-# 2021| ValueCategory = prvalue
-# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
-# 2021| Conversion = [GlvalueConversion] glvalue conversion
-# 2021| Type = [SpecifiedType] const TernaryNonPodObj
-# 2021| ValueCategory = lvalue
-# 2021| getExpr(): [TemporaryObjectExpr] temporary object
-# 2021| Type = [Struct] TernaryNonPodObj
-# 2021| ValueCategory = lvalue
-# 2021| getElse().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
+# 2021| getElse(): [VariableAccess] y
+# 2021| Type = [Struct] TernaryNonPodObj
+# 2021| ValueCategory = lvalue
+# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
+# 2021| Type = [LValueReferenceType] const TernaryNonPodObj &
+# 2021| ValueCategory = prvalue
+# 2021| getExpr(): [CStyleCast] (const TernaryNonPodObj)...
+# 2021| Conversion = [GlvalueConversion] glvalue conversion
+# 2021| Type = [SpecifiedType] const TernaryNonPodObj
+# 2021| ValueCategory = lvalue
+# 2021| getArgument(0): [ConstructorCall] call to TernaryNonPodObj
+# 2021| Type = [VoidType] void
+# 2021| ValueCategory = prvalue
+# 2021| getQualifier().getFullyConverted(): [ParenthesisExpr] (...)
+# 2021| Type = [Struct] TernaryNonPodObj
+# 2021| ValueCategory = lvalue
+# 2021| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
# 2021| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
@@ -15380,6 +15386,9 @@ ir.cpp:
# 2021| Conversion = [GlvalueConversion] glvalue conversion
# 2021| Type = [SpecifiedType] const TernaryNonPodObj
# 2021| ValueCategory = lvalue
+# 2021| getExpr(): [TemporaryObjectExpr] temporary object
+# 2021| Type = [Struct] TernaryNonPodObj
+# 2021| ValueCategory = lvalue
# 2021| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 2021| Type = [Struct] TernaryNonPodObj
# 2021| ValueCategory = lvalue
diff --git a/cpp/ql/test/library-tests/ir/ir/ir.cpp b/cpp/ql/test/library-tests/ir/ir/ir.cpp
index 2f78d82a48e..4568026c7f4 100644
--- a/cpp/ql/test/library-tests/ir/ir/ir.cpp
+++ b/cpp/ql/test/library-tests/ir/ir/ir.cpp
@@ -1997,7 +1997,7 @@ void TernaryTestInt(bool a, int x, int y, int z) {
z = a ? x : y;
z = a ? x : 5;
z = a ? 3 : 5;
- a ? x : y = 7;
+ (a ? x : y) = 7;
}
struct TernaryPodObj {
@@ -2007,7 +2007,7 @@ void TernaryTestPodObj(bool a, TernaryPodObj x, TernaryPodObj y, TernaryPodObj z
z = a ? x : y;
z = a ? x : TernaryPodObj();
z = a ? TernaryPodObj() : TernaryPodObj();
- z = a ? x : y = TernaryPodObj();
+ (z = a ? x : y) = TernaryPodObj();
}
struct TernaryNonPodObj {
@@ -2018,7 +2018,7 @@ void TernaryTestNonPodObj(bool a, TernaryNonPodObj x, TernaryNonPodObj y, Ternar
z = a ? x : y;
z = a ? x : TernaryNonPodObj();
z = a ? TernaryNonPodObj() : TernaryNonPodObj();
- z = a ? x : y = TernaryNonPodObj();
+ (z = a ? x : y) = TernaryNonPodObj();
}
// semmle-extractor-options: -std=c++17 --clang
diff --git a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
index 8ef33ff286d..f06eceb9965 100644
--- a/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
+++ b/cpp/ql/test/library-tests/ir/ir/operand_locations.expected
@@ -9078,7 +9078,7 @@
| ir.cpp:1993:13:1993:32 | StoreValue | r1993_2 |
| ir.cpp:1996:6:1996:19 | ChiPartial | partial:m1996_3 |
| ir.cpp:1996:6:1996:19 | ChiTotal | total:m1996_2 |
-| ir.cpp:1996:6:1996:19 | SideEffect | m1996_3 |
+| ir.cpp:1996:6:1996:19 | SideEffect | ~m2000_9 |
| ir.cpp:1996:26:1996:26 | Address | &:r1996_5 |
| ir.cpp:1996:33:1996:33 | Address | &:r1996_7 |
| ir.cpp:1996:40:1996:40 | Address | &:r1996_9 |
@@ -9128,20 +9128,21 @@
| ir.cpp:1999:9:1999:17 | StoreValue | r1999_6 |
| ir.cpp:1999:13:1999:13 | StoreValue | r1999_9 |
| ir.cpp:1999:17:1999:17 | StoreValue | r1999_12 |
-| ir.cpp:2000:5:2000:5 | Address | &:r2000_1 |
-| ir.cpp:2000:5:2000:5 | Condition | r2000_2 |
-| ir.cpp:2000:5:2000:5 | Load | m1996_6 |
-| ir.cpp:2000:5:2000:17 | Address | &:r2000_5 |
-| ir.cpp:2000:5:2000:17 | Address | &:r2000_8 |
-| ir.cpp:2000:5:2000:17 | Address | &:r2000_14 |
-| ir.cpp:2000:5:2000:17 | Load | m2000_4 |
-| ir.cpp:2000:5:2000:17 | Phi | from 11:m2000_9 |
-| ir.cpp:2000:5:2000:17 | Phi | from 12:m2000_15 |
-| ir.cpp:2000:9:2000:9 | StoreValue | r2000_7 |
-| ir.cpp:2000:13:2000:13 | Address | &:r2000_11 |
-| ir.cpp:2000:13:2000:13 | Unary | r2000_11 |
-| ir.cpp:2000:13:2000:17 | StoreValue | r2000_13 |
-| ir.cpp:2000:17:2000:17 | StoreValue | r2000_10 |
+| ir.cpp:2000:5:2000:19 | ChiPartial | partial:m2000_8 |
+| ir.cpp:2000:5:2000:19 | ChiTotal | total:m1996_4 |
+| ir.cpp:2000:6:2000:6 | Address | &:r2000_2 |
+| ir.cpp:2000:6:2000:6 | Condition | r2000_3 |
+| ir.cpp:2000:6:2000:6 | Load | m1996_6 |
+| ir.cpp:2000:6:2000:14 | Address | &:r2000_6 |
+| ir.cpp:2000:6:2000:14 | Address | &:r2000_7 |
+| ir.cpp:2000:6:2000:14 | Address | &:r2000_11 |
+| ir.cpp:2000:6:2000:14 | Address | &:r2000_14 |
+| ir.cpp:2000:6:2000:14 | Load | m2000_5 |
+| ir.cpp:2000:6:2000:14 | Phi | from 11:m2000_12 |
+| ir.cpp:2000:6:2000:14 | Phi | from 12:m2000_15 |
+| ir.cpp:2000:10:2000:10 | StoreValue | r2000_10 |
+| ir.cpp:2000:14:2000:14 | StoreValue | r2000_13 |
+| ir.cpp:2000:19:2000:19 | StoreValue | r2000_1 |
| ir.cpp:2006:6:2006:22 | ChiPartial | partial:m2006_3 |
| ir.cpp:2006:6:2006:22 | ChiTotal | total:m2006_2 |
| ir.cpp:2006:6:2006:22 | SideEffect | m2006_3 |
@@ -9218,28 +9219,30 @@
| ir.cpp:2009:31:2009:45 | Load | m2009_20 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_19 |
| ir.cpp:2009:31:2009:45 | StoreValue | r2009_21 |
-| ir.cpp:2010:5:2010:5 | Address | &:r2010_7 |
-| ir.cpp:2010:9:2010:9 | Address | &:r2010_1 |
-| ir.cpp:2010:9:2010:9 | Condition | r2010_2 |
-| ir.cpp:2010:9:2010:9 | Load | m2006_6 |
-| ir.cpp:2010:9:2010:35 | Address | &:r2010_5 |
-| ir.cpp:2010:9:2010:35 | Address | &:r2010_11 |
-| ir.cpp:2010:9:2010:35 | Address | &:r2010_20 |
-| ir.cpp:2010:9:2010:35 | Load | m2010_4 |
-| ir.cpp:2010:9:2010:35 | Phi | from 11:m2010_12 |
-| ir.cpp:2010:9:2010:35 | Phi | from 12:m2010_21 |
-| ir.cpp:2010:9:2010:35 | StoreValue | r2010_6 |
-| ir.cpp:2010:13:2010:13 | Address | &:r2010_9 |
-| ir.cpp:2010:13:2010:13 | Load | m2006_8 |
-| ir.cpp:2010:13:2010:13 | StoreValue | r2010_10 |
-| ir.cpp:2010:17:2010:17 | Address | &:r2010_17 |
-| ir.cpp:2010:17:2010:35 | StoreValue | r2010_19 |
-| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
-| ir.cpp:2010:21:2010:35 | Address | &:r2010_13 |
-| ir.cpp:2010:21:2010:35 | Load | m2010_15 |
-| ir.cpp:2010:21:2010:35 | StoreValue | r2010_14 |
-| ir.cpp:2010:21:2010:35 | StoreValue | r2010_16 |
-| ir.cpp:2010:21:2010:35 | Unary | r2010_16 |
+| ir.cpp:2010:6:2010:6 | Address | &:r2010_11 |
+| ir.cpp:2010:6:2010:6 | Unary | r2010_11 |
+| ir.cpp:2010:6:2010:18 | Address | &:r2010_13 |
+| ir.cpp:2010:10:2010:10 | Address | &:r2010_5 |
+| ir.cpp:2010:10:2010:10 | Condition | r2010_6 |
+| ir.cpp:2010:10:2010:10 | Load | m2006_6 |
+| ir.cpp:2010:10:2010:18 | Address | &:r2010_9 |
+| ir.cpp:2010:10:2010:18 | Address | &:r2010_17 |
+| ir.cpp:2010:10:2010:18 | Address | &:r2010_21 |
+| ir.cpp:2010:10:2010:18 | Load | m2010_8 |
+| ir.cpp:2010:10:2010:18 | Phi | from 11:m2010_18 |
+| ir.cpp:2010:10:2010:18 | Phi | from 12:m2010_22 |
+| ir.cpp:2010:10:2010:18 | StoreValue | r2010_10 |
+| ir.cpp:2010:14:2010:14 | Address | &:r2010_15 |
+| ir.cpp:2010:14:2010:14 | Load | m2006_8 |
+| ir.cpp:2010:14:2010:14 | StoreValue | r2010_16 |
+| ir.cpp:2010:18:2010:18 | Address | &:r2010_19 |
+| ir.cpp:2010:18:2010:18 | Load | m2006_10 |
+| ir.cpp:2010:18:2010:18 | StoreValue | r2010_20 |
+| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
+| ir.cpp:2010:23:2010:37 | Address | &:r2010_1 |
+| ir.cpp:2010:23:2010:37 | Load | m2010_3 |
+| ir.cpp:2010:23:2010:37 | StoreValue | r2010_2 |
+| ir.cpp:2010:23:2010:37 | StoreValue | r2010_4 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
| ir.cpp:2013:8:2013:8 | Address | &:r2013_5 |
@@ -9280,7 +9283,7 @@
| ir.cpp:2014:13:2014:29 | SideEffect | m2014_8 |
| ir.cpp:2017:6:2017:25 | ChiPartial | partial:m2017_3 |
| ir.cpp:2017:6:2017:25 | ChiTotal | total:m2017_2 |
-| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_14 |
+| ir.cpp:2017:6:2017:25 | SideEffect | ~m2021_32 |
| ir.cpp:2017:32:2017:32 | Address | &:r2017_5 |
| ir.cpp:2017:52:2017:52 | Address | &:r2017_7 |
| ir.cpp:2017:72:2017:72 | Address | &:r2017_9 |
@@ -9423,60 +9426,58 @@
| ir.cpp:2020:34:2020:51 | Load | m2020_40 |
| ir.cpp:2020:34:2020:51 | SideEffect | ~m2019_16 |
| ir.cpp:2020:34:2020:51 | StoreValue | r2020_41 |
-| ir.cpp:2021:5:2021:5 | Address | &:r2021_1 |
-| ir.cpp:2021:5:2021:5 | Address | &:r2021_1 |
-| ir.cpp:2021:5:2021:5 | Arg(this) | this:r2021_1 |
-| ir.cpp:2021:5:2021:5 | ChiPartial | partial:m2021_17 |
-| ir.cpp:2021:5:2021:5 | ChiTotal | total:m2020_20 |
-| ir.cpp:2021:5:2021:5 | SideEffect | m2020_20 |
-| ir.cpp:2021:7:2021:7 | CallTarget | func:r2021_2 |
-| ir.cpp:2021:7:2021:7 | ChiPartial | partial:m2021_13 |
-| ir.cpp:2021:7:2021:7 | ChiTotal | total:m2021_6 |
-| ir.cpp:2021:7:2021:7 | SideEffect | ~m2021_6 |
-| ir.cpp:2021:7:2021:7 | Unary | r2021_12 |
-| ir.cpp:2021:9:2021:9 | Address | &:r2021_3 |
-| ir.cpp:2021:9:2021:9 | Condition | r2021_4 |
-| ir.cpp:2021:9:2021:9 | Load | m2017_6 |
-| ir.cpp:2021:9:2021:38 | Address | &:r2021_8 |
-| ir.cpp:2021:9:2021:38 | Address | &:r2021_11 |
-| ir.cpp:2021:9:2021:38 | Address | &:r2021_21 |
-| ir.cpp:2021:9:2021:38 | Address | &:r2021_43 |
-| ir.cpp:2021:9:2021:38 | Arg(0) | 0:r2021_11 |
-| ir.cpp:2021:9:2021:38 | Load | m2021_7 |
-| ir.cpp:2021:9:2021:38 | Phi | from 11:m2021_22 |
-| ir.cpp:2021:9:2021:38 | Phi | from 11:~m2020_16 |
-| ir.cpp:2021:9:2021:38 | Phi | from 12:m2021_44 |
-| ir.cpp:2021:9:2021:38 | Phi | from 12:~m2021_37 |
-| ir.cpp:2021:9:2021:38 | SideEffect | ~m2021_14 |
-| ir.cpp:2021:9:2021:38 | Unary | r2021_9 |
-| ir.cpp:2021:9:2021:38 | Unary | r2021_10 |
-| ir.cpp:2021:13:2021:13 | StoreValue | r2021_20 |
-| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
-| ir.cpp:2021:17:2021:17 | Address | &:r2021_23 |
-| ir.cpp:2021:17:2021:17 | Arg(this) | this:r2021_23 |
-| ir.cpp:2021:17:2021:17 | ChiPartial | partial:m2021_40 |
-| ir.cpp:2021:17:2021:17 | ChiTotal | total:m2017_10 |
-| ir.cpp:2021:17:2021:17 | SideEffect | m2017_10 |
-| ir.cpp:2021:19:2021:19 | CallTarget | func:r2021_24 |
-| ir.cpp:2021:19:2021:19 | ChiPartial | partial:m2021_36 |
-| ir.cpp:2021:19:2021:19 | ChiTotal | total:m2021_30 |
-| ir.cpp:2021:19:2021:19 | SideEffect | ~m2021_30 |
-| ir.cpp:2021:19:2021:19 | Unary | r2021_35 |
-| ir.cpp:2021:19:2021:39 | StoreValue | r2021_42 |
-| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
-| ir.cpp:2021:21:2021:38 | Address | &:r2021_25 |
-| ir.cpp:2021:21:2021:38 | Address | &:r2021_34 |
-| ir.cpp:2021:21:2021:38 | Arg(0) | 0:r2021_34 |
-| ir.cpp:2021:21:2021:38 | Arg(this) | this:r2021_25 |
-| ir.cpp:2021:21:2021:38 | CallTarget | func:r2021_27 |
-| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_29 |
-| ir.cpp:2021:21:2021:38 | ChiPartial | partial:m2021_31 |
-| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2020_16 |
-| ir.cpp:2021:21:2021:38 | ChiTotal | total:m2021_26 |
-| ir.cpp:2021:21:2021:38 | SideEffect | ~m2020_16 |
-| ir.cpp:2021:21:2021:38 | SideEffect | ~m2021_32 |
-| ir.cpp:2021:21:2021:38 | Unary | r2021_25 |
-| ir.cpp:2021:21:2021:38 | Unary | r2021_33 |
+| ir.cpp:2021:5:2021:19 | ChiPartial | partial:m2021_35 |
+| ir.cpp:2021:5:2021:19 | ChiTotal | total:m2021_17 |
+| ir.cpp:2021:5:2021:19 | SideEffect | m2021_17 |
+| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
+| ir.cpp:2021:6:2021:6 | Address | &:r2021_1 |
+| ir.cpp:2021:6:2021:6 | Arg(this) | this:r2021_1 |
+| ir.cpp:2021:6:2021:6 | ChiPartial | partial:m2021_16 |
+| ir.cpp:2021:6:2021:6 | ChiTotal | total:m2020_20 |
+| ir.cpp:2021:6:2021:6 | SideEffect | m2020_20 |
+| ir.cpp:2021:8:2021:8 | CallTarget | func:r2021_2 |
+| ir.cpp:2021:8:2021:8 | ChiPartial | partial:m2021_12 |
+| ir.cpp:2021:8:2021:8 | ChiTotal | total:m2020_16 |
+| ir.cpp:2021:8:2021:8 | SideEffect | ~m2020_16 |
+| ir.cpp:2021:8:2021:8 | Unary | r2021_11 |
+| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
+| ir.cpp:2021:8:2021:19 | Address | &:r2021_18 |
+| ir.cpp:2021:8:2021:19 | Arg(this) | this:r2021_18 |
+| ir.cpp:2021:10:2021:10 | Address | &:r2021_3 |
+| ir.cpp:2021:10:2021:10 | Condition | r2021_4 |
+| ir.cpp:2021:10:2021:10 | Load | m2017_6 |
+| ir.cpp:2021:10:2021:18 | Address | &:r2021_7 |
+| ir.cpp:2021:10:2021:18 | Address | &:r2021_10 |
+| ir.cpp:2021:10:2021:18 | Address | &:r2021_39 |
+| ir.cpp:2021:10:2021:18 | Address | &:r2021_42 |
+| ir.cpp:2021:10:2021:18 | Arg(0) | 0:r2021_10 |
+| ir.cpp:2021:10:2021:18 | Load | m2021_6 |
+| ir.cpp:2021:10:2021:18 | Phi | from 11:m2021_40 |
+| ir.cpp:2021:10:2021:18 | Phi | from 12:m2021_43 |
+| ir.cpp:2021:10:2021:18 | SideEffect | ~m2021_13 |
+| ir.cpp:2021:10:2021:18 | Unary | r2021_8 |
+| ir.cpp:2021:10:2021:18 | Unary | r2021_9 |
+| ir.cpp:2021:14:2021:14 | StoreValue | r2021_38 |
+| ir.cpp:2021:18:2021:18 | StoreValue | r2021_41 |
+| ir.cpp:2021:21:2021:21 | CallTarget | func:r2021_19 |
+| ir.cpp:2021:21:2021:21 | ChiPartial | partial:m2021_31 |
+| ir.cpp:2021:21:2021:21 | ChiTotal | total:m2021_25 |
+| ir.cpp:2021:21:2021:21 | SideEffect | ~m2021_25 |
+| ir.cpp:2021:21:2021:21 | Unary | r2021_30 |
+| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
+| ir.cpp:2021:23:2021:40 | Address | &:r2021_20 |
+| ir.cpp:2021:23:2021:40 | Address | &:r2021_29 |
+| ir.cpp:2021:23:2021:40 | Arg(0) | 0:r2021_29 |
+| ir.cpp:2021:23:2021:40 | Arg(this) | this:r2021_20 |
+| ir.cpp:2021:23:2021:40 | CallTarget | func:r2021_22 |
+| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_24 |
+| ir.cpp:2021:23:2021:40 | ChiPartial | partial:m2021_26 |
+| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_13 |
+| ir.cpp:2021:23:2021:40 | ChiTotal | total:m2021_21 |
+| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_13 |
+| ir.cpp:2021:23:2021:40 | SideEffect | ~m2021_27 |
+| ir.cpp:2021:23:2021:40 | Unary | r2021_20 |
+| ir.cpp:2021:23:2021:40 | Unary | r2021_28 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
index bd3d387c5bb..a6b527b95b6 100644
--- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
+++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected
@@ -10529,9 +10529,10 @@ ir.cpp:
# 1999| r1999_5(int) = Load[#temp1999:9] : &:r1999_4, ~m?
# 1999| r1999_6(glval) = VariableAddress[z] :
# 1999| mu1999_7(int) = Store[z] : &:r1999_6, r1999_5
-# 2000| r2000_1(glval) = VariableAddress[a] :
-# 2000| r2000_2(bool) = Load[a] : &:r2000_1, ~m?
-# 2000| v2000_3(void) = ConditionalBranch : r2000_2
+# 2000| r2000_1(int) = Constant[7] :
+# 2000| r2000_2(glval) = VariableAddress[a] :
+# 2000| r2000_3(bool) = Load[a] : &:r2000_2, ~m?
+# 2000| v2000_4(void) = ConditionalBranch : r2000_3
#-----| False -> Block 12
#-----| True -> Block 11
@@ -10548,26 +10549,24 @@ ir.cpp:
#-----| Goto -> Block 7
# 2000| Block 10
-# 2000| r2000_4(glval) = VariableAddress[#temp2000:5] :
-# 2000| r2000_5(glval) = Load[#temp2000:5] : &:r2000_4, ~m?
+# 2000| r2000_5(glval) = VariableAddress[#temp2000:6] :
+# 2000| r2000_6(glval) = Load[#temp2000:6] : &:r2000_5, ~m?
+# 2000| mu2000_7(int) = Store[?] : &:r2000_6, r2000_1
# 2001| v2001_1(void) = NoOp :
# 1996| v1996_12(void) = ReturnVoid :
# 1996| v1996_13(void) = AliasedUse : ~m?
# 1996| v1996_14(void) = ExitFunction :
# 2000| Block 11
-# 2000| r2000_6(glval) = VariableAddress[x] :
-# 2000| r2000_7(glval) = VariableAddress[#temp2000:5] :
-# 2000| mu2000_8(glval) = Store[#temp2000:5] : &:r2000_7, r2000_6
+# 2000| r2000_8(glval) = VariableAddress[x] :
+# 2000| r2000_9(glval) = VariableAddress[#temp2000:6] :
+# 2000| mu2000_10(glval) = Store[#temp2000:6] : &:r2000_9, r2000_8
#-----| Goto -> Block 10
# 2000| Block 12
-# 2000| r2000_9(int) = Constant[7] :
-# 2000| r2000_10(glval) = VariableAddress[y] :
-# 2000| mu2000_11(int) = Store[y] : &:r2000_10, r2000_9
-# 2000| r2000_12(glval) = CopyValue : r2000_10
-# 2000| r2000_13(glval) = VariableAddress[#temp2000:5] :
-# 2000| mu2000_14(glval) = Store[#temp2000:5] : &:r2000_13, r2000_12
+# 2000| r2000_11(glval) = VariableAddress[y] :
+# 2000| r2000_12(glval) = VariableAddress[#temp2000:6] :
+# 2000| mu2000_13(glval) = Store[#temp2000:6] : &:r2000_12, r2000_11
#-----| Goto -> Block 10
# 2006| void TernaryTestPodObj(bool, TernaryPodObj, TernaryPodObj, TernaryPodObj)
@@ -10649,15 +10648,19 @@ ir.cpp:
#-----| Goto -> Block 4
# 2009| Block 7
-# 2009| r2009_5(glval) = VariableAddress[#temp2009:9] :
-# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
-# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
-# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
-# 2009| r2009_9(glval) = VariableAddress[z] :
-# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
-# 2010| r2010_1(glval) = VariableAddress[a] :
-# 2010| r2010_2(bool) = Load[a] : &:r2010_1, ~m?
-# 2010| v2010_3(void) = ConditionalBranch : r2010_2
+# 2009| r2009_5(glval) = VariableAddress[#temp2009:9] :
+# 2009| r2009_6(TernaryPodObj) = Load[#temp2009:9] : &:r2009_5, ~m?
+# 2009| mu2009_7(TernaryPodObj) = Store[#temp2009:9] : &:r2009_1, r2009_6
+# 2009| r2009_8(TernaryPodObj) = Load[#temp2009:9] : &:r2009_1, ~m?
+# 2009| r2009_9(glval) = VariableAddress[z] :
+# 2009| mu2009_10(TernaryPodObj) = Store[z] : &:r2009_9, r2009_8
+# 2010| r2010_1(glval) = VariableAddress[#temp2010:23] :
+# 2010| r2010_2(TernaryPodObj) = Constant[0] :
+# 2010| mu2010_3(TernaryPodObj) = Store[#temp2010:23] : &:r2010_1, r2010_2
+# 2010| r2010_4(TernaryPodObj) = Load[#temp2010:23] : &:r2010_1, ~m?
+# 2010| r2010_5(glval) = VariableAddress[a] :
+# 2010| r2010_6(bool) = Load[a] : &:r2010_5, ~m?
+# 2010| v2010_7(void) = ConditionalBranch : r2010_6
#-----| False -> Block 12
#-----| True -> Block 11
@@ -10680,32 +10683,29 @@ ir.cpp:
#-----| Goto -> Block 7
# 2010| Block 10
-# 2010| r2010_4(glval) = VariableAddress[#temp2010:9] :
-# 2010| r2010_5(TernaryPodObj) = Load[#temp2010:9] : &:r2010_4, ~m?
-# 2010| r2010_6(glval) = VariableAddress[z] :
-# 2010| mu2010_7(TernaryPodObj) = Store[z] : &:r2010_6, r2010_5
-# 2011| v2011_1(void) = NoOp :
-# 2006| v2006_12(void) = ReturnVoid :
-# 2006| v2006_13(void) = AliasedUse : ~m?
-# 2006| v2006_14(void) = ExitFunction :
+# 2010| r2010_8(glval) = VariableAddress[#temp2010:10] :
+# 2010| r2010_9(TernaryPodObj) = Load[#temp2010:10] : &:r2010_8, ~m?
+# 2010| r2010_10(glval) = VariableAddress[z] :
+# 2010| mu2010_11(TernaryPodObj) = Store[z] : &:r2010_10, r2010_9
+# 2010| r2010_12(glval) = CopyValue : r2010_10
+# 2010| mu2010_13(TernaryPodObj) = Store[?] : &:r2010_12, r2010_4
+# 2011| v2011_1(void) = NoOp :
+# 2006| v2006_12(void) = ReturnVoid :
+# 2006| v2006_13(void) = AliasedUse : ~m?
+# 2006| v2006_14(void) = ExitFunction :
# 2010| Block 11
-# 2010| r2010_8(glval) = VariableAddress[x] :
-# 2010| r2010_9(TernaryPodObj) = Load[x] : &:r2010_8, ~m?
-# 2010| r2010_10(glval) = VariableAddress[#temp2010:9] :
-# 2010| mu2010_11(TernaryPodObj) = Store[#temp2010:9] : &:r2010_10, r2010_9
+# 2010| r2010_14(glval) = VariableAddress[x] :
+# 2010| r2010_15(TernaryPodObj) = Load[x] : &:r2010_14, ~m?
+# 2010| r2010_16(glval) = VariableAddress[#temp2010:10] :
+# 2010| mu2010_17(TernaryPodObj) = Store[#temp2010:10] : &:r2010_16, r2010_15
#-----| Goto -> Block 10
# 2010| Block 12
-# 2010| r2010_12(glval) = VariableAddress[#temp2010:21] :
-# 2010| r2010_13(TernaryPodObj) = Constant[0] :
-# 2010| mu2010_14(TernaryPodObj) = Store[#temp2010:21] : &:r2010_12, r2010_13
-# 2010| r2010_15(TernaryPodObj) = Load[#temp2010:21] : &:r2010_12, ~m?
-# 2010| r2010_16(glval) = VariableAddress[y] :
-# 2010| mu2010_17(TernaryPodObj) = Store[y] : &:r2010_16, r2010_15
-# 2010| r2010_18(TernaryPodObj) = CopyValue : r2010_15
-# 2010| r2010_19(glval) = VariableAddress[#temp2010:9] :
-# 2010| mu2010_20(TernaryPodObj) = Store[#temp2010:9] : &:r2010_19, r2010_18
+# 2010| r2010_18(glval) = VariableAddress[y] :
+# 2010| r2010_19(TernaryPodObj) = Load[y] : &:r2010_18, ~m?
+# 2010| r2010_20(glval) = VariableAddress[#temp2010:10] :
+# 2010| mu2010_21(TernaryPodObj) = Store[#temp2010:10] : &:r2010_20, r2010_19
#-----| Goto -> Block 10
# 2013| TernaryNonPodObj& TernaryNonPodObj::operator=(TernaryNonPodObj const&)
@@ -10931,46 +10931,46 @@ ir.cpp:
#-----| Goto -> Block 7
# 2021| Block 10
-# 2021| r2021_6(glval) = VariableAddress[#temp2021:9] :
-# 2021| r2021_7(glval) = Load[#temp2021:9] : &:r2021_6, ~m?
-# 2021| r2021_8(glval) = Convert : r2021_7
-# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
-# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
-# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
-# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
-# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
-# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
-# 2021| r2021_15(glval) = CopyValue : r2021_10
-# 2022| v2022_1(void) = NoOp :
-# 2017| v2017_12(void) = ReturnVoid :
-# 2017| v2017_13(void) = AliasedUse : ~m?
-# 2017| v2017_14(void) = ExitFunction :
+# 2021| r2021_6(glval) = VariableAddress[#temp2021:10] :
+# 2021| r2021_7(glval) = Load[#temp2021:10] : &:r2021_6, ~m?
+# 2021| r2021_8(glval) = Convert : r2021_7
+# 2021| r2021_9(TernaryNonPodObj &) = CopyValue : r2021_8
+# 2021| r2021_10(TernaryNonPodObj &) = Call[operator=] : func:r2021_2, this:r2021_1, 0:r2021_9
+# 2021| mu2021_11(unknown) = ^CallSideEffect : ~m?
+# 2021| v2021_12(void) = ^IndirectReadSideEffect[-1] : &:r2021_1, ~m?
+# 2021| v2021_13(void) = ^BufferReadSideEffect[0] : &:r2021_9, ~m?
+# 2021| mu2021_14(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_1
+# 2021| r2021_15(glval) = CopyValue : r2021_10
+# 2021| r2021_16(glval) = FunctionAddress[operator=] :
+# 2021| r2021_17(glval) = VariableAddress[#temp2021:23] :
+# 2021| mu2021_18(TernaryNonPodObj) = Uninitialized[#temp2021:23] : &:r2021_17
+# 2021| r2021_19(glval) = FunctionAddress[TernaryNonPodObj] :
+# 2021| v2021_20(void) = Call[TernaryNonPodObj] : func:r2021_19, this:r2021_17
+# 2021| mu2021_21(unknown) = ^CallSideEffect : ~m?
+# 2021| mu2021_22(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_17
+# 2021| r2021_23(glval) = Convert : r2021_17
+# 2021| r2021_24(TernaryNonPodObj &) = CopyValue : r2021_23
+# 2021| r2021_25(TernaryNonPodObj &) = Call[operator=] : func:r2021_16, this:r2021_15, 0:r2021_24
+# 2021| mu2021_26(unknown) = ^CallSideEffect : ~m?
+# 2021| v2021_27(void) = ^IndirectReadSideEffect[-1] : &:r2021_15, ~m?
+# 2021| v2021_28(void) = ^BufferReadSideEffect[0] : &:r2021_24, ~m?
+# 2021| mu2021_29(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_15
+# 2021| r2021_30(glval) = CopyValue : r2021_25
+# 2022| v2022_1(void) = NoOp :
+# 2017| v2017_12(void) = ReturnVoid :
+# 2017| v2017_13(void) = AliasedUse : ~m?
+# 2017| v2017_14(void) = ExitFunction :
# 2021| Block 11
-# 2021| r2021_16(glval) = VariableAddress[x] :
-# 2021| r2021_17(glval) = VariableAddress[#temp2021:9] :
-# 2021| mu2021_18(glval) = Store[#temp2021:9] : &:r2021_17, r2021_16
+# 2021| r2021_31(glval) = VariableAddress[x] :
+# 2021| r2021_32(glval) = VariableAddress[#temp2021:10] :
+# 2021| mu2021_33(glval) = Store[#temp2021:10] : &:r2021_32, r2021_31
#-----| Goto -> Block 10
# 2021| Block 12
-# 2021| r2021_19(glval) = VariableAddress[y] :
-# 2021| r2021_20(glval) = FunctionAddress[operator=] :
-# 2021| r2021_21(glval) = VariableAddress[#temp2021:21] :
-# 2021| mu2021_22(TernaryNonPodObj) = Uninitialized[#temp2021:21] : &:r2021_21
-# 2021| r2021_23(glval) = FunctionAddress[TernaryNonPodObj] :
-# 2021| v2021_24(void) = Call[TernaryNonPodObj] : func:r2021_23, this:r2021_21
-# 2021| mu2021_25(unknown) = ^CallSideEffect : ~m?
-# 2021| mu2021_26(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_21
-# 2021| r2021_27(glval) = Convert : r2021_21
-# 2021| r2021_28(TernaryNonPodObj &) = CopyValue : r2021_27
-# 2021| r2021_29(TernaryNonPodObj &) = Call[operator=] : func:r2021_20, this:r2021_19, 0:r2021_28
-# 2021| mu2021_30(unknown) = ^CallSideEffect : ~m?
-# 2021| v2021_31(void) = ^IndirectReadSideEffect[-1] : &:r2021_19, ~m?
-# 2021| v2021_32(void) = ^BufferReadSideEffect[0] : &:r2021_28, ~m?
-# 2021| mu2021_33(TernaryNonPodObj) = ^IndirectMayWriteSideEffect[-1] : &:r2021_19
-# 2021| r2021_34(glval) = CopyValue : r2021_29
-# 2021| r2021_35(glval) = VariableAddress[#temp2021:9] :
-# 2021| mu2021_36(glval) = Store[#temp2021:9] : &:r2021_35, r2021_34
+# 2021| r2021_34(glval) = VariableAddress[y] :
+# 2021| r2021_35(glval) = VariableAddress[#temp2021:10] :
+# 2021| mu2021_36(glval) = Store[#temp2021:10] : &:r2021_35, r2021_34
#-----| Goto -> Block 10
perf-regression.cpp:
From 3bd4d34a4783e08c25bc01e2d8ae003b9817eb78 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 31 Jul 2023 09:48:03 +0200
Subject: [PATCH 30/32] Java: Remove superfluous generated models
---
java/ql/lib/ext/generated/struts2.model.yml | 23 ---------------------
1 file changed, 23 deletions(-)
diff --git a/java/ql/lib/ext/generated/struts2.model.yml b/java/ql/lib/ext/generated/struts2.model.yml
index f157c44806e..74e1101a960 100644
--- a/java/ql/lib/ext/generated/struts2.model.yml
+++ b/java/ql/lib/ext/generated/struts2.model.yml
@@ -4849,15 +4849,6 @@ extensions:
- ["org.apache.struts2", "StrutsException", true, "StrutsException", "(Throwable,Object)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- ["org.apache.struts2", "StrutsException", true, "StrutsException", "(Throwable,Object)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"]
- ["org.apache.struts2", "StrutsException", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "Order", "(String,String,int)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "Order", "(String,String,int)", "", "Argument[1]", "Argument[this]", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "getClientName", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "getId", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "setClientName", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "setId", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- - ["org.demo.rest.example", "Order", true, "toString", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", true, "create", "()", "", "Argument[this]", "ReturnValue", "taint", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", true, "setId", "(String)", "", "Argument[0]", "Argument[this]", "taint", "df-generated"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
@@ -6886,19 +6877,5 @@ extensions:
- ["org.apache.struts2", "ServletActionContext", "setResponse", "(HttpServletResponse)", "summary", "df-generated"]
- ["org.apache.struts2", "ServletActionContext", "setServletContext", "(ServletContext)", "summary", "df-generated"]
- ["org.apache.struts2", "ServletCache", "clear", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "IndexController", "index", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "Order", "getAmount", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "Order", "setAmount", "(int)", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "deleteConfirm", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "destroy", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "edit", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "editNew", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "index", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "show", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersController", "update", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersService", "get", "(String)", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersService", "getAll", "()", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersService", "remove", "(String)", "summary", "df-generated"]
- - ["org.demo.rest.example", "OrdersService", "save", "(Order)", "summary", "df-generated"]
- ["org.w3c.dom", "Document", "getElementsByTagName", "(String)", "summary", "df-generated"]
- ["org.w3c.dom", "Document", "getElementsByTagNameNS", "(String,String)", "summary", "df-generated"]
From 12f2539d1d1878560b5c41e7403d873da8d59003 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 31 Jul 2023 10:03:25 +0100
Subject: [PATCH 31/32] Swift: Use flowTo.
---
.../library-tests/dataflow/flowsources/FlowSourcesInline.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
index 25b3b327a70..e4ea2e0e56e 100644
--- a/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
+++ b/swift/ql/test/library-tests/dataflow/flowsources/FlowSourcesInline.ql
@@ -38,7 +38,7 @@ module FlowSourcesTest implements TestSig {
exists(DataFlow::Node sink |
// this is not really what the "flowsources" test is about, but sometimes it's helpful to
// have sinks and confirm that taint reaches obvious points in the flow source test code.
- TestFlow::flow(_, sink) and
+ TestFlow::flowTo(sink) and
location = sink.getLocation() and
element = sink.toString() and
tag = "tainted" and
From f921076fca7ef5b57c9388cec7d878309c6c1b90 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 31 Jul 2023 10:25:25 +0100
Subject: [PATCH 32/32] Swift: Autoformat.
---
swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
index 98d68d0a101..148676e1ac3 100644
--- a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
+++ b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql
@@ -19,4 +19,4 @@ import CommandInjectionFlow::PathGraph
from CommandInjectionFlow::PathNode sourceNode, CommandInjectionFlow::PathNode sinkNode
where CommandInjectionFlow::flowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This command depends on a $@.",
- sourceNode.getNode(), "user-provided value"
\ No newline at end of file
+ sourceNode.getNode(), "user-provided value"