From 048daa9a57e8c481d77313c25f3ad3c32d489c20 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 31 Jul 2023 10:46:18 +0100 Subject: [PATCH 01/11] Swift: QLDoc comments and metadata. --- .../security/CommandInjectionExtensions.qll | 44 ++++++++++++------- .../swift/security/CommandInjectionQuery.qll | 6 +-- .../Security/CWE-078/CommandInjection.ql | 3 +- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll index 26e8782a7994..169656a8f7d7 100644 --- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll @@ -29,26 +29,16 @@ 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() - ) - } -} - +/** + * A reference to any member of `Process`. + */ private class ProcessHost extends MemberRefExpr { ProcessHost() { this.getBase() instanceof ProcessRef } } -/** An expression of type `Process`. */ +/** + * An expression of type `Process`. + */ private class ProcessRef extends Expr { ProcessRef() { this.getType() instanceof ProcessType or @@ -56,7 +46,9 @@ private class ProcessRef extends Expr { } } -/** The type `Process`. */ +/** + * The type `Process`. + */ private class ProcessType extends NominalType { ProcessType() { this.getFullName() = "Process" } } @@ -77,6 +69,24 @@ private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node } } +/** + * A `DataFlow::Node` that is written into a field of a `Process` object. + */ +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() + ) + } +} + /** * A sink defined in a CSV model. */ diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll index 4b67932209dc..10dbc1377260 100644 --- a/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll +++ b/swift/ql/lib/codeql/swift/security/CommandInjectionQuery.qll @@ -1,6 +1,6 @@ /** * Provides a taint-tracking configuration for reasoning about system - * commands built from user-controlled sources (that is, Command injection + * commands built from user-controlled sources (that is, command injection * vulnerabilities). */ @@ -11,7 +11,7 @@ import codeql.swift.dataflow.FlowSources import codeql.swift.security.CommandInjectionExtensions /** - * A taint configuration for tainted data that reaches a Command Injection sink. + * 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 } @@ -26,6 +26,6 @@ module CommandInjectionConfig implements DataFlow::ConfigSig { } /** - * Detect taint flow of tainted data that reaches a Command Injection sink. + * Detect taint flow of tainted data that reaches a command injection sink. */ module CommandInjectionFlow = TaintTracking::Global; diff --git a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql index 148676e1ac38..defa939cf68b 100644 --- a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql +++ b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.ql @@ -1,6 +1,7 @@ /** * @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. + * @description Building a system command from user-controlled sources may allow a malicious + * user to change the meaning of the command. * @kind path-problem * @problem.severity error * @security-severity 9.8 From 2664c306d33e213738970012a896ec7ce2ff8383 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 31 Jul 2023 11:18:12 +0100 Subject: [PATCH 02/11] Swift: Qhelp / examples. --- .../Security/CWE-078/CommandInjection.qhelp | 6 +++--- .../Security/CWE-078/CommandInjectionGood.swift | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp index ab9562af12c2..ed6a27a4222b 100644 --- a/swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp +++ b/swift/ql/src/experimental/Security/CWE-078/CommandInjection.qhelp @@ -24,14 +24,14 @@ using it.

-The following examples execute code from user input without +The following example executes code from user input without sanitizing it first:

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. +meanings:

@@ -42,4 +42,4 @@ OWASP: Command Injection. - \ No newline at end of file + diff --git a/swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift b/swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift index 3482718eeac5..1773d5b187ba 100644 --- a/swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift +++ b/swift/ql/src/experimental/Security/CWE-078/CommandInjectionGood.swift @@ -6,8 +6,10 @@ func validateCommand(_ command: String) -> String? { return nil } -var task = Process() -task.launchPath = "/bin/bash" -task.arguments = ["-c", validateCommand(userControlledString)] // GOOD +if let validatedString = validateCommand(userControlledString) { + var task = Process() + task.launchPath = "/bin/bash" + task.arguments = ["-c", validatedString] // GOOD -task.launch() \ No newline at end of file + task.launch() +} From 8c2140b28d80edf17789522c1828d6c1ee85a906 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 31 Jul 2023 15:31:30 +0100 Subject: [PATCH 03/11] Swift: Add tests. --- .../CWE-078/CommandInjection.expected | 82 +++++++++++ .../Security/CWE-078/CommandInjection.qlref | 1 + .../Security/CWE-078/CommandInjection.swift | 128 ++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected create mode 100644 swift/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref create mode 100644 swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected new file mode 100644 index 000000000000..93ece550df6e --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -0,0 +1,82 @@ +edges +| CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command | +| CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | +| CommandInjection.swift:42:16:42:16 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | +| CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | +| CommandInjection.swift:49:8:49:12 | let ...? [some:0] | CommandInjection.swift:49:12:49:12 | userControlledString | +| CommandInjection.swift:49:12:49:12 | userControlledString | CommandInjection.swift:55:27:55:27 | userControlledString | +| CommandInjection.swift:49:12:49:12 | userControlledString | CommandInjection.swift:58:43:58:43 | userControlledString | +| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | +| CommandInjection.swift:58:5:58:9 | let ...? [some:0] | CommandInjection.swift:58:9:58:9 | validatedString | +| CommandInjection.swift:58:9:58:9 | validatedString | CommandInjection.swift:61:31:61:31 | validatedString | +| CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | +| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | +| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | +| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:79:8:79:12 | let ...? [some:0] | CommandInjection.swift:79:12:79:12 | userControlledString | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:94:36:94:36 | userControlledString | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:95:28:95:28 | userControlledString | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:99:45:99:45 | userControlledString | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:104:46:104:46 | userControlledString | +| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:105:22:105:22 | userControlledString | +| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | +| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:57 | ...! | +| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:94:24:94:57 | ...! | +| CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | +| CommandInjection.swift:99:45:99:45 | userControlledString | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:104:46:104:46 | userControlledString | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | +nodes +| CommandInjection.swift:38:22:38:33 | command | semmle.label | command | +| CommandInjection.swift:38:22:38:33 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:42:16:42:16 | command | semmle.label | command | +| CommandInjection.swift:42:16:42:16 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:42:16:42:16 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | semmle.label | let ...? [some:0, some:0] | +| CommandInjection.swift:49:8:49:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:49:12:49:12 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | +| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:55:27:55:27 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:58:5:58:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:58:9:58:9 | validatedString | semmle.label | validatedString | +| CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | semmle.label | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:58:43:58:43 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:61:31:61:31 | validatedString | semmle.label | validatedString | +| CommandInjection.swift:79:8:79:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:79:12:79:12 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | +| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | +| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:94:24:94:57 | ...! | semmle.label | ...! | +| CommandInjection.swift:94:36:94:36 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:95:28:95:28 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:99:45:99:45 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:104:46:104:46 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:105:22:105:22 | userControlledString | semmle.label | userControlledString | +subpaths +| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +#select +| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:55:27:55:27 | userControlledString | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:61:31:61:31 | validatedString | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:61:31:61:31 | validatedString | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:94:24:94:57 | ...! | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:95:28:95:28 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:105:22:105:22 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref new file mode 100644 index 000000000000..3556b36b1857 --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE-078/CommandInjection.ql \ No newline at end of file diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift new file mode 100644 index 000000000000..85bbda2ee64e --- /dev/null +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -0,0 +1,128 @@ + +// --- stubs --- + +struct URL +{ + init?(string: String) {} + init(fileURLWithPath: String) {} +} + +class NSObject { +} + +class Process : NSObject { + var launchPath: String? { get { nil } set {} } + var arguments: [String]? { get { nil } set {} } + func launch() {} + + var executableURL: URL? { get { nil } set {} } + func run() throws {} + + class func launchedProcess(launchPath path: String, arguments: [String]) -> Process { + return Process() + } + + class func run(_ url: URL, arguments: [String], terminationHandler: (@Sendable (Process) -> Void)? = nil) throws -> Process { + return Process() + } +} + +extension String { + init(contentsOf url: URL) throws { + self.init("") + } +} + +// --- tests --- + +func validateCommand(_ command: String) -> String? { + let allowedCommands = ["ls -l", "pwd", "echo"] + + if allowedCommands.contains(command) { + return command + } + + return nil +} + +func testCommandInjectionQhelpExamples() { + guard let userControlledString = try? String(contentsOf: URL(string: "http://example.com/")!) else { + return + } + + let task1 = Process() + task1.launchPath = "/bin/bash" // GOOD + task1.arguments = ["-c", userControlledString] // BAD + task1.launch() + + if let validatedString = validateCommand(userControlledString) { + let task2 = Process() + task2.launchPath = "/bin/bash" // GOOD + task2.arguments = ["-c", validatedString] // GOOD [FALSE POSITIVE] + task2.launch() + } +} + +func mkProcess() -> Process? { + return Process() +} + +class MyProcess : Process { + var harmlessField: String? + + func setArguments(_ arguments: [String]) { + self.arguments = arguments + } +} + +func testCommandInjectionMore(mySafeString: String) { + guard let userControlledString = try? String(contentsOf: URL(string: "http://example.com/")!) else { + return + } + + let task1 = Process() + task1.executableURL = URL(string: mySafeString)! // GOOD + task1.arguments = ["abc"] // GOOD + try! task1.run() + + let task2 = Process() + task2.executableURL = URL(fileURLWithPath: mySafeString) // GOOD + task2.arguments = ["abc", "def"] // GOOD + try! task2.run() + + let task3 = Process() + task3.executableURL = URL(string: userControlledString)! // BAD + task3.arguments = ["abc", userControlledString] // BAD + try! task3.run() + + let task4 = Process() + task4.executableURL = URL(fileURLWithPath: userControlledString) // BAD + task4.arguments = ["abc", "def" + userControlledString] // BAD + try! task4.run() + + let task5 = mkProcess() + task5?.executableURL = URL(fileURLWithPath: userControlledString) // BAD + task5?.arguments = [userControlledString] // BAD + try! task5?.run() + + let task6 = MyProcess() + task6.executableURL = URL(string: userControlledString)! // BAD [NOT DETECTED] + task6.arguments = [userControlledString] // BAD [NOT DETECTED] + task6.setArguments([userControlledString]) // BAD [NOT DETECTED] + task6.harmlessField = userControlledString // GOOD + try! task6.run() + + let task7 = Process() + task7.executableURL = URL(fileURLWithPath: mySafeString) // GOOD + task7.arguments = ["abc", "def"] + task7.arguments?.append(userControlledString) // BAD [NOT DETECTED] + try! task7.run() + + _ = Process.launchedProcess(launchPath: mySafeString, arguments: ["abc", mySafeString]) // GOOD + _ = Process.launchedProcess(launchPath: userControlledString, arguments: ["abc", mySafeString]) // BAD [NOT DETECTED] + _ = Process.launchedProcess(launchPath: mySafeString, arguments: ["abc", userControlledString]) // BAD [NOT DETECTED] + + _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", mySafeString]) // GOOD + _ = try? Process.run(URL(string: userControlledString)!, arguments: ["abc", mySafeString]) // BAD [NOT DETECTED] + _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", userControlledString]) // BAD [NOT DETECTED] +} From 7b9b96d65716bc846f600a8529ea48f0b4fc595d Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 31 Jul 2023 17:44:22 +0100 Subject: [PATCH 04/11] Swift: Unify the two sink models into one (needs further polish). --- .../security/CommandInjectionExtensions.qll | 50 +--- .../CWE-078/CommandInjection.expected | 223 ++++++++++++++++-- .../Security/CWE-078/CommandInjection.swift | 12 +- 3 files changed, 226 insertions(+), 59 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll index 169656a8f7d7..1af0dc629a33 100644 --- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll @@ -30,29 +30,18 @@ class CommandInjectionAdditionalFlowStep extends Unit { } /** - * A reference to any member of `Process`. + * An additional taint step for command injection vulnerabilities. */ -private class ProcessHost extends MemberRefExpr { - ProcessHost() { this.getBase() instanceof ProcessRef } -} - -/** - * 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) +private class CommandInjectionArrayAdditionalFlowStep extends CommandInjectionAdditionalFlowStep { + override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + // needed until we have proper content flow through arrays. + exists(ArrayExpr arr | + nodeFrom.asExpr() = arr.getAnElement() and + nodeTo.asExpr() = arr + ) } } -/** - * The type `Process`. - */ -private class ProcessType extends NominalType { - ProcessType() { this.getFullName() = "Process" } -} - /** * A `DataFlow::Node` that is written into a `Process` object. */ @@ -63,26 +52,9 @@ private class ProcessSink extends CommandInjectionSink instanceof DataFlow::Node // 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 `DataFlow::Node` that is written into a field of a `Process` object. - */ -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() + this.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = e and + e.getFullyConverted().getType() = t and + not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl ) } } diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 93ece550df6e..02e230c9978f 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -1,16 +1,35 @@ edges +| CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | +| CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | +| CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | +| CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | +| CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | +| CommandInjection.swift:19:7:19:7 | self [harmlessField] | CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command | | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | | CommandInjection.swift:42:16:42:16 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | | CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | | CommandInjection.swift:49:8:49:12 | let ...? [some:0] | CommandInjection.swift:49:12:49:12 | userControlledString | | CommandInjection.swift:49:12:49:12 | userControlledString | CommandInjection.swift:55:27:55:27 | userControlledString | -| CommandInjection.swift:49:12:49:12 | userControlledString | CommandInjection.swift:58:43:58:43 | userControlledString | -| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | +| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | +| CommandInjection.swift:55:2:55:2 | [post] task1 | CommandInjection.swift:56:2:56:2 | task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:55:2:55:2 | [post] task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:55:2:55:2 | [post] task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | task1 [arguments] | +| CommandInjection.swift:55:20:55:47 | [...] | CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | +| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:55:20:55:47 | [...] | +| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:58:43:58:43 | userControlledString | +| CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | +| CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 | +| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:16:7:16:7 | self | +| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:56:2:56:2 | [post] task1 | +| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | +| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | CommandInjection.swift:58:9:58:9 | validatedString | | CommandInjection.swift:58:9:58:9 | validatedString | CommandInjection.swift:61:31:61:31 | validatedString | | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | @@ -18,22 +37,114 @@ edges | CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:61:6:61:6 | [post] task2 | CommandInjection.swift:62:6:62:6 | task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:61:6:61:6 | [post] task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:61:6:61:6 | [post] task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | task2 [arguments] | +| CommandInjection.swift:61:24:61:46 | [...] | CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | +| CommandInjection.swift:61:31:61:31 | validatedString | CommandInjection.swift:61:24:61:46 | [...] | +| CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 | +| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:16:7:16:7 | self | +| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:62:6:62:6 | [post] task2 | +| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | +| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | +| CommandInjection.swift:71:6:71:6 | value | file://:0:0:0:0 | value | | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | CommandInjection.swift:79:12:79:12 | userControlledString | | CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:94:36:94:36 | userControlledString | | CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:95:28:95:28 | userControlledString | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:99:45:99:45 | userControlledString | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:104:46:104:46 | userControlledString | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:105:22:105:22 | userControlledString | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | +| CommandInjection.swift:94:2:94:2 | [post] task3 | CommandInjection.swift:95:2:95:2 | task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:95:2:95:2 | task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:95:2:95:2 | task3 [executableURL] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:57 | ...! | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:94:24:94:57 | ...! | +| CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | | CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | +| CommandInjection.swift:95:2:95:2 | [post] task3 | CommandInjection.swift:96:7:96:7 | task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | task3 [arguments] | +| CommandInjection.swift:95:2:95:2 | task3 | CommandInjection.swift:96:7:96:7 | task3 | +| CommandInjection.swift:95:2:95:2 | task3 [executableURL] | CommandInjection.swift:96:7:96:7 | task3 [executableURL] | +| CommandInjection.swift:95:20:95:48 | [...] | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:95:20:95:48 | [...] | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:99:45:99:45 | userControlledString | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:104:46:104:46 | userControlledString | +| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:105:22:105:22 | userControlledString | +| CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 | +| CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 | +| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:19:7:19:7 | self | +| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:96:7:96:7 | [post] task3 | +| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | +| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | +| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | +| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | +| CommandInjection.swift:99:2:99:2 | [post] task4 | CommandInjection.swift:100:2:100:2 | task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:99:2:99:2 | [post] task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:99:2:99:2 | [post] task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:100:2:100:2 | task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:100:2:100:2 | task4 [executableURL] | +| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | | CommandInjection.swift:99:45:99:45 | userControlledString | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:100:2:100:2 | [post] task4 | CommandInjection.swift:101:7:101:7 | task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:100:2:100:2 | [post] task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:100:2:100:2 | [post] task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | task4 [arguments] | +| CommandInjection.swift:100:2:100:2 | task4 | CommandInjection.swift:101:7:101:7 | task4 | +| CommandInjection.swift:100:2:100:2 | task4 [executableURL] | CommandInjection.swift:101:7:101:7 | task4 [executableURL] | +| CommandInjection.swift:100:20:100:56 | [...] | CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | +| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | CommandInjection.swift:100:20:100:56 | [...] | +| CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 | +| CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 | +| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:19:7:19:7 | self | +| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:101:7:101:7 | [post] task4 | +| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | +| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | +| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | +| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | +| CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | CommandInjection.swift:104:2:104:7 | [post] ...? | +| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | | CommandInjection.swift:104:46:104:46 | userControlledString | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | CommandInjection.swift:105:2:105:7 | [post] ...? | +| CommandInjection.swift:105:21:105:42 | [...] | CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | +| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:105:21:105:42 | [...] | +| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:110:21:110:21 | userControlledString | +| CommandInjection.swift:110:21:110:21 | userControlledString | CommandInjection.swift:111:22:111:22 | userControlledString | +| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:112:24:112:24 | userControlledString | +| CommandInjection.swift:112:2:112:2 | [post] task6 | CommandInjection.swift:113:7:113:7 | task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | +| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:71:6:71:6 | value | +| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | +| CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 | +| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:19:7:19:7 | self | +| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:113:7:113:7 | [post] task6 | +| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:19:7:19:7 | self [harmlessField] | +| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | +| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [harmlessField] | nodes +| CommandInjection.swift:16:2:16:17 | self[return] | semmle.label | self[return] | +| CommandInjection.swift:16:2:16:17 | self[return] [arguments] | semmle.label | self[return] [arguments] | +| CommandInjection.swift:16:7:16:7 | self | semmle.label | self | +| CommandInjection.swift:16:7:16:7 | self [arguments] | semmle.label | self [arguments] | +| CommandInjection.swift:19:2:19:21 | self[return] | semmle.label | self[return] | +| CommandInjection.swift:19:2:19:21 | self[return] [arguments] | semmle.label | self[return] [arguments] | +| CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | semmle.label | self[return] [executableURL] | +| CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | semmle.label | self[return] [harmlessField] | +| CommandInjection.swift:19:7:19:7 | self | semmle.label | self | +| CommandInjection.swift:19:7:19:7 | self [arguments] | semmle.label | self [arguments] | +| CommandInjection.swift:19:7:19:7 | self [executableURL] | semmle.label | self [executableURL] | +| CommandInjection.swift:19:7:19:7 | self [harmlessField] | semmle.label | self [harmlessField] | | CommandInjection.swift:38:22:38:33 | command | semmle.label | command | | CommandInjection.swift:38:22:38:33 | command [some:0] | semmle.label | command [some:0] | | CommandInjection.swift:42:16:42:16 | command | semmle.label | command | @@ -46,37 +157,121 @@ nodes | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:55:2:55:2 | [post] task1 | semmle.label | [post] task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 | semmle.label | [post] task1 | +| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | +| CommandInjection.swift:55:20:55:47 | [...] | semmle.label | [...] | | CommandInjection.swift:55:27:55:27 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:56:2:56:2 | [post] task1 | semmle.label | [post] task1 | +| CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | +| CommandInjection.swift:56:2:56:2 | task1 | semmle.label | task1 | +| CommandInjection.swift:56:2:56:2 | task1 [arguments] | semmle.label | task1 [arguments] | | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:58:9:58:9 | validatedString | semmle.label | validatedString | | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | semmle.label | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:61:6:61:6 | [post] task2 | semmle.label | [post] task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 | semmle.label | [post] task2 | +| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | +| CommandInjection.swift:61:24:61:46 | [...] | semmle.label | [...] | | CommandInjection.swift:61:31:61:31 | validatedString | semmle.label | validatedString | +| CommandInjection.swift:62:6:62:6 | [post] task2 | semmle.label | [post] task2 | +| CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | +| CommandInjection.swift:62:6:62:6 | task2 | semmle.label | task2 | +| CommandInjection.swift:62:6:62:6 | task2 [arguments] | semmle.label | task2 [arguments] | +| CommandInjection.swift:71:6:71:6 | value | semmle.label | value | | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:79:12:79:12 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:94:24:94:57 | ...! | semmle.label | ...! | | CommandInjection.swift:94:36:94:36 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:95:2:95:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | +| CommandInjection.swift:95:2:95:2 | task3 | semmle.label | task3 | +| CommandInjection.swift:95:2:95:2 | task3 [executableURL] | semmle.label | task3 [executableURL] | +| CommandInjection.swift:95:20:95:48 | [...] | semmle.label | [...] | | CommandInjection.swift:95:28:95:28 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:96:7:96:7 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | +| CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | +| CommandInjection.swift:96:7:96:7 | task3 | semmle.label | task3 | +| CommandInjection.swift:96:7:96:7 | task3 [arguments] | semmle.label | task3 [arguments] | +| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | semmle.label | task3 [executableURL] | +| CommandInjection.swift:99:2:99:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:99:45:99:45 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:100:2:100:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | +| CommandInjection.swift:100:2:100:2 | task4 | semmle.label | task4 | +| CommandInjection.swift:100:2:100:2 | task4 [executableURL] | semmle.label | task4 [executableURL] | +| CommandInjection.swift:100:20:100:56 | [...] | semmle.label | [...] | | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| CommandInjection.swift:101:7:101:7 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | +| CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | +| CommandInjection.swift:101:7:101:7 | task4 | semmle.label | task4 | +| CommandInjection.swift:101:7:101:7 | task4 [arguments] | semmle.label | task4 [arguments] | +| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | semmle.label | task4 [executableURL] | +| CommandInjection.swift:104:2:104:7 | [post] ...? | semmle.label | [post] ...? | +| CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | semmle.label | [post] ...? [executableURL] | | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:104:46:104:46 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:105:2:105:7 | [post] ...? | semmle.label | [post] ...? | +| CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | semmle.label | [post] ...? [arguments] | +| CommandInjection.swift:105:21:105:42 | [...] | semmle.label | [...] | | CommandInjection.swift:105:22:105:22 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:110:21:110:21 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:111:22:111:22 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:112:2:112:2 | [post] task6 | semmle.label | [post] task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 | semmle.label | [post] task6 | +| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | semmle.label | [post] task6 [harmlessField] | +| CommandInjection.swift:112:24:112:24 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:113:7:113:7 | [post] task6 | semmle.label | [post] task6 | +| CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | semmle.label | [post] task6 [harmlessField] | +| CommandInjection.swift:113:7:113:7 | task6 | semmle.label | task6 | +| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | semmle.label | task6 [harmlessField] | +| file://:0:0:0:0 | [post] self [harmlessField] | semmle.label | [post] self [harmlessField] | +| file://:0:0:0:0 | value | semmle.label | value | subpaths +| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | CommandInjection.swift:56:2:56:2 | [post] task1 | +| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | | CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | CommandInjection.swift:62:6:62:6 | [post] task2 | +| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | +| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:96:7:96:7 | [post] task3 | +| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | +| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | +| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:101:7:101:7 | [post] task4 | +| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | +| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | +| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:71:6:71:6 | value | file://:0:0:0:0 | [post] self [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | +| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:113:7:113:7 | [post] task6 | +| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:19:7:19:7 | self [harmlessField] | CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | #select -| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:55:27:55:27 | userControlledString | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:61:31:61:31 | validatedString | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:61:31:61:31 | validatedString | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:94:24:94:57 | ...! | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:95:28:95:28 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:105:22:105:22 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:55:2:55:2 | [post] task1 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:55:2:55:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:56:2:56:2 | [post] task1 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:56:2:56:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:61:6:61:6 | [post] task2 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:61:6:61:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:62:6:62:6 | [post] task2 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:62:6:62:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:94:2:94:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:94:2:94:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:95:2:95:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:95:2:95:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:96:7:96:7 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:96:7:96:7 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:99:2:99:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:2:99:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:100:2:100:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:100:2:100:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:101:7:101:7 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:101:7:101:7 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:104:2:104:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:104:2:104:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:105:2:105:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:105:2:105:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:112:2:112:2 | [post] task6 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:112:2:112:2 | [post] task6 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:113:7:113:7 | [post] task6 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:113:7:113:7 | [post] task6 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift index 85bbda2ee64e..ad335d81c197 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -53,13 +53,13 @@ func testCommandInjectionQhelpExamples() { let task1 = Process() task1.launchPath = "/bin/bash" // GOOD task1.arguments = ["-c", userControlledString] // BAD - task1.launch() + task1.launch() // [FALSE POSITIVE] if let validatedString = validateCommand(userControlledString) { let task2 = Process() task2.launchPath = "/bin/bash" // GOOD task2.arguments = ["-c", validatedString] // GOOD [FALSE POSITIVE] - task2.launch() + task2.launch() // [FALSE POSITIVE] } } @@ -93,12 +93,12 @@ func testCommandInjectionMore(mySafeString: String) { let task3 = Process() task3.executableURL = URL(string: userControlledString)! // BAD task3.arguments = ["abc", userControlledString] // BAD - try! task3.run() + try! task3.run() // [FALSE POSITIVE] let task4 = Process() task4.executableURL = URL(fileURLWithPath: userControlledString) // BAD task4.arguments = ["abc", "def" + userControlledString] // BAD - try! task4.run() + try! task4.run() // [FALSE POSITIVE] let task5 = mkProcess() task5?.executableURL = URL(fileURLWithPath: userControlledString) // BAD @@ -109,8 +109,8 @@ func testCommandInjectionMore(mySafeString: String) { task6.executableURL = URL(string: userControlledString)! // BAD [NOT DETECTED] task6.arguments = [userControlledString] // BAD [NOT DETECTED] task6.setArguments([userControlledString]) // BAD [NOT DETECTED] - task6.harmlessField = userControlledString // GOOD - try! task6.run() + task6.harmlessField = userControlledString // GOOD [FALSE POSITIVE] + try! task6.run() // [FALSE POSITIVE] let task7 = Process() task7.executableURL = URL(fileURLWithPath: mySafeString) // GOOD From 1c7d63a18fe4eb661c6a7a9d25c3fcdef038566c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:20:31 +0100 Subject: [PATCH 05/11] Swift: Model sinks explicitly with models-as-data. --- .../security/CommandInjectionExtensions.qll | 36 ++-- .../CWE-078/CommandInjection.expected | 170 +++--------------- .../Security/CWE-078/CommandInjection.swift | 20 +-- 3 files changed, 52 insertions(+), 174 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll index 1af0dc629a33..a0672bdb187a 100644 --- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll @@ -42,26 +42,28 @@ private class CommandInjectionArrayAdditionalFlowStep extends CommandInjectionAd } } -/** - * A `DataFlow::Node` that is written into a `Process` object. - */ -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 - this.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = e and - e.getFullyConverted().getType() = t and - not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl - ) - } -} - /** * A sink defined in a CSV model. */ private class DefaultCommandInjectionSink extends CommandInjectionSink { DefaultCommandInjectionSink() { sinkNode(this, "command-injection") } } + +private class CommandInjectionSinks extends SinkModelCsv { + override predicate row(string row) { + row = + [ + ";Process;true;run(_:arguments:terminationHandler:);;;Argument[0..1];command-injection", + ";Process;true;launchedProcess(launchPath:arguments:);;;Argument[0..1];command-injection", + ";Process;true;arguments;;;PostUpdate;command-injection", + ";Process;true;currentDirectory;;;PostUpdate;command-injection", + ";Process;true;environment;;;PostUpdate;command-injection", + ";Process;true;executableURL;;;PostUpdate;command-injection", + ";Process;true;standardError;;;PostUpdate;command-injection", + ";Process;true;standardInput;;;PostUpdate;command-injection", + ";Process;true;standardOutput;;;PostUpdate;command-injection", + ";Process;true;currentDirectoryPath;;;PostUpdate;command-injection", + ";Process;true;launchPath;;;PostUpdate;command-injection", + ] + } +} diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 02e230c9978f..16710c8a23d5 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -1,10 +1,4 @@ edges -| CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | -| CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | -| CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | -| CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | -| CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | -| CommandInjection.swift:19:7:19:7 | self [harmlessField] | CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command | | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | | CommandInjection.swift:42:16:42:16 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | @@ -16,20 +10,11 @@ edges | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | -| CommandInjection.swift:55:2:55:2 | [post] task1 | CommandInjection.swift:56:2:56:2 | task1 | | CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:55:2:55:2 | [post] task1 | -| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:55:2:55:2 | [post] task1 | -| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | task1 | -| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | task1 [arguments] | | CommandInjection.swift:55:20:55:47 | [...] | CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | | CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:55:20:55:47 | [...] | | CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:58:43:58:43 | userControlledString | | CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | -| CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 | -| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:16:7:16:7 | self | -| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:56:2:56:2 | [post] task1 | -| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | -| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | CommandInjection.swift:58:9:58:9 | validatedString | | CommandInjection.swift:58:9:58:9 | validatedString | CommandInjection.swift:61:31:61:31 | validatedString | | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | @@ -37,79 +22,33 @@ edges | CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:61:6:61:6 | [post] task2 | CommandInjection.swift:62:6:62:6 | task2 | -| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:61:6:61:6 | [post] task2 | | CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:61:6:61:6 | [post] task2 | -| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | task2 | -| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | task2 [arguments] | | CommandInjection.swift:61:24:61:46 | [...] | CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | | CommandInjection.swift:61:31:61:31 | validatedString | CommandInjection.swift:61:24:61:46 | [...] | -| CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 | -| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:16:7:16:7 | self | -| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:62:6:62:6 | [post] task2 | -| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | -| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | -| CommandInjection.swift:71:6:71:6 | value | file://:0:0:0:0 | value | | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | CommandInjection.swift:79:12:79:12 | userControlledString | | CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:94:36:94:36 | userControlledString | | CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:95:28:95:28 | userControlledString | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | -| CommandInjection.swift:94:2:94:2 | [post] task3 | CommandInjection.swift:95:2:95:2 | task3 | -| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | -| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:95:2:95:2 | task3 | -| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:95:2:95:2 | task3 [executableURL] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:57 | ...! | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:94:24:94:57 | ...! | | CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | | CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | -| CommandInjection.swift:95:2:95:2 | [post] task3 | CommandInjection.swift:96:7:96:7 | task3 | | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | -| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | -| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | task3 | -| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | task3 [arguments] | -| CommandInjection.swift:95:2:95:2 | task3 | CommandInjection.swift:96:7:96:7 | task3 | -| CommandInjection.swift:95:2:95:2 | task3 [executableURL] | CommandInjection.swift:96:7:96:7 | task3 [executableURL] | | CommandInjection.swift:95:20:95:48 | [...] | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:95:20:95:48 | [...] | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:99:45:99:45 | userControlledString | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:104:46:104:46 | userControlledString | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:105:22:105:22 | userControlledString | -| CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 | -| CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 | -| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:19:7:19:7 | self | -| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:96:7:96:7 | [post] task3 | -| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | -| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | -| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | -| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | -| CommandInjection.swift:99:2:99:2 | [post] task4 | CommandInjection.swift:100:2:100:2 | task4 | -| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:99:2:99:2 | [post] task4 | | CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:99:2:99:2 | [post] task4 | -| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:100:2:100:2 | task4 | -| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:100:2:100:2 | task4 [executableURL] | | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | | CommandInjection.swift:99:45:99:45 | userControlledString | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | -| CommandInjection.swift:100:2:100:2 | [post] task4 | CommandInjection.swift:101:7:101:7 | task4 | -| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:100:2:100:2 | [post] task4 | | CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:100:2:100:2 | [post] task4 | -| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | task4 | -| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | task4 [arguments] | -| CommandInjection.swift:100:2:100:2 | task4 | CommandInjection.swift:101:7:101:7 | task4 | -| CommandInjection.swift:100:2:100:2 | task4 [executableURL] | CommandInjection.swift:101:7:101:7 | task4 [executableURL] | | CommandInjection.swift:100:20:100:56 | [...] | CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | CommandInjection.swift:100:20:100:56 | [...] | -| CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 | -| CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 | -| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:19:7:19:7 | self | -| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:101:7:101:7 | [post] task4 | -| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | -| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | -| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | -| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | | CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | CommandInjection.swift:104:2:104:7 | [post] ...? | | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | | CommandInjection.swift:104:46:104:46 | userControlledString | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | @@ -118,33 +57,17 @@ edges | CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:105:21:105:42 | [...] | | CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:110:21:110:21 | userControlledString | | CommandInjection.swift:110:21:110:21 | userControlledString | CommandInjection.swift:111:22:111:22 | userControlledString | -| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:112:24:112:24 | userControlledString | -| CommandInjection.swift:112:2:112:2 | [post] task6 | CommandInjection.swift:113:7:113:7 | task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | -| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:71:6:71:6 | value | -| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | -| CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 | -| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:19:7:19:7 | self | -| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:113:7:113:7 | [post] task6 | -| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:19:7:19:7 | self [harmlessField] | -| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | -| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [harmlessField] | +| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:122:42:122:42 | userControlledString | +| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:123:75:123:75 | userControlledString | +| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:123:67:123:95 | [...] | +| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:126:35:126:35 | userControlledString | +| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:127:70:127:70 | userControlledString | +| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | CommandInjection.swift:126:23:126:56 | ...! | +| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:126:23:126:56 | ...! | +| CommandInjection.swift:126:35:126:35 | userControlledString | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | +| CommandInjection.swift:127:70:127:70 | userControlledString | CommandInjection.swift:127:62:127:90 | [...] | nodes -| CommandInjection.swift:16:2:16:17 | self[return] | semmle.label | self[return] | -| CommandInjection.swift:16:2:16:17 | self[return] [arguments] | semmle.label | self[return] [arguments] | -| CommandInjection.swift:16:7:16:7 | self | semmle.label | self | -| CommandInjection.swift:16:7:16:7 | self [arguments] | semmle.label | self [arguments] | -| CommandInjection.swift:19:2:19:21 | self[return] | semmle.label | self[return] | -| CommandInjection.swift:19:2:19:21 | self[return] [arguments] | semmle.label | self[return] [arguments] | -| CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | semmle.label | self[return] [executableURL] | -| CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | semmle.label | self[return] [harmlessField] | -| CommandInjection.swift:19:7:19:7 | self | semmle.label | self | -| CommandInjection.swift:19:7:19:7 | self [arguments] | semmle.label | self [arguments] | -| CommandInjection.swift:19:7:19:7 | self [executableURL] | semmle.label | self [executableURL] | -| CommandInjection.swift:19:7:19:7 | self [harmlessField] | semmle.label | self [harmlessField] | | CommandInjection.swift:38:22:38:33 | command | semmle.label | command | | CommandInjection.swift:38:22:38:33 | command [some:0] | semmle.label | command [some:0] | | CommandInjection.swift:42:16:42:16 | command | semmle.label | command | @@ -158,72 +81,41 @@ nodes | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:55:2:55:2 | [post] task1 | semmle.label | [post] task1 | -| CommandInjection.swift:55:2:55:2 | [post] task1 | semmle.label | [post] task1 | | CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | | CommandInjection.swift:55:20:55:47 | [...] | semmle.label | [...] | | CommandInjection.swift:55:27:55:27 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | -| CommandInjection.swift:56:2:56:2 | [post] task1 | semmle.label | [post] task1 | -| CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | -| CommandInjection.swift:56:2:56:2 | task1 | semmle.label | task1 | -| CommandInjection.swift:56:2:56:2 | task1 [arguments] | semmle.label | task1 [arguments] | | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:58:9:58:9 | validatedString | semmle.label | validatedString | | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | semmle.label | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | | CommandInjection.swift:61:6:61:6 | [post] task2 | semmle.label | [post] task2 | -| CommandInjection.swift:61:6:61:6 | [post] task2 | semmle.label | [post] task2 | | CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | | CommandInjection.swift:61:24:61:46 | [...] | semmle.label | [...] | | CommandInjection.swift:61:31:61:31 | validatedString | semmle.label | validatedString | -| CommandInjection.swift:62:6:62:6 | [post] task2 | semmle.label | [post] task2 | -| CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | -| CommandInjection.swift:62:6:62:6 | task2 | semmle.label | task2 | -| CommandInjection.swift:62:6:62:6 | task2 [arguments] | semmle.label | task2 [arguments] | -| CommandInjection.swift:71:6:71:6 | value | semmle.label | value | | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | | CommandInjection.swift:79:12:79:12 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:94:24:94:57 | ...! | semmle.label | ...! | | CommandInjection.swift:94:36:94:36 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:95:2:95:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:95:2:95:2 | [post] task3 | semmle.label | [post] task3 | | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | -| CommandInjection.swift:95:2:95:2 | task3 | semmle.label | task3 | -| CommandInjection.swift:95:2:95:2 | task3 [executableURL] | semmle.label | task3 [executableURL] | | CommandInjection.swift:95:20:95:48 | [...] | semmle.label | [...] | | CommandInjection.swift:95:28:95:28 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:96:7:96:7 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | -| CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | -| CommandInjection.swift:96:7:96:7 | task3 | semmle.label | task3 | -| CommandInjection.swift:96:7:96:7 | task3 [arguments] | semmle.label | task3 [arguments] | -| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | semmle.label | task3 [executableURL] | -| CommandInjection.swift:99:2:99:2 | [post] task4 | semmle.label | [post] task4 | | CommandInjection.swift:99:2:99:2 | [post] task4 | semmle.label | [post] task4 | | CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | | CommandInjection.swift:99:45:99:45 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:100:2:100:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:100:2:100:2 | [post] task4 | semmle.label | [post] task4 | | CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | -| CommandInjection.swift:100:2:100:2 | task4 | semmle.label | task4 | -| CommandInjection.swift:100:2:100:2 | task4 [executableURL] | semmle.label | task4 [executableURL] | | CommandInjection.swift:100:20:100:56 | [...] | semmle.label | [...] | | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| CommandInjection.swift:101:7:101:7 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | -| CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | -| CommandInjection.swift:101:7:101:7 | task4 | semmle.label | task4 | -| CommandInjection.swift:101:7:101:7 | task4 [arguments] | semmle.label | task4 [arguments] | -| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | semmle.label | task4 [executableURL] | | CommandInjection.swift:104:2:104:7 | [post] ...? | semmle.label | [post] ...? | | CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | semmle.label | [post] ...? [executableURL] | | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | @@ -234,44 +126,28 @@ nodes | CommandInjection.swift:105:22:105:22 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:110:21:110:21 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:111:22:111:22 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:112:2:112:2 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | semmle.label | [post] task6 [harmlessField] | -| CommandInjection.swift:112:24:112:24 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:113:7:113:7 | [post] task6 | semmle.label | [post] task6 | -| CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | semmle.label | [post] task6 [harmlessField] | -| CommandInjection.swift:113:7:113:7 | task6 | semmle.label | task6 | -| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | semmle.label | task6 [harmlessField] | -| file://:0:0:0:0 | [post] self [harmlessField] | semmle.label | [post] self [harmlessField] | -| file://:0:0:0:0 | value | semmle.label | value | +| CommandInjection.swift:122:42:122:42 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:123:67:123:95 | [...] | semmle.label | [...] | +| CommandInjection.swift:123:75:123:75 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | +| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:126:23:126:56 | ...! | semmle.label | ...! | +| CommandInjection.swift:126:35:126:35 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:127:62:127:90 | [...] | semmle.label | [...] | +| CommandInjection.swift:127:70:127:70 | userControlledString | semmle.label | userControlledString | subpaths -| CommandInjection.swift:56:2:56:2 | task1 | CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | CommandInjection.swift:56:2:56:2 | [post] task1 | -| CommandInjection.swift:56:2:56:2 | task1 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | CommandInjection.swift:56:2:56:2 | [post] task1 [arguments] | | CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:62:6:62:6 | task2 | CommandInjection.swift:16:7:16:7 | self | CommandInjection.swift:16:2:16:17 | self[return] | CommandInjection.swift:62:6:62:6 | [post] task2 | -| CommandInjection.swift:62:6:62:6 | task2 [arguments] | CommandInjection.swift:16:7:16:7 | self [arguments] | CommandInjection.swift:16:2:16:17 | self[return] [arguments] | CommandInjection.swift:62:6:62:6 | [post] task2 [arguments] | -| CommandInjection.swift:96:7:96:7 | task3 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:96:7:96:7 | [post] task3 | -| CommandInjection.swift:96:7:96:7 | task3 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | CommandInjection.swift:96:7:96:7 | [post] task3 [arguments] | -| CommandInjection.swift:96:7:96:7 | task3 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | CommandInjection.swift:96:7:96:7 | [post] task3 [executableURL] | -| CommandInjection.swift:101:7:101:7 | task4 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:101:7:101:7 | [post] task4 | -| CommandInjection.swift:101:7:101:7 | task4 [arguments] | CommandInjection.swift:19:7:19:7 | self [arguments] | CommandInjection.swift:19:2:19:21 | self[return] [arguments] | CommandInjection.swift:101:7:101:7 | [post] task4 [arguments] | -| CommandInjection.swift:101:7:101:7 | task4 [executableURL] | CommandInjection.swift:19:7:19:7 | self [executableURL] | CommandInjection.swift:19:2:19:21 | self[return] [executableURL] | CommandInjection.swift:101:7:101:7 | [post] task4 [executableURL] | -| CommandInjection.swift:112:24:112:24 | userControlledString | CommandInjection.swift:71:6:71:6 | value | file://:0:0:0:0 | [post] self [harmlessField] | CommandInjection.swift:112:2:112:2 | [post] task6 [harmlessField] | -| CommandInjection.swift:113:7:113:7 | task6 | CommandInjection.swift:19:7:19:7 | self | CommandInjection.swift:19:2:19:21 | self[return] | CommandInjection.swift:113:7:113:7 | [post] task6 | -| CommandInjection.swift:113:7:113:7 | task6 [harmlessField] | CommandInjection.swift:19:7:19:7 | self [harmlessField] | CommandInjection.swift:19:2:19:21 | self[return] [harmlessField] | CommandInjection.swift:113:7:113:7 | [post] task6 [harmlessField] | #select | CommandInjection.swift:55:2:55:2 | [post] task1 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:55:2:55:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:56:2:56:2 | [post] task1 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:56:2:56:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:61:6:61:6 | [post] task2 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:61:6:61:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:62:6:62:6 | [post] task2 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:62:6:62:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:94:2:94:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:94:2:94:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:95:2:95:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:95:2:95:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:96:7:96:7 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:96:7:96:7 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:99:2:99:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:2:99:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:100:2:100:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:100:2:100:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:101:7:101:7 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:101:7:101:7 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:104:2:104:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:104:2:104:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:105:2:105:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:105:2:105:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:112:2:112:2 | [post] task6 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:112:2:112:2 | [post] task6 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:113:7:113:7 | [post] task6 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:113:7:113:7 | [post] task6 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:122:42:122:42 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:122:42:122:42 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:123:67:123:95 | [...] | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:123:67:123:95 | [...] | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:126:23:126:56 | ...! | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:126:23:126:56 | ...! | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:127:62:127:90 | [...] | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:127:62:127:90 | [...] | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift index ad335d81c197..73f7872e3e42 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -53,13 +53,13 @@ func testCommandInjectionQhelpExamples() { let task1 = Process() task1.launchPath = "/bin/bash" // GOOD task1.arguments = ["-c", userControlledString] // BAD - task1.launch() // [FALSE POSITIVE] + task1.launch() if let validatedString = validateCommand(userControlledString) { let task2 = Process() task2.launchPath = "/bin/bash" // GOOD task2.arguments = ["-c", validatedString] // GOOD [FALSE POSITIVE] - task2.launch() // [FALSE POSITIVE] + task2.launch() } } @@ -93,12 +93,12 @@ func testCommandInjectionMore(mySafeString: String) { let task3 = Process() task3.executableURL = URL(string: userControlledString)! // BAD task3.arguments = ["abc", userControlledString] // BAD - try! task3.run() // [FALSE POSITIVE] + try! task3.run() let task4 = Process() task4.executableURL = URL(fileURLWithPath: userControlledString) // BAD task4.arguments = ["abc", "def" + userControlledString] // BAD - try! task4.run() // [FALSE POSITIVE] + try! task4.run() let task5 = mkProcess() task5?.executableURL = URL(fileURLWithPath: userControlledString) // BAD @@ -109,8 +109,8 @@ func testCommandInjectionMore(mySafeString: String) { task6.executableURL = URL(string: userControlledString)! // BAD [NOT DETECTED] task6.arguments = [userControlledString] // BAD [NOT DETECTED] task6.setArguments([userControlledString]) // BAD [NOT DETECTED] - task6.harmlessField = userControlledString // GOOD [FALSE POSITIVE] - try! task6.run() // [FALSE POSITIVE] + task6.harmlessField = userControlledString // GOOD + try! task6.run() let task7 = Process() task7.executableURL = URL(fileURLWithPath: mySafeString) // GOOD @@ -119,10 +119,10 @@ func testCommandInjectionMore(mySafeString: String) { try! task7.run() _ = Process.launchedProcess(launchPath: mySafeString, arguments: ["abc", mySafeString]) // GOOD - _ = Process.launchedProcess(launchPath: userControlledString, arguments: ["abc", mySafeString]) // BAD [NOT DETECTED] - _ = Process.launchedProcess(launchPath: mySafeString, arguments: ["abc", userControlledString]) // BAD [NOT DETECTED] + _ = Process.launchedProcess(launchPath: userControlledString, arguments: ["abc", mySafeString]) // BAD + _ = Process.launchedProcess(launchPath: mySafeString, arguments: ["abc", userControlledString]) // BAD _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", mySafeString]) // GOOD - _ = try? Process.run(URL(string: userControlledString)!, arguments: ["abc", mySafeString]) // BAD [NOT DETECTED] - _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", userControlledString]) // BAD [NOT DETECTED] + _ = try? Process.run(URL(string: userControlledString)!, arguments: ["abc", mySafeString]) // BAD + _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", userControlledString]) // BAD } From 348c45dff32dc2aee72725ad3afe7cd027ff862a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 3 Aug 2023 18:07:59 +0100 Subject: [PATCH 06/11] Swift: Use enum content in URL and NSURL models. --- .../codeql/swift/frameworks/StandardLibrary/NsUrl.qll | 2 +- .../codeql/swift/frameworks/StandardLibrary/Url.qll | 8 ++++---- .../Security/CWE-078/CommandInjection.expected | 10 ++-------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsUrl.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsUrl.qll index 019bc30cdf35..fb4f8a8516ce 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsUrl.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/NsUrl.qll @@ -10,6 +10,6 @@ private import codeql.swift.dataflow.ExternalFlow */ private class NsUrlSummaries extends SummaryModelCsv { override predicate row(string row) { - row = ";NSURL;true;init(string:);(String);;Argument[0];ReturnValue;taint" + row = ";NSURL;true;init(string:);(String);;Argument[0];ReturnValue.OptionalSome;taint" } } diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll index 2f03fdd5327b..d86c004b1b24 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll @@ -85,8 +85,8 @@ private class UrlSummaries extends SummaryModelCsv { override predicate row(string row) { row = [ - ";URL;true;init(string:);(String);;Argument[0];ReturnValue;taint", - ";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0..1];ReturnValue;taint", + ";URL;true;init(string:);(String);;Argument[0];ReturnValue.OptionalSome;taint", + ";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0..1];ReturnValue.OptionalSome;taint", ";URL;true;init(fileURLWithPath:);;;Argument[0];ReturnValue;taint", ";URL;true;init(fileURLWithPath:isDirectory:);;;Argument[0];ReturnValue;taint", ";URL;true;init(fileURLWithPath:relativeTo:);;;Argument[0..1];ReturnValue;taint", @@ -95,8 +95,8 @@ private class UrlSummaries extends SummaryModelCsv { ";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[0];ReturnValue;taint", ";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[2];ReturnValue;taint", ";URL;true;init(fileReferenceLiteralResourceName:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(_:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(_:isDirectory:);;;Argument[0];ReturnValue;taint", + ";URL;true;init(_:);;;Argument[0];ReturnValue.OptionalSome;taint", + ";URL;true;init(_:isDirectory:);;;Argument[0];ReturnValue.OptionalSome;taint", ";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[0];ReturnValue;taint", ";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[2];ReturnValue;taint", ";URL;true;init(resolvingAliasFileAt:options:);;;Argument[0];ReturnValue;taint", diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 16710c8a23d5..9bdcc8101f87 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -31,11 +31,9 @@ edges | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | -| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | -| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | CommandInjection.swift:94:24:94:57 | ...! | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:94:24:94:57 | ...! | | CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | -| CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | +| CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | | CommandInjection.swift:95:20:95:48 | [...] | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | | CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:95:20:95:48 | [...] | @@ -62,10 +60,8 @@ edges | CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:123:67:123:95 | [...] | | CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:126:35:126:35 | userControlledString | | CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:127:70:127:70 | userControlledString | -| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | -| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | CommandInjection.swift:126:23:126:56 | ...! | | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:126:23:126:56 | ...! | -| CommandInjection.swift:126:35:126:35 | userControlledString | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | +| CommandInjection.swift:126:35:126:35 | userControlledString | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | | CommandInjection.swift:127:70:127:70 | userControlledString | CommandInjection.swift:127:62:127:90 | [...] | nodes | CommandInjection.swift:38:22:38:33 | command | semmle.label | command | @@ -100,7 +96,6 @@ nodes | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | | CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | -| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:94:24:94:57 | ...! | semmle.label | ...! | | CommandInjection.swift:94:36:94:36 | userControlledString | semmle.label | userControlledString | @@ -129,7 +124,6 @@ nodes | CommandInjection.swift:122:42:122:42 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:123:67:123:95 | [...] | semmle.label | [...] | | CommandInjection.swift:123:75:123:75 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | CommandInjection.swift:126:23:126:56 | ...! | semmle.label | ...! | | CommandInjection.swift:126:35:126:35 | userControlledString | semmle.label | userControlledString | From 71771890a5ccb5823bd684041437f700d09534c5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:56:11 +0100 Subject: [PATCH 07/11] Swift: Add a test with NSUserScriptTask. --- .../CWE-078/CommandInjection.expected | 286 +++++++++--------- .../Security/CWE-078/CommandInjection.swift | 33 ++ 2 files changed, 176 insertions(+), 143 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 9bdcc8101f87..e79dab71b3ab 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -1,147 +1,147 @@ edges -| CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command | -| CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | -| CommandInjection.swift:42:16:42:16 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | -| CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | -| CommandInjection.swift:49:8:49:12 | let ...? [some:0] | CommandInjection.swift:49:12:49:12 | userControlledString | -| CommandInjection.swift:49:12:49:12 | userControlledString | CommandInjection.swift:55:27:55:27 | userControlledString | -| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:8:49:12 | let ...? [some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | -| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | CommandInjection.swift:55:2:55:2 | [post] task1 | -| CommandInjection.swift:55:20:55:47 | [...] | CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | -| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:55:20:55:47 | [...] | -| CommandInjection.swift:55:27:55:27 | userControlledString | CommandInjection.swift:58:43:58:43 | userControlledString | -| CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | -| CommandInjection.swift:58:5:58:9 | let ...? [some:0] | CommandInjection.swift:58:9:58:9 | validatedString | -| CommandInjection.swift:58:9:58:9 | validatedString | CommandInjection.swift:61:31:61:31 | validatedString | -| CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | CommandInjection.swift:58:5:58:9 | let ...? [some:0] | -| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | -| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | -| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | CommandInjection.swift:61:6:61:6 | [post] task2 | -| CommandInjection.swift:61:24:61:46 | [...] | CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | -| CommandInjection.swift:61:31:61:31 | validatedString | CommandInjection.swift:61:24:61:46 | [...] | -| CommandInjection.swift:79:8:79:12 | let ...? [some:0] | CommandInjection.swift:79:12:79:12 | userControlledString | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:94:36:94:36 | userControlledString | -| CommandInjection.swift:79:12:79:12 | userControlledString | CommandInjection.swift:95:28:95:28 | userControlledString | -| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | -| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:79:8:79:12 | let ...? [some:0] | -| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | CommandInjection.swift:94:2:94:2 | [post] task3 | -| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:94:24:94:57 | ...! | -| CommandInjection.swift:94:24:94:57 | ...! | CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | -| CommandInjection.swift:94:36:94:36 | userControlledString | CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | -| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | CommandInjection.swift:95:2:95:2 | [post] task3 | -| CommandInjection.swift:95:20:95:48 | [...] | CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:95:20:95:48 | [...] | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:99:45:99:45 | userControlledString | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:104:46:104:46 | userControlledString | -| CommandInjection.swift:95:28:95:28 | userControlledString | CommandInjection.swift:105:22:105:22 | userControlledString | -| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | CommandInjection.swift:99:2:99:2 | [post] task4 | -| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | -| CommandInjection.swift:99:45:99:45 | userControlledString | CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | -| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | CommandInjection.swift:100:2:100:2 | [post] task4 | -| CommandInjection.swift:100:20:100:56 | [...] | CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | -| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | CommandInjection.swift:100:20:100:56 | [...] | -| CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | CommandInjection.swift:104:2:104:7 | [post] ...? | -| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | -| CommandInjection.swift:104:46:104:46 | userControlledString | CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | -| CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | CommandInjection.swift:105:2:105:7 | [post] ...? | -| CommandInjection.swift:105:21:105:42 | [...] | CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | -| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:105:21:105:42 | [...] | -| CommandInjection.swift:105:22:105:22 | userControlledString | CommandInjection.swift:110:21:110:21 | userControlledString | -| CommandInjection.swift:110:21:110:21 | userControlledString | CommandInjection.swift:111:22:111:22 | userControlledString | -| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:122:42:122:42 | userControlledString | -| CommandInjection.swift:111:22:111:22 | userControlledString | CommandInjection.swift:123:75:123:75 | userControlledString | -| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:123:67:123:95 | [...] | -| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:126:35:126:35 | userControlledString | -| CommandInjection.swift:123:75:123:75 | userControlledString | CommandInjection.swift:127:70:127:70 | userControlledString | -| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:126:23:126:56 | ...! | -| CommandInjection.swift:126:35:126:35 | userControlledString | CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | -| CommandInjection.swift:127:70:127:70 | userControlledString | CommandInjection.swift:127:62:127:90 | [...] | +| CommandInjection.swift:58:22:58:33 | command | CommandInjection.swift:62:16:62:16 | command | +| CommandInjection.swift:58:22:58:33 | command [some:0] | CommandInjection.swift:62:16:62:16 | command [some:0] | +| CommandInjection.swift:62:16:62:16 | command | CommandInjection.swift:62:16:62:16 | command [some:0] | +| CommandInjection.swift:69:8:69:12 | let ...? [some:0, some:0] | CommandInjection.swift:69:12:69:12 | userControlledString [some:0] | +| CommandInjection.swift:69:8:69:12 | let ...? [some:0] | CommandInjection.swift:69:12:69:12 | userControlledString | +| CommandInjection.swift:69:12:69:12 | userControlledString | CommandInjection.swift:75:27:75:27 | userControlledString | +| CommandInjection.swift:69:12:69:12 | userControlledString [some:0] | CommandInjection.swift:75:27:75:27 | userControlledString [some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0, some:0] | CommandInjection.swift:69:8:69:12 | let ...? [some:0, some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:69:8:69:12 | let ...? [some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0, some:0] | +| CommandInjection.swift:75:2:75:2 | [post] task1 [arguments] | CommandInjection.swift:75:2:75:2 | [post] task1 | +| CommandInjection.swift:75:20:75:47 | [...] | CommandInjection.swift:75:2:75:2 | [post] task1 [arguments] | +| CommandInjection.swift:75:27:75:27 | userControlledString | CommandInjection.swift:75:20:75:47 | [...] | +| CommandInjection.swift:75:27:75:27 | userControlledString | CommandInjection.swift:78:43:78:43 | userControlledString | +| CommandInjection.swift:75:27:75:27 | userControlledString [some:0] | CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | +| CommandInjection.swift:78:5:78:9 | let ...? [some:0] | CommandInjection.swift:78:9:78:9 | validatedString | +| CommandInjection.swift:78:9:78:9 | validatedString | CommandInjection.swift:81:31:81:31 | validatedString | +| CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | CommandInjection.swift:78:5:78:9 | let ...? [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString | CommandInjection.swift:58:22:58:33 | command | +| CommandInjection.swift:78:43:78:43 | userControlledString | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | CommandInjection.swift:58:22:58:33 | command [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:81:6:81:6 | [post] task2 [arguments] | CommandInjection.swift:81:6:81:6 | [post] task2 | +| CommandInjection.swift:81:24:81:46 | [...] | CommandInjection.swift:81:6:81:6 | [post] task2 [arguments] | +| CommandInjection.swift:81:31:81:31 | validatedString | CommandInjection.swift:81:24:81:46 | [...] | +| CommandInjection.swift:99:8:99:12 | let ...? [some:0] | CommandInjection.swift:99:12:99:12 | userControlledString | +| CommandInjection.swift:99:12:99:12 | userControlledString | CommandInjection.swift:114:36:114:36 | userControlledString | +| CommandInjection.swift:99:12:99:12 | userControlledString | CommandInjection.swift:115:28:115:28 | userControlledString | +| CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:99:8:99:12 | let ...? [some:0] | +| CommandInjection.swift:114:2:114:2 | [post] task3 [executableURL] | CommandInjection.swift:114:2:114:2 | [post] task3 | +| CommandInjection.swift:114:24:114:56 | call to URL.init(string:) [some:0] | CommandInjection.swift:114:24:114:57 | ...! | +| CommandInjection.swift:114:24:114:57 | ...! | CommandInjection.swift:114:2:114:2 | [post] task3 [executableURL] | +| CommandInjection.swift:114:36:114:36 | userControlledString | CommandInjection.swift:114:24:114:56 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:115:2:115:2 | [post] task3 [arguments] | CommandInjection.swift:115:2:115:2 | [post] task3 | +| CommandInjection.swift:115:20:115:48 | [...] | CommandInjection.swift:115:2:115:2 | [post] task3 [arguments] | +| CommandInjection.swift:115:28:115:28 | userControlledString | CommandInjection.swift:115:20:115:48 | [...] | +| CommandInjection.swift:115:28:115:28 | userControlledString | CommandInjection.swift:119:45:119:45 | userControlledString | +| CommandInjection.swift:115:28:115:28 | userControlledString | CommandInjection.swift:120:28:120:36 | ... .+(_:_:) ... | +| CommandInjection.swift:115:28:115:28 | userControlledString | CommandInjection.swift:124:46:124:46 | userControlledString | +| CommandInjection.swift:115:28:115:28 | userControlledString | CommandInjection.swift:125:22:125:22 | userControlledString | +| CommandInjection.swift:119:2:119:2 | [post] task4 [executableURL] | CommandInjection.swift:119:2:119:2 | [post] task4 | +| CommandInjection.swift:119:24:119:65 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:119:2:119:2 | [post] task4 [executableURL] | +| CommandInjection.swift:119:45:119:45 | userControlledString | CommandInjection.swift:119:24:119:65 | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:120:2:120:2 | [post] task4 [arguments] | CommandInjection.swift:120:2:120:2 | [post] task4 | +| CommandInjection.swift:120:20:120:56 | [...] | CommandInjection.swift:120:2:120:2 | [post] task4 [arguments] | +| CommandInjection.swift:120:28:120:36 | ... .+(_:_:) ... | CommandInjection.swift:120:20:120:56 | [...] | +| CommandInjection.swift:124:2:124:7 | [post] ...? [executableURL] | CommandInjection.swift:124:2:124:7 | [post] ...? | +| CommandInjection.swift:124:25:124:66 | call to URL.init(fileURLWithPath:) | CommandInjection.swift:124:2:124:7 | [post] ...? [executableURL] | +| CommandInjection.swift:124:46:124:46 | userControlledString | CommandInjection.swift:124:25:124:66 | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:125:2:125:7 | [post] ...? [arguments] | CommandInjection.swift:125:2:125:7 | [post] ...? | +| CommandInjection.swift:125:21:125:42 | [...] | CommandInjection.swift:125:2:125:7 | [post] ...? [arguments] | +| CommandInjection.swift:125:22:125:22 | userControlledString | CommandInjection.swift:125:21:125:42 | [...] | +| CommandInjection.swift:125:22:125:22 | userControlledString | CommandInjection.swift:130:21:130:21 | userControlledString | +| CommandInjection.swift:130:21:130:21 | userControlledString | CommandInjection.swift:131:22:131:22 | userControlledString | +| CommandInjection.swift:131:22:131:22 | userControlledString | CommandInjection.swift:142:42:142:42 | userControlledString | +| CommandInjection.swift:131:22:131:22 | userControlledString | CommandInjection.swift:143:75:143:75 | userControlledString | +| CommandInjection.swift:143:75:143:75 | userControlledString | CommandInjection.swift:143:67:143:95 | [...] | +| CommandInjection.swift:143:75:143:75 | userControlledString | CommandInjection.swift:146:35:146:35 | userControlledString | +| CommandInjection.swift:143:75:143:75 | userControlledString | CommandInjection.swift:147:70:147:70 | userControlledString | +| CommandInjection.swift:146:23:146:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:146:23:146:56 | ...! | +| CommandInjection.swift:146:35:146:35 | userControlledString | CommandInjection.swift:146:23:146:55 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:147:70:147:70 | userControlledString | CommandInjection.swift:147:62:147:90 | [...] | nodes -| CommandInjection.swift:38:22:38:33 | command | semmle.label | command | -| CommandInjection.swift:38:22:38:33 | command [some:0] | semmle.label | command [some:0] | -| CommandInjection.swift:42:16:42:16 | command | semmle.label | command | -| CommandInjection.swift:42:16:42:16 | command [some:0] | semmle.label | command [some:0] | -| CommandInjection.swift:42:16:42:16 | command [some:0] | semmle.label | command [some:0] | -| CommandInjection.swift:49:8:49:12 | let ...? [some:0, some:0] | semmle.label | let ...? [some:0, some:0] | -| CommandInjection.swift:49:8:49:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | -| CommandInjection.swift:49:12:49:12 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:49:12:49:12 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | -| CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | -| CommandInjection.swift:55:2:55:2 | [post] task1 | semmle.label | [post] task1 | -| CommandInjection.swift:55:2:55:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | -| CommandInjection.swift:55:20:55:47 | [...] | semmle.label | [...] | -| CommandInjection.swift:55:27:55:27 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:55:27:55:27 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | -| CommandInjection.swift:58:5:58:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | -| CommandInjection.swift:58:9:58:9 | validatedString | semmle.label | validatedString | -| CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | semmle.label | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:58:43:58:43 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | -| CommandInjection.swift:61:6:61:6 | [post] task2 | semmle.label | [post] task2 | -| CommandInjection.swift:61:6:61:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | -| CommandInjection.swift:61:24:61:46 | [...] | semmle.label | [...] | -| CommandInjection.swift:61:31:61:31 | validatedString | semmle.label | validatedString | -| CommandInjection.swift:79:8:79:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | -| CommandInjection.swift:79:12:79:12 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | -| CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | -| CommandInjection.swift:94:2:94:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:94:2:94:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | -| CommandInjection.swift:94:24:94:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | -| CommandInjection.swift:94:24:94:57 | ...! | semmle.label | ...! | -| CommandInjection.swift:94:36:94:36 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:95:2:95:2 | [post] task3 | semmle.label | [post] task3 | -| CommandInjection.swift:95:2:95:2 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | -| CommandInjection.swift:95:20:95:48 | [...] | semmle.label | [...] | -| CommandInjection.swift:95:28:95:28 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:99:2:99:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:99:2:99:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | -| CommandInjection.swift:99:24:99:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | -| CommandInjection.swift:99:45:99:45 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:100:2:100:2 | [post] task4 | semmle.label | [post] task4 | -| CommandInjection.swift:100:2:100:2 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | -| CommandInjection.swift:100:20:100:56 | [...] | semmle.label | [...] | -| CommandInjection.swift:100:28:100:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | -| CommandInjection.swift:104:2:104:7 | [post] ...? | semmle.label | [post] ...? | -| CommandInjection.swift:104:2:104:7 | [post] ...? [executableURL] | semmle.label | [post] ...? [executableURL] | -| CommandInjection.swift:104:25:104:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | -| CommandInjection.swift:104:46:104:46 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:105:2:105:7 | [post] ...? | semmle.label | [post] ...? | -| CommandInjection.swift:105:2:105:7 | [post] ...? [arguments] | semmle.label | [post] ...? [arguments] | -| CommandInjection.swift:105:21:105:42 | [...] | semmle.label | [...] | -| CommandInjection.swift:105:22:105:22 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:110:21:110:21 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:111:22:111:22 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:122:42:122:42 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:123:67:123:95 | [...] | semmle.label | [...] | -| CommandInjection.swift:123:75:123:75 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:126:23:126:55 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | -| CommandInjection.swift:126:23:126:56 | ...! | semmle.label | ...! | -| CommandInjection.swift:126:35:126:35 | userControlledString | semmle.label | userControlledString | -| CommandInjection.swift:127:62:127:90 | [...] | semmle.label | [...] | -| CommandInjection.swift:127:70:127:70 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:58:22:58:33 | command | semmle.label | command | +| CommandInjection.swift:58:22:58:33 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:62:16:62:16 | command | semmle.label | command | +| CommandInjection.swift:62:16:62:16 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:62:16:62:16 | command [some:0] | semmle.label | command [some:0] | +| CommandInjection.swift:69:8:69:12 | let ...? [some:0, some:0] | semmle.label | let ...? [some:0, some:0] | +| CommandInjection.swift:69:8:69:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:69:12:69:12 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:69:12:69:12 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0, some:0] | semmle.label | call to String.init(contentsOf:) [some:0, some:0] | +| CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:75:2:75:2 | [post] task1 | semmle.label | [post] task1 | +| CommandInjection.swift:75:2:75:2 | [post] task1 [arguments] | semmle.label | [post] task1 [arguments] | +| CommandInjection.swift:75:20:75:47 | [...] | semmle.label | [...] | +| CommandInjection.swift:75:27:75:27 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:75:27:75:27 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:78:5:78:9 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:78:9:78:9 | validatedString | semmle.label | validatedString | +| CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | semmle.label | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | semmle.label | userControlledString [some:0] | +| CommandInjection.swift:81:6:81:6 | [post] task2 | semmle.label | [post] task2 | +| CommandInjection.swift:81:6:81:6 | [post] task2 [arguments] | semmle.label | [post] task2 [arguments] | +| CommandInjection.swift:81:24:81:46 | [...] | semmle.label | [...] | +| CommandInjection.swift:81:31:81:31 | validatedString | semmle.label | validatedString | +| CommandInjection.swift:99:8:99:12 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:99:12:99:12 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | +| CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:114:2:114:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:114:2:114:2 | [post] task3 [executableURL] | semmle.label | [post] task3 [executableURL] | +| CommandInjection.swift:114:24:114:56 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:114:24:114:57 | ...! | semmle.label | ...! | +| CommandInjection.swift:114:36:114:36 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:115:2:115:2 | [post] task3 | semmle.label | [post] task3 | +| CommandInjection.swift:115:2:115:2 | [post] task3 [arguments] | semmle.label | [post] task3 [arguments] | +| CommandInjection.swift:115:20:115:48 | [...] | semmle.label | [...] | +| CommandInjection.swift:115:28:115:28 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:119:2:119:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:119:2:119:2 | [post] task4 [executableURL] | semmle.label | [post] task4 [executableURL] | +| CommandInjection.swift:119:24:119:65 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:119:45:119:45 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:120:2:120:2 | [post] task4 | semmle.label | [post] task4 | +| CommandInjection.swift:120:2:120:2 | [post] task4 [arguments] | semmle.label | [post] task4 [arguments] | +| CommandInjection.swift:120:20:120:56 | [...] | semmle.label | [...] | +| CommandInjection.swift:120:28:120:36 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | +| CommandInjection.swift:124:2:124:7 | [post] ...? | semmle.label | [post] ...? | +| CommandInjection.swift:124:2:124:7 | [post] ...? [executableURL] | semmle.label | [post] ...? [executableURL] | +| CommandInjection.swift:124:25:124:66 | call to URL.init(fileURLWithPath:) | semmle.label | call to URL.init(fileURLWithPath:) | +| CommandInjection.swift:124:46:124:46 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:125:2:125:7 | [post] ...? | semmle.label | [post] ...? | +| CommandInjection.swift:125:2:125:7 | [post] ...? [arguments] | semmle.label | [post] ...? [arguments] | +| CommandInjection.swift:125:21:125:42 | [...] | semmle.label | [...] | +| CommandInjection.swift:125:22:125:22 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:130:21:130:21 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:131:22:131:22 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:142:42:142:42 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:143:67:143:95 | [...] | semmle.label | [...] | +| CommandInjection.swift:143:75:143:75 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:146:23:146:55 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:146:23:146:56 | ...! | semmle.label | ...! | +| CommandInjection.swift:146:35:146:35 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:147:62:147:90 | [...] | semmle.label | [...] | +| CommandInjection.swift:147:70:147:70 | userControlledString | semmle.label | userControlledString | subpaths -| CommandInjection.swift:58:43:58:43 | userControlledString | CommandInjection.swift:38:22:38:33 | command | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | -| CommandInjection.swift:58:43:58:43 | userControlledString [some:0] | CommandInjection.swift:38:22:38:33 | command [some:0] | CommandInjection.swift:42:16:42:16 | command [some:0] | CommandInjection.swift:58:27:58:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString | CommandInjection.swift:58:22:58:33 | command | CommandInjection.swift:62:16:62:16 | command [some:0] | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | +| CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | CommandInjection.swift:58:22:58:33 | command [some:0] | CommandInjection.swift:62:16:62:16 | command [some:0] | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | #select -| CommandInjection.swift:55:2:55:2 | [post] task1 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:55:2:55:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:61:6:61:6 | [post] task2 | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | CommandInjection.swift:61:6:61:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:49:40:49:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:94:2:94:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:94:2:94:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:95:2:95:2 | [post] task3 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:95:2:95:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:99:2:99:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:99:2:99:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:100:2:100:2 | [post] task4 | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:100:2:100:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:104:2:104:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:104:2:104:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:105:2:105:7 | [post] ...? | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:105:2:105:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:122:42:122:42 | userControlledString | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:122:42:122:42 | userControlledString | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:123:67:123:95 | [...] | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:123:67:123:95 | [...] | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:126:23:126:56 | ...! | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:126:23:126:56 | ...! | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | -| CommandInjection.swift:127:62:127:90 | [...] | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | CommandInjection.swift:127:62:127:90 | [...] | This command depends on a $@. | CommandInjection.swift:79:40:79:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:75:2:75:2 | [post] task1 | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | CommandInjection.swift:75:2:75:2 | [post] task1 | This command depends on a $@. | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:81:6:81:6 | [post] task2 | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | CommandInjection.swift:81:6:81:6 | [post] task2 | This command depends on a $@. | CommandInjection.swift:69:40:69:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:114:2:114:2 | [post] task3 | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:114:2:114:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:115:2:115:2 | [post] task3 | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:115:2:115:2 | [post] task3 | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:119:2:119:2 | [post] task4 | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:119:2:119:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:120:2:120:2 | [post] task4 | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:120:2:120:2 | [post] task4 | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:124:2:124:7 | [post] ...? | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:124:2:124:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:125:2:125:7 | [post] ...? | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:125:2:125:7 | [post] ...? | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:142:42:142:42 | userControlledString | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:142:42:142:42 | userControlledString | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:143:67:143:95 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:143:67:143:95 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:146:23:146:56 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:146:23:146:56 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:147:62:147:90 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:147:62:147:90 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift index 73f7872e3e42..0ce7c4230340 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -33,6 +33,26 @@ extension String { } } +class NSUserScriptTask : NSObject { + typealias CompletionHandler = @Sendable (Error?) -> Void + + init(url: URL) throws {} + func execute(completionHandler handler: NSUserScriptTask.CompletionHandler? = nil) { } +} + +class NSUserUnixTask : NSUserScriptTask { + func execute(withArguments arguments: [String]?, completionHandler handler: NSUserScriptTask.CompletionHandler? = nil) { } +} + +protocol NSSecureCoding { +} + +class NSUserAutomatorTask : NSUserScriptTask { + func execute(withInput input: NSSecureCoding?, completionHandler handler: NSUserScriptTask.CompletionHandler? = nil) { } + + var variables: [String: Any]? { get { return nil } set { } } +} + // --- tests --- func validateCommand(_ command: String) -> String? { @@ -125,4 +145,17 @@ func testCommandInjectionMore(mySafeString: String) { _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", mySafeString]) // GOOD _ = try? Process.run(URL(string: userControlledString)!, arguments: ["abc", mySafeString]) // BAD _ = try? Process.run(URL(string: mySafeString)!, arguments: ["abc", userControlledString]) // BAD + + let task8 = try! NSUserScriptTask(url: URL(string: mySafeString)!) // GOOD + task8.execute() + + let task9 = try! NSUserScriptTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] + task9.execute() + + let task10 = try! NSUserUnixTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] + task10.execute(withArguments: [userControlledString]) // BAD [NOT DETECTED] + + let task11 = try! NSUserAutomatorTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] + task11.variables = ["abc": userControlledString] // BAD [NOT DETECTED] + task11.execute(withInput: nil) } From 416b731870672f0ffc1358fec6fe48df6e2fff2f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:26:00 +0100 Subject: [PATCH 08/11] Swift: Model NSUserScriptTask sinks. --- .../security/CommandInjectionExtensions.qll | 2 + .../CWE-078/CommandInjection.expected | 40 +++++++++++++++++++ .../Security/CWE-078/CommandInjection.swift | 8 ++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll index a0672bdb187a..5b1cc065ec28 100644 --- a/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll +++ b/swift/ql/lib/codeql/swift/security/CommandInjectionExtensions.qll @@ -64,6 +64,8 @@ private class CommandInjectionSinks extends SinkModelCsv { ";Process;true;standardOutput;;;PostUpdate;command-injection", ";Process;true;currentDirectoryPath;;;PostUpdate;command-injection", ";Process;true;launchPath;;;PostUpdate;command-injection", + ";NSUserScriptTask;true;init(url:);;;Argument[0];command-injection", + ";NSUserUnixTask;true;execute(withArguments:completionHandler:);;;Argument[0];command-injection", ] } } diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index e79dab71b3ab..8c9bfed20789 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -63,6 +63,23 @@ edges | CommandInjection.swift:146:23:146:55 | call to URL.init(string:) [some:0] | CommandInjection.swift:146:23:146:56 | ...! | | CommandInjection.swift:146:35:146:35 | userControlledString | CommandInjection.swift:146:23:146:55 | call to URL.init(string:) [some:0] | | CommandInjection.swift:147:70:147:70 | userControlledString | CommandInjection.swift:147:62:147:90 | [...] | +| CommandInjection.swift:147:70:147:70 | userControlledString | CommandInjection.swift:152:53:152:53 | userControlledString | +| CommandInjection.swift:147:70:147:70 | userControlledString | CommandInjection.swift:155:52:155:52 | userControlledString | +| CommandInjection.swift:147:70:147:70 | userControlledString | CommandInjection.swift:156:33:156:33 | userControlledString | +| CommandInjection.swift:152:41:152:73 | call to URL.init(string:) [some:0] | CommandInjection.swift:152:41:152:74 | ...! | +| CommandInjection.swift:152:53:152:53 | userControlledString | CommandInjection.swift:152:41:152:73 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:155:40:155:72 | call to URL.init(string:) [some:0] | CommandInjection.swift:155:40:155:73 | ...! | +| CommandInjection.swift:155:40:155:72 | call to URL.init(string:) [some:0] | CommandInjection.swift:155:40:155:73 | ...! | +| CommandInjection.swift:155:40:155:73 | ...! | file://:0:0:0:0 | url | +| CommandInjection.swift:155:52:155:52 | userControlledString | CommandInjection.swift:155:40:155:72 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:156:33:156:33 | userControlledString | CommandInjection.swift:156:32:156:53 | [...] | +| CommandInjection.swift:156:33:156:33 | userControlledString | CommandInjection.swift:158:57:158:57 | userControlledString | +| CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | CommandInjection.swift:158:45:158:78 | ...! | +| CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | CommandInjection.swift:158:45:158:78 | ...! | +| CommandInjection.swift:158:45:158:78 | ...! | file://:0:0:0:0 | url | +| CommandInjection.swift:158:57:158:57 | userControlledString | CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | +| file://:0:0:0:0 | url | file://:0:0:0:0 | url | +| file://:0:0:0:0 | url | file://:0:0:0:0 | url | nodes | CommandInjection.swift:58:22:58:33 | command | semmle.label | command | | CommandInjection.swift:58:22:58:33 | command [some:0] | semmle.label | command [some:0] | @@ -129,6 +146,23 @@ nodes | CommandInjection.swift:146:35:146:35 | userControlledString | semmle.label | userControlledString | | CommandInjection.swift:147:62:147:90 | [...] | semmle.label | [...] | | CommandInjection.swift:147:70:147:70 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:152:41:152:73 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:152:41:152:74 | ...! | semmle.label | ...! | +| CommandInjection.swift:152:53:152:53 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:155:40:155:72 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:155:40:155:73 | ...! | semmle.label | ...! | +| CommandInjection.swift:155:40:155:73 | ...! | semmle.label | ...! | +| CommandInjection.swift:155:52:155:52 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:156:32:156:53 | [...] | semmle.label | [...] | +| CommandInjection.swift:156:33:156:33 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | +| CommandInjection.swift:158:45:158:78 | ...! | semmle.label | ...! | +| CommandInjection.swift:158:45:158:78 | ...! | semmle.label | ...! | +| CommandInjection.swift:158:57:158:57 | userControlledString | semmle.label | userControlledString | +| file://:0:0:0:0 | url | semmle.label | url | +| file://:0:0:0:0 | url | semmle.label | url | +| file://:0:0:0:0 | url | semmle.label | url | +| file://:0:0:0:0 | url | semmle.label | url | subpaths | CommandInjection.swift:78:43:78:43 | userControlledString | CommandInjection.swift:58:22:58:33 | command | CommandInjection.swift:62:16:62:16 | command [some:0] | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | | CommandInjection.swift:78:43:78:43 | userControlledString [some:0] | CommandInjection.swift:58:22:58:33 | command [some:0] | CommandInjection.swift:62:16:62:16 | command [some:0] | CommandInjection.swift:78:27:78:63 | call to validateCommand(_:) [some:0] | @@ -145,3 +179,9 @@ subpaths | CommandInjection.swift:143:67:143:95 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:143:67:143:95 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:146:23:146:56 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:146:23:146:56 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:147:62:147:90 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:147:62:147:90 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:152:41:152:74 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:152:41:152:74 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:155:40:155:73 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:155:40:155:73 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:156:32:156:53 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:156:32:156:53 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:158:45:158:78 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:158:45:158:78 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| file://:0:0:0:0 | url | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | file://:0:0:0:0 | url | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| file://:0:0:0:0 | url | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | file://:0:0:0:0 | url | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift index 0ce7c4230340..9c7827fe009d 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -149,13 +149,13 @@ func testCommandInjectionMore(mySafeString: String) { let task8 = try! NSUserScriptTask(url: URL(string: mySafeString)!) // GOOD task8.execute() - let task9 = try! NSUserScriptTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] + let task9 = try! NSUserScriptTask(url: URL(string: userControlledString)!) // BAD task9.execute() - let task10 = try! NSUserUnixTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] - task10.execute(withArguments: [userControlledString]) // BAD [NOT DETECTED] + let task10 = try! NSUserUnixTask(url: URL(string: userControlledString)!) // BAD + task10.execute(withArguments: [userControlledString]) // BAD - let task11 = try! NSUserAutomatorTask(url: URL(string: userControlledString)!) // BAD [NOT DETECTED] + let task11 = try! NSUserAutomatorTask(url: URL(string: userControlledString)!) // BAD task11.variables = ["abc": userControlledString] // BAD [NOT DETECTED] task11.execute(withInput: nil) } From 4c8accd5ba24f00d4133221f20a62e6098dd6b08 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:13:24 +0100 Subject: [PATCH 09/11] Swift: Add a few more test cases. --- .../CWE-078/CommandInjection.expected | 85 +++++++++++++++++++ .../Security/CWE-078/CommandInjection.swift | 37 ++++++++ 2 files changed, 122 insertions(+) diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected index 8c9bfed20789..a015cb69b644 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.expected @@ -78,6 +78,45 @@ edges | CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | CommandInjection.swift:158:45:158:78 | ...! | | CommandInjection.swift:158:45:158:78 | ...! | file://:0:0:0:0 | url | | CommandInjection.swift:158:57:158:57 | userControlledString | CommandInjection.swift:158:45:158:77 | call to URL.init(string:) [some:0] | +| CommandInjection.swift:172:3:172:3 | newValue | CommandInjection.swift:173:19:173:19 | newValue | +| CommandInjection.swift:172:3:172:3 | newValue | CommandInjection.swift:174:20:174:20 | newValue | +| CommandInjection.swift:172:3:172:3 | newValue | CommandInjection.swift:175:19:175:19 | newValue | +| CommandInjection.swift:173:4:173:4 | [post] getter for .p1 [arguments] | CommandInjection.swift:173:4:173:4 | [post] getter for .p1 | +| CommandInjection.swift:173:19:173:19 | newValue | CommandInjection.swift:173:4:173:4 | [post] getter for .p1 [arguments] | +| CommandInjection.swift:174:4:174:6 | [post] ...! [arguments] | CommandInjection.swift:174:4:174:6 | [post] ...! | +| CommandInjection.swift:174:20:174:20 | newValue | CommandInjection.swift:174:4:174:6 | [post] ...! [arguments] | +| CommandInjection.swift:175:4:175:4 | [post] ...! [arguments] | CommandInjection.swift:175:4:175:4 | [post] ...! | +| CommandInjection.swift:175:19:175:19 | newValue | CommandInjection.swift:175:4:175:4 | [post] ...! [arguments] | +| CommandInjection.swift:180:9:180:13 | let ...? [some:0] | CommandInjection.swift:180:13:180:13 | userControlledString | +| CommandInjection.swift:180:13:180:13 | userControlledString | CommandInjection.swift:184:19:184:19 | userControlledString | +| CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) [some:0] | CommandInjection.swift:180:9:180:13 | let ...? [some:0] | +| CommandInjection.swift:184:18:184:39 | [...] | CommandInjection.swift:186:18:186:18 | tainted1 | +| CommandInjection.swift:184:18:184:39 | [...] | CommandInjection.swift:187:19:187:19 | tainted1 | +| CommandInjection.swift:184:18:184:39 | [...] | CommandInjection.swift:188:18:188:18 | tainted1 | +| CommandInjection.swift:184:19:184:19 | userControlledString | CommandInjection.swift:184:18:184:39 | [...] | +| CommandInjection.swift:184:19:184:19 | userControlledString | CommandInjection.swift:190:31:190:31 | userControlledString | +| CommandInjection.swift:186:3:186:3 | [post] getter for .p1 [arguments] | CommandInjection.swift:186:3:186:3 | [post] getter for .p1 | +| CommandInjection.swift:186:18:186:18 | tainted1 | CommandInjection.swift:186:3:186:3 | [post] getter for .p1 [arguments] | +| CommandInjection.swift:186:18:186:18 | tainted1 | CommandInjection.swift:187:19:187:19 | tainted1 | +| CommandInjection.swift:186:18:186:18 | tainted1 | CommandInjection.swift:188:18:188:18 | tainted1 | +| CommandInjection.swift:187:3:187:5 | [post] ...! [arguments] | CommandInjection.swift:187:3:187:5 | [post] ...! | +| CommandInjection.swift:187:19:187:19 | tainted1 | CommandInjection.swift:187:3:187:5 | [post] ...! [arguments] | +| CommandInjection.swift:187:19:187:19 | tainted1 | CommandInjection.swift:188:18:188:18 | tainted1 | +| CommandInjection.swift:188:3:188:3 | [post] ...! [arguments] | CommandInjection.swift:188:3:188:3 | [post] ...! | +| CommandInjection.swift:188:18:188:18 | tainted1 | CommandInjection.swift:188:3:188:3 | [post] ...! [arguments] | +| CommandInjection.swift:190:30:190:51 | [...] | CommandInjection.swift:192:18:192:18 | tainted2 | +| CommandInjection.swift:190:30:190:51 | [...] | CommandInjection.swift:193:19:193:19 | tainted2 | +| CommandInjection.swift:190:30:190:51 | [...] | CommandInjection.swift:194:18:194:18 | tainted2 | +| CommandInjection.swift:190:30:190:51 | [...] | CommandInjection.swift:196:13:196:13 | tainted2 | +| CommandInjection.swift:190:31:190:31 | userControlledString | CommandInjection.swift:190:30:190:51 | [...] | +| CommandInjection.swift:192:3:192:3 | [post] getter for .p1 [arguments] | CommandInjection.swift:192:3:192:3 | [post] getter for .p1 | +| CommandInjection.swift:192:18:192:18 | tainted2 | CommandInjection.swift:192:3:192:3 | [post] getter for .p1 [arguments] | +| CommandInjection.swift:193:3:193:5 | [post] ...! [arguments] | CommandInjection.swift:193:3:193:5 | [post] ...! | +| CommandInjection.swift:193:19:193:19 | tainted2 | CommandInjection.swift:193:3:193:5 | [post] ...! [arguments] | +| CommandInjection.swift:194:3:194:3 | [post] ...! [arguments] | CommandInjection.swift:194:3:194:3 | [post] ...! | +| CommandInjection.swift:194:18:194:18 | tainted2 | CommandInjection.swift:194:3:194:3 | [post] ...! [arguments] | +| CommandInjection.swift:196:13:196:13 | tainted2 | CommandInjection.swift:172:3:172:3 | newValue | | file://:0:0:0:0 | url | file://:0:0:0:0 | url | | file://:0:0:0:0 | url | file://:0:0:0:0 | url | nodes @@ -159,6 +198,43 @@ nodes | CommandInjection.swift:158:45:158:78 | ...! | semmle.label | ...! | | CommandInjection.swift:158:45:158:78 | ...! | semmle.label | ...! | | CommandInjection.swift:158:57:158:57 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:172:3:172:3 | newValue | semmle.label | newValue | +| CommandInjection.swift:173:4:173:4 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | +| CommandInjection.swift:173:4:173:4 | [post] getter for .p1 [arguments] | semmle.label | [post] getter for .p1 [arguments] | +| CommandInjection.swift:173:19:173:19 | newValue | semmle.label | newValue | +| CommandInjection.swift:174:4:174:6 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:174:4:174:6 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:174:20:174:20 | newValue | semmle.label | newValue | +| CommandInjection.swift:175:4:175:4 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:175:4:175:4 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:175:19:175:19 | newValue | semmle.label | newValue | +| CommandInjection.swift:180:9:180:13 | let ...? [some:0] | semmle.label | let ...? [some:0] | +| CommandInjection.swift:180:13:180:13 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) | +| CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) [some:0] | semmle.label | call to String.init(contentsOf:) [some:0] | +| CommandInjection.swift:184:18:184:39 | [...] | semmle.label | [...] | +| CommandInjection.swift:184:19:184:19 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:186:3:186:3 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | +| CommandInjection.swift:186:3:186:3 | [post] getter for .p1 [arguments] | semmle.label | [post] getter for .p1 [arguments] | +| CommandInjection.swift:186:18:186:18 | tainted1 | semmle.label | tainted1 | +| CommandInjection.swift:187:3:187:5 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:187:3:187:5 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:187:19:187:19 | tainted1 | semmle.label | tainted1 | +| CommandInjection.swift:188:3:188:3 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:188:3:188:3 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:188:18:188:18 | tainted1 | semmle.label | tainted1 | +| CommandInjection.swift:190:30:190:51 | [...] | semmle.label | [...] | +| CommandInjection.swift:190:31:190:31 | userControlledString | semmle.label | userControlledString | +| CommandInjection.swift:192:3:192:3 | [post] getter for .p1 | semmle.label | [post] getter for .p1 | +| CommandInjection.swift:192:3:192:3 | [post] getter for .p1 [arguments] | semmle.label | [post] getter for .p1 [arguments] | +| CommandInjection.swift:192:18:192:18 | tainted2 | semmle.label | tainted2 | +| CommandInjection.swift:193:3:193:5 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:193:3:193:5 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:193:19:193:19 | tainted2 | semmle.label | tainted2 | +| CommandInjection.swift:194:3:194:3 | [post] ...! | semmle.label | [post] ...! | +| CommandInjection.swift:194:3:194:3 | [post] ...! [arguments] | semmle.label | [post] ...! [arguments] | +| CommandInjection.swift:194:18:194:18 | tainted2 | semmle.label | tainted2 | +| CommandInjection.swift:196:13:196:13 | tainted2 | semmle.label | tainted2 | | file://:0:0:0:0 | url | semmle.label | url | | file://:0:0:0:0 | url | semmle.label | url | | file://:0:0:0:0 | url | semmle.label | url | @@ -183,5 +259,14 @@ subpaths | CommandInjection.swift:155:40:155:73 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:155:40:155:73 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:156:32:156:53 | [...] | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:156:32:156:53 | [...] | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | | CommandInjection.swift:158:45:158:78 | ...! | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | CommandInjection.swift:158:45:158:78 | ...! | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:173:4:173:4 | [post] getter for .p1 | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:173:4:173:4 | [post] getter for .p1 | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:174:4:174:6 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:174:4:174:6 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:175:4:175:4 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:175:4:175:4 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:186:3:186:3 | [post] getter for .p1 | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:186:3:186:3 | [post] getter for .p1 | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:187:3:187:5 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:187:3:187:5 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:188:3:188:3 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:188:3:188:3 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:192:3:192:3 | [post] getter for .p1 | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:192:3:192:3 | [post] getter for .p1 | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:193:3:193:5 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:193:3:193:5 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | +| CommandInjection.swift:194:3:194:3 | [post] ...! | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | CommandInjection.swift:194:3:194:3 | [post] ...! | This command depends on a $@. | CommandInjection.swift:180:41:180:95 | call to String.init(contentsOf:) | user-provided value | | file://:0:0:0:0 | url | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | file://:0:0:0:0 | url | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | | file://:0:0:0:0 | url | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | file://:0:0:0:0 | url | This command depends on a $@. | CommandInjection.swift:99:40:99:94 | call to String.init(contentsOf:) | user-provided value | diff --git a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift index 9c7827fe009d..c1facad1305b 100644 --- a/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift +++ b/swift/ql/test/query-tests/Security/CWE-078/CommandInjection.swift @@ -159,3 +159,40 @@ func testCommandInjectionMore(mySafeString: String) { task11.variables = ["abc": userControlledString] // BAD [NOT DETECTED] task11.execute(withInput: nil) } + +struct MyClass { + let p1 : Process + let p2 : Process? + let p3 : Process! + + var myValue: [String]? { + get { + return nil + } + set { + p1.arguments = newValue // BAD + p2!.arguments = newValue // BAD + p3.arguments = newValue // BAD + } + } + + mutating func myFunc() { + guard let userControlledString = try? String(contentsOf: URL(string: "http://example.com/")!) else { + return + } + + let tainted1 = [userControlledString] + + p1.arguments = tainted1 // BAD + p2!.arguments = tainted1 // BAD + p3.arguments = tainted1 // BAD + + let tainted2 : [String]? = [userControlledString] + + p1.arguments = tainted2 // BAD + p2!.arguments = tainted2 // BAD + p3.arguments = tainted2 // BAD + + myValue = tainted2 + } +} From a73354d0b3d29a59f1822b9bc789dff5662b3b5c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 7 Aug 2023 20:14:07 +0100 Subject: [PATCH 10/11] Swift: Accept test failures. --- .../CWE-079/UnsafeWebViewFetch.expected | 50 +------------------ 1 file changed, 2 insertions(+), 48 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected index a4fc0d173128..fb06adf5fb08 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected @@ -17,27 +17,13 @@ edges | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:138:47:138:56 | ...! | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:153:85:153:94 | ...! | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:154:86:154:95 | ...! | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:153:85:153:85 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:154:86:154:86 | remoteURL [some:0] | -| UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:140:47:140:57 | ...! | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:141:48:141:58 | ...! | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | +| UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | UnsafeWebViewFetch.swift:138:47:138:56 | ...! | | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | -| UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:140:47:140:57 | ...! | -| UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:141:48:141:58 | ...! | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:152:15:152:15 | remoteData | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | @@ -52,27 +38,13 @@ edges | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:185:47:185:56 | ...! | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:200:90:200:99 | ...! | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | UnsafeWebViewFetch.swift:201:91:201:100 | ...! | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:200:90:200:90 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:201:91:201:91 | remoteURL [some:0] | -| UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:187:47:187:57 | ...! | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | UnsafeWebViewFetch.swift:188:48:188:58 | ...! | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | +| UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | UnsafeWebViewFetch.swift:185:47:185:56 | ...! | | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | -| UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:187:47:187:57 | ...! | -| UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:188:48:188:58 | ...! | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:199:15:199:15 | remoteData | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | @@ -94,12 +66,8 @@ nodes | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | semmle.label | "..." | -| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | semmle.label | remoteString | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) | semmle.label | call to URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | semmle.label | call to URL.init(string:relativeTo:) [some:0] | -| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL | semmle.label | remoteURL | | UnsafeWebViewFetch.swift:135:25:135:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:137:25:137:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | @@ -107,11 +75,7 @@ nodes | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | semmle.label | ...! | -| UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:140:47:140:57 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | semmle.label | remoteString | -| UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:141:48:141:58 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | semmle.label | .utf8 | | UnsafeWebViewFetch.swift:152:15:152:15 | remoteData | semmle.label | remoteData | @@ -125,12 +89,8 @@ nodes | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | semmle.label | ... .+(_:_:) ... | | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | semmle.label | "..." | -| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) | semmle.label | call to URL.init(string:) | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | semmle.label | remoteString | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) | semmle.label | call to URL.init(string:relativeTo:) | -| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | semmle.label | call to URL.init(string:relativeTo:) [some:0] | -| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL | semmle.label | remoteURL | | UnsafeWebViewFetch.swift:182:25:182:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:184:25:184:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | @@ -138,11 +98,7 @@ nodes | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | semmle.label | ...! | -| UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:187:47:187:57 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | semmle.label | remoteString | -| UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | -| UnsafeWebViewFetch.swift:188:48:188:58 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | semmle.label | .utf8 | | UnsafeWebViewFetch.swift:199:15:199:15 | remoteData | semmle.label | remoteData | @@ -164,13 +120,11 @@ subpaths | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | -| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | Tainted data is used in a WebView fetch without restricting the base URL. | From b2d3d465f06958455979cf658ddd546e79875084 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:25:36 +0100 Subject: [PATCH 11/11] Swift: Add more missing details to the URL model (along with a change from the SetContent PR, this fixes the test failures we were getting). --- .../swift/frameworks/StandardLibrary/Url.qll | 27 +++++++++++-------- .../CWE-079/UnsafeWebViewFetch.expected | 26 ++++++++++++++++++ 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll index d86c004b1b24..a24a394dd0f4 100644 --- a/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll +++ b/swift/ql/lib/codeql/swift/frameworks/StandardLibrary/Url.qll @@ -86,28 +86,32 @@ private class UrlSummaries extends SummaryModelCsv { row = [ ";URL;true;init(string:);(String);;Argument[0];ReturnValue.OptionalSome;taint", - ";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0..1];ReturnValue.OptionalSome;taint", + ";URL;true;init(string:relativeTo:);(String,URL?);;Argument[0];ReturnValue.OptionalSome;taint", + ";URL;true;init(string:relativeTo:);(String,URL?);;Argument[1].OptionalSome;ReturnValue.OptionalSome;taint", ";URL;true;init(fileURLWithPath:);;;Argument[0];ReturnValue;taint", ";URL;true;init(fileURLWithPath:isDirectory:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(fileURLWithPath:relativeTo:);;;Argument[0..1];ReturnValue;taint", + ";URL;true;init(fileURLWithPath:relativeTo:);;;Argument[0];ReturnValue;taint", + ";URL;true;init(fileURLWithPath:relativeTo:);;;Argument[1].OptionalSome;ReturnValue;taint", ";URL;true;init(fileURLWithPath:isDirectory:relativeTo:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(fileURLWithPath:isDirectory:relativeTo:);;;Argument[2];ReturnValue;taint", + ";URL;true;init(fileURLWithPath:isDirectory:relativeTo:);;;Argument[2].OptionalSome;ReturnValue;taint", ";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[2];ReturnValue;taint", + ";URL;true;init(fileURLWithFileSystemRepresentation:isDirectory:relativeTo:);;;Argument[2].OptionalSome;ReturnValue;taint", ";URL;true;init(fileReferenceLiteralResourceName:);;;Argument[0];ReturnValue;taint", ";URL;true;init(_:);;;Argument[0];ReturnValue.OptionalSome;taint", ";URL;true;init(_:isDirectory:);;;Argument[0];ReturnValue.OptionalSome;taint", ";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[2];ReturnValue;taint", + ";URL;true;init(resolvingBookmarkData:options:relativeTo:bookmarkDataIsStale:);;;Argument[2].OptionalSome;ReturnValue;taint", ";URL;true;init(resolvingAliasFileAt:options:);;;Argument[0];ReturnValue;taint", ";URL;true;init(resource:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[0..1];ReturnValue;taint", + ";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[0];ReturnValue;taint", + ";URL;true;init(dataRepresentation:relativeTo:isAbsolute:);;;Argument[1].OptionalSome;ReturnValue;taint", ";URL;true;init(_:strategy:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(filePath:directoryHint:);;;Argument[0];ReturnValue;taint", + ";URL;true;init(filePath:directoryHint:);;;Argument[0];ReturnValue.OptionalSome;taint", ";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[0];ReturnValue;taint", - ";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[2];ReturnValue;taint", - ";URL;true;init(for:in:appropriateFor:create:);;;Argument[0..2];ReturnValue;taint", - ";URL;true;init(string:encodingInvalidCharacters:);;;Argument[0];ReturnValue;taint", + ";URL;true;init(filePath:directoryHint:relativeTo:);;;Argument[2].OptionalSome;ReturnValue;taint", + ";URL;true;init(for:in:appropriateFor:create:);;;Argument[0..1];ReturnValue;taint", + ";URL;true;init(for:in:appropriateFor:create:);;;Argument[2].OptionalSome;ReturnValue;taint", + ";URL;true;init(string:encodingInvalidCharacters:);;;Argument[0];ReturnValue.OptionalSome;taint", ";URL;true;resourceValues(forKeys:);;;Argument[-1];ReturnValue;taint", ";URL;true;setResourceValues(_:);;;Argument[0];Argument[-1];taint", ";URL;true;setTemporaryResourceValue(_:forKey:);;;Argument[-1..0];Argument[-1];taint", @@ -125,7 +129,8 @@ private class UrlSummaries extends SummaryModelCsv { ";URL;true;deletingLastPathComponent();;;Argument[-1];ReturnValue;taint", ";URL;true;deletingPathExtension();;;Argument[-1];ReturnValue;taint", ";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[-1];ReturnValue;taint", - ";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[1..2];ReturnValue;taint", + ";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[1].OptionalSome.CollectionElement;ReturnValue;taint", + ";URL;true;bookmarkData(options:includingResourceValuesForKeys:relativeTo:);;;Argument[2].OptionalSome;ReturnValue;taint", ";URL;true;bookmarkData(withContentsOf:);;;Argument[0];ReturnValue;taint", ";URL;true;resourceValues(forKeys:fromBookmarkData:);;;Argument[1];ReturnValue;taint", ";URL;true;promisedItemResourceValues(forKeys:);;;Argument[-1];ReturnValue;taint", diff --git a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected index fb06adf5fb08..66356d313493 100644 --- a/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected +++ b/swift/ql/test/query-tests/Security/CWE-079/UnsafeWebViewFetch.expected @@ -17,13 +17,19 @@ edges | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | | UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | +| UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:153:85:153:85 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:154:86:154:86 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | +| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL [some:0] | UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | UnsafeWebViewFetch.swift:138:47:138:56 | ...! | | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | +| UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:140:47:140:57 | ...! | +| UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:141:48:141:58 | ...! | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:152:15:152:15 | remoteData | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | @@ -38,13 +44,19 @@ edges | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | | UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | +| UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:200:90:200:90 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | UnsafeWebViewFetch.swift:201:91:201:91 | remoteURL [some:0] | | UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | +| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL [some:0] | UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | UnsafeWebViewFetch.swift:185:47:185:56 | ...! | | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | +| UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:187:47:187:57 | ...! | +| UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | UnsafeWebViewFetch.swift:188:48:188:58 | ...! | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:199:15:199:15 | remoteData | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | @@ -68,6 +80,8 @@ nodes | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | semmle.label | "..." | | UnsafeWebViewFetch.swift:131:18:131:42 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:131:30:131:30 | remoteString | semmle.label | remoteString | +| UnsafeWebViewFetch.swift:132:19:132:61 | call to URL.init(string:relativeTo:) [some:0] | semmle.label | call to URL.init(string:relativeTo:) [some:0] | +| UnsafeWebViewFetch.swift:132:52:132:52 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:135:25:135:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:137:25:137:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:138:47:138:47 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | @@ -75,7 +89,11 @@ nodes | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:139:48:139:48 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:139:48:139:57 | ...! | semmle.label | ...! | +| UnsafeWebViewFetch.swift:140:47:140:47 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:140:47:140:57 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | semmle.label | remoteString | +| UnsafeWebViewFetch.swift:141:48:141:48 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:141:48:141:58 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:150:19:150:41 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | UnsafeWebViewFetch.swift:150:24:150:37 | .utf8 | semmle.label | .utf8 | | UnsafeWebViewFetch.swift:152:15:152:15 | remoteData | semmle.label | remoteData | @@ -91,6 +109,8 @@ nodes | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | semmle.label | "..." | | UnsafeWebViewFetch.swift:178:18:178:42 | call to URL.init(string:) [some:0] | semmle.label | call to URL.init(string:) [some:0] | | UnsafeWebViewFetch.swift:178:30:178:30 | remoteString | semmle.label | remoteString | +| UnsafeWebViewFetch.swift:179:19:179:61 | call to URL.init(string:relativeTo:) [some:0] | semmle.label | call to URL.init(string:relativeTo:) [some:0] | +| UnsafeWebViewFetch.swift:179:52:179:52 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:182:25:182:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:184:25:184:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:185:47:185:47 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | @@ -98,7 +118,11 @@ nodes | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | semmle.label | remoteString | | UnsafeWebViewFetch.swift:186:48:186:48 | remoteURL [some:0] | semmle.label | remoteURL [some:0] | | UnsafeWebViewFetch.swift:186:48:186:57 | ...! | semmle.label | ...! | +| UnsafeWebViewFetch.swift:187:47:187:47 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:187:47:187:57 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | semmle.label | remoteString | +| UnsafeWebViewFetch.swift:188:48:188:48 | remoteURL2 [some:0] | semmle.label | remoteURL2 [some:0] | +| UnsafeWebViewFetch.swift:188:48:188:58 | ...! | semmle.label | ...! | | UnsafeWebViewFetch.swift:197:19:197:41 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | | UnsafeWebViewFetch.swift:197:24:197:37 | .utf8 | semmle.label | .utf8 | | UnsafeWebViewFetch.swift:199:15:199:15 | remoteData | semmle.label | remoteData | @@ -120,11 +144,13 @@ subpaths | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:124:25:124:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:154:15:154:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:171:25:171:51 | ... .+(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. | | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | +| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:201:15:201:15 | remoteData | Tainted data is used in a WebView fetch with a tainted base URL. | | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | UnsafeWebViewFetch.swift:94:14:94:37 | call to String.init(contentsOf:) | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | Tainted data is used in a WebView fetch without restricting the base URL. |