Skip to content

Commit 33b0412

Browse files
committed
Swift: Recognize Core Data + Realm sources via type aliases.
1 parent daa8141 commit 33b0412

File tree

5 files changed

+39
-6
lines changed

5 files changed

+39
-6
lines changed

swift/ql/lib/codeql/swift/elements/type/Type.qll

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
private import codeql.swift.generated.type.Type
2+
private import codeql.swift.elements.type.NominalType
3+
private import codeql.swift.elements.type.TypeAliasType
24

35
class Type extends Generated::Type {
46
override string toString() { result = this.getName() }
@@ -11,4 +13,22 @@ class Type extends Generated::Type {
1113
* ```
1214
*/
1315
Type getUnderlyingType() { result = this }
16+
17+
/**
18+
* Gets any base type of this type, or the result of resolving a typedef. For
19+
* example in the following code, `C` has base type `B` which has underlying
20+
* type `A`. Thus, `getABaseOrAliasedType*` can be used to discover the
21+
* relationship between `C` and `A`.
22+
* ```
23+
* class A {}
24+
*
25+
* typealias B = A
26+
*
27+
* class C : B {}
28+
* ```
29+
*/
30+
Type getABaseOrAliasedType() {
31+
result = this.(NominalType).getABaseType() or
32+
result = this.(TypeAliasType).getAliasedType()
33+
}
1434
}

swift/ql/lib/codeql/swift/security/CleartextStorageDatabaseExtensions.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ private class CoreDataStore extends CleartextStorageDatabaseSink {
4949
// with `coreDataObj.data` is a sink.
5050
// (ideally this would be only members with the `@NSManaged` attribute)
5151
exists(NominalType t, Expr e |
52-
t.getABaseType*().getName() = "NSManagedObject" and
52+
t.getABaseOrAliasedType*().getName() = "NSManagedObject" and
5353
this.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = e and
5454
e.getFullyConverted().getType() = t and
5555
not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl
@@ -67,7 +67,7 @@ private class RealmStore extends CleartextStorageDatabaseSink instanceof DataFlo
6767
// example in `realmObj.data = sensitive` the post-update node corresponding
6868
// with `realmObj.data` is a sink.
6969
exists(NominalType t, Expr e |
70-
t.getABaseType*().getName() = "RealmSwiftObject" and
70+
t.getABaseOrAliasedType*().getName() = "RealmSwiftObject" and
7171
this.getPreUpdateNode().asExpr() = e and
7272
e.getFullyConverted().getType() = t and
7373
not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl

swift/ql/lib/codeql/swift/security/CleartextStorageDatabaseQuery.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ class CleartextStorageConfig extends TaintTracking::Configuration {
3737
// flow out from fields of an `NSManagedObject` or `RealmSwiftObject` at the sink,
3838
// for example in `realmObj.data = sensitive`.
3939
isSink(node) and
40-
exists(ClassOrStructDecl cd, Decl cx |
41-
cd.getABaseTypeDecl*().getName() = ["NSManagedObject", "RealmSwiftObject"] and
42-
cx.asNominalTypeDecl() = cd and
40+
exists(NominalTypeDecl d, Decl cx |
41+
d.getType().getABaseOrAliasedType*().getName() = ["NSManagedObject", "RealmSwiftObject"] and
42+
cx.asNominalTypeDecl() = d and
4343
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember()
4444
)
4545
or

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ edges
22
| file://:0:0:0:0 | self [value] : | file://:0:0:0:0 | .value : |
33
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [data] : |
44
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : |
5+
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [password] : |
56
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [value] : |
67
| testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | value : |
78
| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : | testCoreData2.swift:37:2:37:2 | [post] obj |
@@ -169,6 +170,7 @@ edges
169170
| testGRDB.swift:210:85:210:85 | password : | testGRDB.swift:210:84:210:93 | [...] |
170171
| testGRDB.swift:212:99:212:99 | password : | testGRDB.swift:212:98:212:107 | [...] |
171172
| testRealm.swift:27:6:27:6 | value : | file://:0:0:0:0 | value : |
173+
| testRealm.swift:34:6:34:6 | value : | file://:0:0:0:0 | value : |
172174
| testRealm.swift:41:2:41:2 | [post] a [data] : | testRealm.swift:41:2:41:2 | [post] a |
173175
| testRealm.swift:41:11:41:11 | myPassword : | testRealm.swift:27:6:27:6 | value : |
174176
| testRealm.swift:41:11:41:11 | myPassword : | testRealm.swift:41:2:41:2 | [post] a [data] : |
@@ -181,17 +183,22 @@ edges
181183
| testRealm.swift:66:2:66:2 | [post] g [data] : | testRealm.swift:66:2:66:2 | [post] g |
182184
| testRealm.swift:66:11:66:11 | myPassword : | testRealm.swift:27:6:27:6 | value : |
183185
| testRealm.swift:66:11:66:11 | myPassword : | testRealm.swift:66:2:66:2 | [post] g [data] : |
186+
| testRealm.swift:73:2:73:2 | [post] h [password] : | testRealm.swift:73:2:73:2 | [post] h |
187+
| testRealm.swift:73:15:73:15 | myPassword : | testRealm.swift:34:6:34:6 | value : |
188+
| testRealm.swift:73:15:73:15 | myPassword : | testRealm.swift:73:2:73:2 | [post] h [password] : |
184189
nodes
185190
| file://:0:0:0:0 | .value2 : | semmle.label | .value2 : |
186191
| file://:0:0:0:0 | .value : | semmle.label | .value : |
187192
| file://:0:0:0:0 | .value : | semmle.label | .value : |
188193
| file://:0:0:0:0 | [post] self [data] : | semmle.label | [post] self [data] : |
189194
| file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | semmle.label | [post] self [notStoredBankAccountNumber] : |
195+
| file://:0:0:0:0 | [post] self [password] : | semmle.label | [post] self [password] : |
190196
| file://:0:0:0:0 | [post] self [value] : | semmle.label | [post] self [value] : |
191197
| file://:0:0:0:0 | self [value] : | semmle.label | self [value] : |
192198
| file://:0:0:0:0 | value : | semmle.label | value : |
193199
| file://:0:0:0:0 | value : | semmle.label | value : |
194200
| file://:0:0:0:0 | value : | semmle.label | value : |
201+
| file://:0:0:0:0 | value : | semmle.label | value : |
195202
| testCoreData2.swift:23:13:23:13 | value : | semmle.label | value : |
196203
| testCoreData2.swift:37:2:37:2 | [post] obj | semmle.label | [post] obj |
197204
| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : | semmle.label | [post] obj [myValue] : |
@@ -422,6 +429,7 @@ nodes
422429
| testGRDB.swift:212:98:212:107 | [...] | semmle.label | [...] |
423430
| testGRDB.swift:212:99:212:99 | password : | semmle.label | password : |
424431
| testRealm.swift:27:6:27:6 | value : | semmle.label | value : |
432+
| testRealm.swift:34:6:34:6 | value : | semmle.label | value : |
425433
| testRealm.swift:41:2:41:2 | [post] a | semmle.label | [post] a |
426434
| testRealm.swift:41:2:41:2 | [post] a [data] : | semmle.label | [post] a [data] : |
427435
| testRealm.swift:41:11:41:11 | myPassword : | semmle.label | myPassword : |
@@ -434,6 +442,9 @@ nodes
434442
| testRealm.swift:66:2:66:2 | [post] g | semmle.label | [post] g |
435443
| testRealm.swift:66:2:66:2 | [post] g [data] : | semmle.label | [post] g [data] : |
436444
| testRealm.swift:66:11:66:11 | myPassword : | semmle.label | myPassword : |
445+
| testRealm.swift:73:2:73:2 | [post] h | semmle.label | [post] h |
446+
| testRealm.swift:73:2:73:2 | [post] h [password] : | semmle.label | [post] h [password] : |
447+
| testRealm.swift:73:15:73:15 | myPassword : | semmle.label | myPassword : |
437448
subpaths
438449
| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : |
439450
| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : |
@@ -453,6 +464,7 @@ subpaths
453464
| testRealm.swift:49:11:49:11 | myPassword : | testRealm.swift:27:6:27:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:49:2:49:2 | [post] c [data] : |
454465
| testRealm.swift:59:12:59:12 | myPassword : | testRealm.swift:27:6:27:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:59:2:59:3 | [post] ...! [data] : |
455466
| testRealm.swift:66:11:66:11 | myPassword : | testRealm.swift:27:6:27:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:66:2:66:2 | [post] g [data] : |
467+
| testRealm.swift:73:15:73:15 | myPassword : | testRealm.swift:34:6:34:6 | value : | file://:0:0:0:0 | [post] self [password] : | testRealm.swift:73:2:73:2 | [post] h [password] : |
456468
#select
457469
| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo : | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo : | bankAccountNo |
458470
| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo : | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo : | bankAccountNo |
@@ -546,3 +558,4 @@ subpaths
546558
| testRealm.swift:49:2:49:2 | c | testRealm.swift:49:11:49:11 | myPassword : | testRealm.swift:49:2:49:2 | [post] c | This operation stores 'c' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:49:11:49:11 | myPassword : | myPassword |
547559
| testRealm.swift:59:2:59:3 | ...! | testRealm.swift:59:12:59:12 | myPassword : | testRealm.swift:59:2:59:3 | [post] ...! | This operation stores '...!' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:59:12:59:12 | myPassword : | myPassword |
548560
| testRealm.swift:66:2:66:2 | g | testRealm.swift:66:11:66:11 | myPassword : | testRealm.swift:66:2:66:2 | [post] g | This operation stores 'g' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:66:11:66:11 | myPassword : | myPassword |
561+
| testRealm.swift:73:2:73:2 | h | testRealm.swift:73:15:73:15 | myPassword : | testRealm.swift:73:2:73:2 | [post] h | This operation stores 'h' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:73:15:73:15 | myPassword : | myPassword |

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ func test1(realm : Realm, myUsername: String, myPassword : String, myHashedPassw
7070

7171
let h = MyRealmSwiftObject2()
7272
h.username = myUsername // GOOD (not sensitive)
73-
h.password = myPassword // BAD [NOT DETECTED]
73+
h.password = myPassword // BAD
7474
realm.add(h)
7575
}
7676

0 commit comments

Comments
 (0)