Skip to content

Commit 0cd2efc

Browse files
committed
Swift: CleartextTransmission query.
1 parent dacb7f5 commit 0cd2efc

File tree

4 files changed

+81
-5
lines changed

4 files changed

+81
-5
lines changed

swift/ql/src/queries/Security/CWE-311/CleartextTransmission.ql

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,70 @@
1111
*/
1212

1313
import swift
14+
import codeql.swift.security.SensitiveExprs
1415
import codeql.swift.dataflow.DataFlow
16+
import codeql.swift.dataflow.TaintTracking
1517
import DataFlow::PathGraph
1618

17-
select "TODO"
19+
/**
20+
* An `Expr` that is transmitted over a network.
21+
*/
22+
abstract class Transmitted extends Expr { }
23+
24+
/**
25+
* An `Expr` that is transmitted with `NWConnection.send`.
26+
*/
27+
class NWConnectionSend extends Transmitted {
28+
NWConnectionSend() {
29+
// `content` arg to `NWConnection.send` is a sink
30+
exists(ClassDecl c, AbstractFunctionDecl f, CallExpr call |
31+
c.getName() = "NWConnection" and
32+
c.getAMember() = f and
33+
f.getName() = "send(content:contentContext:isComplete:completion:)" and
34+
call.getFunction().(ApplyExpr).getStaticTarget() = f and
35+
call.getArgument(0).getExpr() = this
36+
)
37+
}
38+
}
39+
40+
/**
41+
* An `Expr` that is used to form a `URL`. Such expressions are very likely to
42+
* be transmitted over a network, because that's what URLs are for.
43+
*/
44+
class URL extends Transmitted {
45+
URL() {
46+
// `string` arg in `URL.init` is a sink
47+
// (we assume here that the URL goes on to be used in a network operation)
48+
exists(ClassDecl c, AbstractFunctionDecl f, CallExpr call |
49+
c.getName() = "URL" and
50+
c.getAMember() = f and
51+
f.getName() = ["init(string:)", "init(string:relativeTo:)"] and
52+
call.getFunction().(ApplyExpr).getStaticTarget() = f and
53+
call.getArgument(0).getExpr() = this
54+
)
55+
}
56+
}
57+
58+
/**
59+
* A taint configuration from sensitive information to expressions that are
60+
* transmitted over a network.
61+
*/
62+
class CleartextTransmissionConfig extends TaintTracking::Configuration {
63+
CleartextTransmissionConfig() { this = "CleartextTransmissionConfig" }
64+
65+
override predicate isSource(DataFlow::Node node) {
66+
exists(SensitiveExpr e |
67+
node.asExpr() = e and
68+
not e.isProbablySafe()
69+
)
70+
}
71+
72+
override predicate isSink(DataFlow::Node node) { node.asExpr() instanceof Transmitted }
73+
}
74+
75+
from CleartextTransmissionConfig config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
76+
where config.hasFlowPath(sourceNode, sinkNode)
77+
select sinkNode.getNode(), sourceNode, sinkNode,
78+
"This operation transmits '" + sinkNode.getNode().toString() +
79+
"', which may contain unencrypted sensitive data from $@", sourceNode,
80+
sourceNode.getNode().toString()
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
edges
2+
| testURL.swift:13:54:13:54 | passwd : | testURL.swift:13:22:13:54 | ... call to +(_:_:) ... |
3+
| testURL.swift:13:54:13:54 | passwd : | testURL.swift:20:22:20:22 | passwd |
4+
| testURL.swift:16:55:16:55 | credit_card_no : | testURL.swift:16:22:16:55 | ... call to +(_:_:) ... |
25
nodes
6+
| testSend.swift:29:19:29:19 | passwordPlain | semmle.label | passwordPlain |
7+
| testURL.swift:13:22:13:54 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
8+
| testURL.swift:13:54:13:54 | passwd : | semmle.label | passwd : |
9+
| testURL.swift:16:22:16:55 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
10+
| testURL.swift:16:55:16:55 | credit_card_no : | semmle.label | credit_card_no : |
11+
| testURL.swift:20:22:20:22 | passwd | semmle.label | passwd |
312
subpaths
413
#select
5-
| TODO |
14+
| testSend.swift:29:19:29:19 | passwordPlain | testSend.swift:29:19:29:19 | passwordPlain | testSend.swift:29:19:29:19 | passwordPlain | This operation transmits 'passwordPlain', which may contain unencrypted sensitive data from $@ | testSend.swift:29:19:29:19 | passwordPlain | passwordPlain |
15+
| testURL.swift:13:22:13:54 | ... call to +(_:_:) ... | testURL.swift:13:54:13:54 | passwd : | testURL.swift:13:22:13:54 | ... call to +(_:_:) ... | This operation transmits '... call to +(_:_:) ...', which may contain unencrypted sensitive data from $@ | testURL.swift:13:54:13:54 | passwd : | passwd |
16+
| testURL.swift:16:22:16:55 | ... call to +(_:_:) ... | testURL.swift:16:55:16:55 | credit_card_no : | testURL.swift:16:22:16:55 | ... call to +(_:_:) ... | This operation transmits '... call to +(_:_:) ...', which may contain unencrypted sensitive data from $@ | testURL.swift:16:55:16:55 | credit_card_no : | credit_card_no |
17+
| testURL.swift:20:22:20:22 | passwd | testURL.swift:13:54:13:54 | passwd : | testURL.swift:20:22:20:22 | passwd | This operation transmits 'passwd', which may contain unencrypted sensitive data from $@ | testURL.swift:13:54:13:54 | passwd : | passwd |
18+
| testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | testURL.swift:20:22:20:22 | passwd | This operation transmits 'passwd', which may contain unencrypted sensitive data from $@ | testURL.swift:20:22:20:22 | passwd | passwd |

swift/ql/test/query-tests/Security/CWE-311/testSend.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ func test1(passwordPlain : String, passwordHash : String) {
3434
let data3 = Data(passwordHash)
3535

3636
nw.send(content: data1, completion: .idempotent) // GOOD (not sensitive)
37-
nw.send(content: data2, completion: .idempotent) // BAD
37+
nw.send(content: data2, completion: .idempotent) // BAD [NOT DETECTED]
3838
nw.send(content: data3, completion: .idempotent) // GOOD (not sensitive)
3939
}

swift/ql/test/query-tests/Security/CWE-311/testURL.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ class URL
1212
func test1(passwd : String, encrypted_passwd : String, account_no : String, credit_card_no : String) {
1313
let a = URL(string: "http://example.com/login?p=" + passwd); // BAD
1414
let b = URL(string: "http://example.com/login?p=" + encrypted_passwd); // GOOD (not sensitive)
15-
let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD
15+
let c = URL(string: "http://example.com/login?ac=" + account_no); // BAD [NOT DETECTED]
1616
let d = URL(string: "http://example.com/login?cc=" + credit_card_no); // BAD
1717

1818
let base = URL(string: "http://example.com/"); // GOOD (not sensitive)
1919
let e = URL(string: "abc", relativeTo: base); // GOOD (not sensitive)
2020
let f = URL(string: passwd, relativeTo: base); // BAD
21-
let g = URL(string: "abc", relativeTo: f); // BAD
21+
let g = URL(string: "abc", relativeTo: f); // BAD [NOT DETECTED]
2222
}

0 commit comments

Comments
 (0)