Skip to content

Commit e0100d7

Browse files
committed
Swift: Expand sinks and fix issue with post-update notes to catch the missing test results.
1 parent eb2a0af commit e0100d7

File tree

3 files changed

+102
-7
lines changed

3 files changed

+102
-7
lines changed

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ class RealmStore extends Stored {
6060
call.getStaticTarget() = f and
6161
call.getArgument(1).getExpr() = this
6262
)
63+
or
64+
// any access into a class derived from `RealmSwiftObject` is a sink
65+
exists(ClassDecl cd |
66+
cd.getABaseTypeDecl*().getName() = "RealmSwiftObject" and
67+
this.getFullyConverted().getType() = cd.getType()
68+
)
6369
}
6470
}
6571

@@ -84,9 +90,19 @@ class CleartextStorageConfig extends TaintTracking::Configuration {
8490
node.asExpr() instanceof EncryptedExpr
8591
}
8692

93+
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
94+
// allow flow from a post-update node at the sink to the sink. For example
95+
// in `realmObj.data = sensitive` taint flows to the post-update node
96+
// corresponding with the sink `realmObj.data`, and we want to consider it
97+
// as reaching that sink.
98+
node1.(DataFlow::PostUpdateNode).getPreUpdateNode() = node2 and
99+
isSink(node2)
100+
}
101+
87102
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
88-
// flow out from fields of a `RealmSwiftObject` at the sink, for example in `obj.var = tainted; sink(obj)`.
89-
isSink(node) and
103+
// flow out from fields of a `RealmSwiftObject` at the sink, for example in
104+
// `obj.var = tainted; sink(obj)`.
105+
(isSink(node) or isAdditionalTaintStep(node, _)) and
90106
exists(ClassDecl cd |
91107
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cd.getAMember() and
92108
cd.getABaseTypeDecl*().getName() = "RealmSwiftObject"

swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
edges
2+
| file://:0:0:0:0 | [post] self : | file://:0:0:0:0 | self |
3+
| file://:0:0:0:0 | [post] self [data] : | file://:0:0:0:0 | [post] self : |
4+
| file://:0:0:0:0 | [post] self [data] : | file://:0:0:0:0 | self |
25
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [data] : |
36
| testCoreData.swift:18:19:18:26 | value : | testCoreData.swift:19:12:19:12 | value |
47
| testCoreData.swift:31:3:31:3 | newValue : | testCoreData.swift:32:13:32:13 | newValue |
@@ -9,15 +12,57 @@ edges
912
| testCoreData.swift:91:10:91:10 | passwd : | testCoreData.swift:95:15:95:15 | x |
1013
| testCoreData.swift:92:10:92:10 | passwd : | testCoreData.swift:96:15:96:15 | y |
1114
| testCoreData.swift:93:10:93:10 | passwd : | testCoreData.swift:97:15:97:15 | z |
15+
| testRealm.swift:16:6:16:6 | self : | file://:0:0:0:0 | self |
1216
| testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | value : |
17+
| testRealm.swift:34:2:34:2 | [post] a : | testRealm.swift:34:2:34:2 | a |
18+
| testRealm.swift:34:2:34:2 | [post] a : | testRealm.swift:34:2:34:2 | a : |
19+
| testRealm.swift:34:2:34:2 | [post] a : | testRealm.swift:35:12:35:12 | a |
20+
| testRealm.swift:34:2:34:2 | [post] a [data] : | testRealm.swift:34:2:34:2 | a |
21+
| testRealm.swift:34:2:34:2 | [post] a [data] : | testRealm.swift:34:2:34:2 | a : |
1322
| testRealm.swift:34:2:34:2 | [post] a [data] : | testRealm.swift:35:12:35:12 | a |
23+
| testRealm.swift:34:2:34:2 | a : | testRealm.swift:16:6:16:6 | self : |
24+
| testRealm.swift:34:2:34:2 | a : | testRealm.swift:35:12:35:12 | a |
1425
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:16:6:16:6 | value : |
26+
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:34:2:34:2 | [post] a : |
1527
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:34:2:34:2 | [post] a [data] : |
28+
| testRealm.swift:42:2:42:2 | [post] c : | testRealm.swift:42:2:42:2 | c |
29+
| testRealm.swift:42:2:42:2 | [post] c : | testRealm.swift:42:2:42:2 | c : |
30+
| testRealm.swift:42:2:42:2 | [post] c : | testRealm.swift:43:47:43:47 | c |
31+
| testRealm.swift:42:2:42:2 | [post] c [data] : | testRealm.swift:42:2:42:2 | c |
32+
| testRealm.swift:42:2:42:2 | [post] c [data] : | testRealm.swift:42:2:42:2 | c : |
1633
| testRealm.swift:42:2:42:2 | [post] c [data] : | testRealm.swift:43:47:43:47 | c |
34+
| testRealm.swift:42:2:42:2 | c : | testRealm.swift:16:6:16:6 | self : |
35+
| testRealm.swift:42:2:42:2 | c : | testRealm.swift:43:47:43:47 | c |
1736
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:16:6:16:6 | value : |
37+
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:42:2:42:2 | [post] c : |
1838
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:42:2:42:2 | [post] c [data] : |
39+
| testRealm.swift:52:2:52:3 | ...! : | testRealm.swift:16:6:16:6 | self : |
40+
| testRealm.swift:52:2:52:3 | [post] ...! : | testRealm.swift:52:2:52:3 | ...! |
41+
| testRealm.swift:52:2:52:3 | [post] ...! : | testRealm.swift:52:2:52:3 | ...! : |
42+
| testRealm.swift:52:2:52:3 | [post] ...! [data] : | testRealm.swift:52:2:52:3 | ...! |
43+
| testRealm.swift:52:2:52:3 | [post] ...! [data] : | testRealm.swift:52:2:52:3 | ...! : |
44+
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:16:6:16:6 | value : |
45+
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:52:2:52:3 | [post] ...! : |
46+
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:52:2:52:3 | [post] ...! [data] : |
47+
| testRealm.swift:59:2:59:2 | [post] g : | testRealm.swift:59:2:59:2 | g |
48+
| testRealm.swift:59:2:59:2 | [post] g : | testRealm.swift:59:2:59:2 | g : |
49+
| testRealm.swift:59:2:59:2 | [post] g : | testRealm.swift:60:2:60:2 | g |
50+
| testRealm.swift:59:2:59:2 | [post] g : | testRealm.swift:60:2:60:2 | g : |
51+
| testRealm.swift:59:2:59:2 | [post] g [data] : | testRealm.swift:59:2:59:2 | g |
52+
| testRealm.swift:59:2:59:2 | [post] g [data] : | testRealm.swift:59:2:59:2 | g : |
53+
| testRealm.swift:59:2:59:2 | [post] g [data] : | testRealm.swift:60:2:60:2 | g |
54+
| testRealm.swift:59:2:59:2 | [post] g [data] : | testRealm.swift:60:2:60:2 | g : |
55+
| testRealm.swift:59:2:59:2 | g : | testRealm.swift:16:6:16:6 | self : |
56+
| testRealm.swift:59:2:59:2 | g : | testRealm.swift:60:2:60:2 | g |
57+
| testRealm.swift:59:2:59:2 | g : | testRealm.swift:60:2:60:2 | g : |
58+
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:16:6:16:6 | value : |
59+
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:59:2:59:2 | [post] g : |
60+
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:59:2:59:2 | [post] g [data] : |
61+
| testRealm.swift:60:2:60:2 | g : | testRealm.swift:16:6:16:6 | self : |
1962
nodes
63+
| file://:0:0:0:0 | [post] self : | semmle.label | [post] self : |
2064
| file://:0:0:0:0 | [post] self [data] : | semmle.label | [post] self [data] : |
65+
| file://:0:0:0:0 | self | semmle.label | self |
2166
| file://:0:0:0:0 | value : | semmle.label | value : |
2267
| testCoreData.swift:18:19:18:26 | value : | semmle.label | value : |
2368
| testCoreData.swift:19:12:19:12 | value | semmle.label | value |
@@ -39,17 +84,46 @@ nodes
3984
| testCoreData.swift:95:15:95:15 | x | semmle.label | x |
4085
| testCoreData.swift:96:15:96:15 | y | semmle.label | y |
4186
| testCoreData.swift:97:15:97:15 | z | semmle.label | z |
87+
| testRealm.swift:16:6:16:6 | self : | semmle.label | self : |
4288
| testRealm.swift:16:6:16:6 | value : | semmle.label | value : |
89+
| testRealm.swift:34:2:34:2 | [post] a : | semmle.label | [post] a : |
4390
| testRealm.swift:34:2:34:2 | [post] a [data] : | semmle.label | [post] a [data] : |
91+
| testRealm.swift:34:2:34:2 | a | semmle.label | a |
92+
| testRealm.swift:34:2:34:2 | a : | semmle.label | a : |
4493
| testRealm.swift:34:11:34:11 | myPassword : | semmle.label | myPassword : |
4594
| testRealm.swift:35:12:35:12 | a | semmle.label | a |
95+
| testRealm.swift:42:2:42:2 | [post] c : | semmle.label | [post] c : |
4696
| testRealm.swift:42:2:42:2 | [post] c [data] : | semmle.label | [post] c [data] : |
97+
| testRealm.swift:42:2:42:2 | c | semmle.label | c |
98+
| testRealm.swift:42:2:42:2 | c : | semmle.label | c : |
4799
| testRealm.swift:42:11:42:11 | myPassword : | semmle.label | myPassword : |
48100
| testRealm.swift:43:47:43:47 | c | semmle.label | c |
101+
| testRealm.swift:52:2:52:3 | ...! | semmle.label | ...! |
102+
| testRealm.swift:52:2:52:3 | ...! : | semmle.label | ...! : |
103+
| testRealm.swift:52:2:52:3 | [post] ...! : | semmle.label | [post] ...! : |
104+
| testRealm.swift:52:2:52:3 | [post] ...! [data] : | semmle.label | [post] ...! [data] : |
105+
| testRealm.swift:52:12:52:12 | myPassword : | semmle.label | myPassword : |
106+
| testRealm.swift:59:2:59:2 | [post] g : | semmle.label | [post] g : |
107+
| testRealm.swift:59:2:59:2 | [post] g [data] : | semmle.label | [post] g [data] : |
108+
| testRealm.swift:59:2:59:2 | g | semmle.label | g |
109+
| testRealm.swift:59:2:59:2 | g : | semmle.label | g : |
110+
| testRealm.swift:59:11:59:11 | myPassword : | semmle.label | myPassword : |
111+
| testRealm.swift:60:2:60:2 | g | semmle.label | g |
112+
| testRealm.swift:60:2:60:2 | g : | semmle.label | g : |
49113
subpaths
114+
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self : | testRealm.swift:34:2:34:2 | [post] a : |
50115
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:34:2:34:2 | [post] a [data] : |
116+
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self : | testRealm.swift:42:2:42:2 | [post] c : |
51117
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:42:2:42:2 | [post] c [data] : |
118+
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self : | testRealm.swift:52:2:52:3 | [post] ...! : |
119+
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:52:2:52:3 | [post] ...! [data] : |
120+
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self : | testRealm.swift:59:2:59:2 | [post] g : |
121+
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:59:2:59:2 | [post] g [data] : |
52122
#select
123+
| file://:0:0:0:0 | self | testRealm.swift:34:11:34:11 | myPassword : | file://:0:0:0:0 | self | This operation stores 'self' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:34:11:34:11 | myPassword : | myPassword |
124+
| file://:0:0:0:0 | self | testRealm.swift:42:11:42:11 | myPassword : | file://:0:0:0:0 | self | This operation stores 'self' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:42:11:42:11 | myPassword : | myPassword |
125+
| file://:0:0:0:0 | self | testRealm.swift:52:12:52:12 | myPassword : | file://:0:0:0:0 | self | This operation stores 'self' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:52:12:52:12 | myPassword : | myPassword |
126+
| file://:0:0:0:0 | self | testRealm.swift:59:11:59:11 | myPassword : | file://:0:0:0:0 | self | This operation stores 'self' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:59:11:59:11 | myPassword : | myPassword |
53127
| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password : | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:61:25:61:25 | password : | password |
54128
| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password : | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:64:16:64:16 | password : | password |
55129
| testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:48:15:48:15 | password | password |
@@ -61,5 +135,10 @@ subpaths
61135
| testCoreData.swift:95:15:95:15 | x | testCoreData.swift:91:10:91:10 | passwd : | testCoreData.swift:95:15:95:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:91:10:91:10 | passwd : | passwd |
62136
| testCoreData.swift:96:15:96:15 | y | testCoreData.swift:92:10:92:10 | passwd : | testCoreData.swift:96:15:96:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:92:10:92:10 | passwd : | passwd |
63137
| testCoreData.swift:97:15:97:15 | z | testCoreData.swift:93:10:93:10 | passwd : | testCoreData.swift:97:15:97:15 | z | This operation stores 'z' in a database. It may contain unencrypted sensitive data from $@ | testCoreData.swift:93:10:93:10 | passwd : | passwd |
138+
| testRealm.swift:34:2:34:2 | a | testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:34:2:34:2 | a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:34:11:34:11 | myPassword : | myPassword |
64139
| testRealm.swift:35:12:35:12 | a | testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:35:12:35:12 | a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:34:11:34:11 | myPassword : | myPassword |
140+
| testRealm.swift:42:2:42:2 | c | testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:42:2:42:2 | c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:42:11:42:11 | myPassword : | myPassword |
65141
| testRealm.swift:43:47:43:47 | c | testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:43:47:43:47 | c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:42:11:42:11 | myPassword : | myPassword |
142+
| testRealm.swift:52:2:52:3 | ...! | testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:52:2:52:3 | ...! | This operation stores '...!' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:52:12:52:12 | myPassword : | myPassword |
143+
| testRealm.swift:59:2:59:2 | g | testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:59:2:59:2 | g | This operation stores 'g' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:59:11:59:11 | myPassword : | myPassword |
144+
| testRealm.swift:60:2:60:2 | g | testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:60:2:60:2 | g | This operation stores 'g' in a database. It may contain unencrypted sensitive data from $@ | testRealm.swift:59:11:59:11 | myPassword : | myPassword |

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ func test1(realm : Realm, myPassword : String, myHashedPassword : String) {
3131
// add objects (within a transaction) ...
3232

3333
let a = MyRealmSwiftObject()
34-
a.data = myPassword
34+
a.data = myPassword // BAD [DUPLICATE]
3535
realm.add(a) // BAD
3636

3737
let b = MyRealmSwiftObject()
3838
b.data = myHashedPassword
3939
realm.add(b) // GOOD (not sensitive)
4040

4141
let c = MyRealmSwiftObject()
42-
c.data = myPassword
42+
c.data = myPassword // BAD [DUPLICATE]
4343
realm.create(MyRealmSwiftObject.self, value: c) // BAD
4444

4545
let d = MyRealmSwiftObject()
@@ -49,15 +49,15 @@ func test1(realm : Realm, myPassword : String, myHashedPassword : String) {
4949
// retrieve objects ...
5050

5151
var e = realm.object(ofType: MyRealmSwiftObject.self, forPrimaryKey: "key")
52-
e!.data = myPassword // BAD [NOT DETECTED]
52+
e!.data = myPassword // BAD
5353

5454
var f = realm.object(ofType: MyRealmSwiftObject.self, forPrimaryKey: "key")
5555
f!.data = myHashedPassword // GOOD (not sensitive)
5656

5757
let g = MyRealmSwiftObject()
5858
g.data = "" // GOOD (not sensitive)
59-
g.data = myPassword // BAD [NOT DETECTED]
60-
g.data = "" // GOOD (not sensitive)
59+
g.data = myPassword // BAD
60+
g.data = "" // GOOD (not sensitive) // [FALSE POSITIVE]
6161
}
6262

6363
// limitation: its possible to configure a Realm DB to be stored encrypted, if this is done correctly

0 commit comments

Comments
 (0)