Swift: Detect Realm sinks more reliably.

This commit is contained in:
Geoffrey White
2023-11-06 14:27:51 +00:00
parent 9ec5e6e35e
commit 77e48f72ec
4 changed files with 40 additions and 6 deletions

View File

@@ -57,6 +57,26 @@ private class CoreDataStore extends CleartextStorageDatabaseSink {
}
}
/**
* The Realm database `RealmSwiftObject` type. Also matches the Realm `Object`
* type, which may or may not be a type alias for `RealmSwiftObject`.
*/
class RealmSwiftObject extends Type {
RealmSwiftObject() {
this.getName() = "RealmSwiftObject"
or
this.getName() = "Object" and
this.(NominalType).getDeclaration().getModule().getName() = "RealmSwift"
}
}
/**
* A class that inherits from `RealmSwiftObject`.
*/
class RealmSwiftObjectType extends Type {
RealmSwiftObjectType() { this.getUnderlyingType().getABaseType*() instanceof RealmSwiftObject }
}
/**
* A `DataFlow::Node` that is an expression stored with the Realm database
* library.
@@ -66,10 +86,9 @@ private class RealmStore extends CleartextStorageDatabaseSink instanceof DataFlo
// any write into a class derived from `RealmSwiftObject` is a sink. For
// example in `realmObj.data = sensitive` the post-update node corresponding
// with `realmObj.data` is a sink.
exists(NominalType t, Type base, Expr e |
base.getName() = "RealmSwiftObject" and
exists(Expr e |
this.getPreUpdateNode().asExpr() = e and
e.getFullyConverted().getType().getUnderlyingType().getABaseType*() = base and
e.getFullyConverted().getType() instanceof RealmSwiftObjectType and
not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl
)
}

View File

@@ -34,8 +34,10 @@ module CleartextStorageDatabaseConfig implements DataFlow::ConfigSig {
// for example in `realmObj.data = sensitive`.
isSink(node) and
exists(NominalTypeDecl d, Decl cx |
d.getType().getUnderlyingType().getABaseType*().getName() =
["NSManagedObject", "RealmSwiftObject"] and
(
d.getType().getUnderlyingType().getABaseType*().getName() = "NSManagedObject" or
d.getType() instanceof RealmSwiftObjectType
) and
cx.asNominalTypeDecl() = d and
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember()
)

View File

@@ -73,6 +73,7 @@ edges
| file://:0:0:0:0 | self | file://:0:0:0:0 | .value2 |
| file://:0:0:0:0 | self [value] | file://:0:0:0:0 | .value |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [data] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [data] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [password] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [value] |
@@ -288,6 +289,10 @@ edges
| testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] [Collection element] |
| testGRDB.swift:212:98:212:107 | [...] [Collection element] | testGRDB.swift:212:98:212:107 | [...] |
| testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] [Collection element] |
| testRealm2.swift:13:6:13:6 | value | file://:0:0:0:0 | value |
| testRealm2.swift:18:2:18:2 | [post] o [data] | testRealm2.swift:18:2:18:2 | [post] o |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o [data] |
| testRealm.swift:27:6:27:6 | value | file://:0:0:0:0 | value |
| testRealm.swift:34:6:34:6 | value | file://:0:0:0:0 | value |
| testRealm.swift:41:2:41:2 | [post] a [data] | testRealm.swift:41:2:41:2 | [post] a |
@@ -405,6 +410,7 @@ nodes
| file://:0:0:0:0 | .value | semmle.label | .value |
| file://:0:0:0:0 | .value2 | semmle.label | .value2 |
| file://:0:0:0:0 | [post] self [data] | semmle.label | [post] self [data] |
| file://:0:0:0:0 | [post] self [data] | semmle.label | [post] self [data] |
| file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] | semmle.label | [post] self [notStoredBankAccountNumber] |
| file://:0:0:0:0 | [post] self [password] | semmle.label | [post] self [password] |
| file://:0:0:0:0 | [post] self [value] | semmle.label | [post] self [value] |
@@ -415,6 +421,7 @@ nodes
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:46:27:46:27 | insertQuery | semmle.label | insertQuery |
@@ -701,6 +708,10 @@ nodes
| testGRDB.swift:212:98:212:107 | [...] | semmle.label | [...] |
| testGRDB.swift:212:98:212:107 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| testGRDB.swift:212:99:212:99 | password | semmle.label | password |
| testRealm2.swift:13:6:13:6 | value | semmle.label | value |
| testRealm2.swift:18:2:18:2 | [post] o | semmle.label | [post] o |
| testRealm2.swift:18:2:18:2 | [post] o [data] | semmle.label | [post] o [data] |
| testRealm2.swift:18:11:18:11 | myPassword | semmle.label | myPassword |
| testRealm.swift:27:6:27:6 | value | semmle.label | value |
| testRealm.swift:34:6:34:6 | value | semmle.label | value |
| testRealm.swift:41:2:41:2 | [post] a | semmle.label | [post] a |
@@ -733,6 +744,7 @@ subpaths
| testCoreData2.swift:98:18:98:18 | d [value] | testCoreData2.swift:70:9:70:9 | self [value] | file://:0:0:0:0 | .value | testCoreData2.swift:98:18:98:20 | .value |
| testCoreData2.swift:104:18:104:18 | e | testCoreData2.swift:70:9:70:9 | self | file://:0:0:0:0 | .value | testCoreData2.swift:104:18:104:20 | .value |
| testCoreData2.swift:105:18:105:18 | e | testCoreData2.swift:71:9:71:9 | self | file://:0:0:0:0 | .value2 | testCoreData2.swift:105:18:105:20 | .value2 |
| testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:13:6:13:6 | value | file://:0:0:0:0 | [post] self [data] | testRealm2.swift:18:2:18:2 | [post] o [data] |
| testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:27:6:27:6 | value | file://:0:0:0:0 | [post] self [data] | testRealm.swift:41:2:41:2 | [post] a [data] |
| 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] |
| 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] |
@@ -864,6 +876,7 @@ subpaths
| testGRDB.swift:208:80:208:89 | [...] | testGRDB.swift:208:81:208:81 | password | testGRDB.swift:208:80:208:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:208:81:208:81 | password | password |
| testGRDB.swift:210:84:210:93 | [...] | testGRDB.swift:210:85:210:85 | password | testGRDB.swift:210:84:210:93 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:210:85:210:85 | password | password |
| testGRDB.swift:212:98:212:107 | [...] | testGRDB.swift:212:99:212:99 | password | testGRDB.swift:212:98:212:107 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | testGRDB.swift:212:99:212:99 | password | password |
| testRealm2.swift:18:2:18:2 | o | testRealm2.swift:18:11:18:11 | myPassword | testRealm2.swift:18:2:18:2 | [post] o | This operation stores 'o' in a database. It may contain unencrypted sensitive data from $@. | testRealm2.swift:18:11:18:11 | myPassword | myPassword |
| testRealm.swift:41:2:41:2 | a | testRealm.swift:41:11:41:11 | myPassword | testRealm.swift:41:2:41:2 | [post] a | This operation stores 'a' in a database. It may contain unencrypted sensitive data from $@. | testRealm.swift:41:11:41:11 | myPassword | myPassword |
| 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 |
| 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 |

View File

@@ -15,7 +15,7 @@ class MyRealmSwiftObject3 : Object {
func test1(o: MyRealmSwiftObject3, myHarmless: String, myPassword : String) {
// ...
o.data = myPassword // BAD [NOT DETECTED]
o.data = myPassword // BAD
o.data = myHarmless
// ...
}