Merge pull request #14394 from geoffw0/sqlpathinject3

Swift: Add sinks for sqlite3 and SQLite.swift to swift/hardcoded-key
This commit is contained in:
Mathias Vorreiter Pedersen
2023-10-13 16:07:09 +01:00
committed by GitHub
8 changed files with 182 additions and 2 deletions

View File

@@ -18,6 +18,8 @@ private class FilePathSummaries extends SummaryModelCsv {
";Expression;true;init(_:_:);;;Argument[1].CollectionElement;ReturnValue;taint",
";ExpressionType;true;init(_:);;;Argument[0];ReturnValue;taint",
";ExpressionType;true;replace(_:with:);;;Argument[1];ReturnValue;taint",
";Blob;true;init(bytes:);;;Argument[0];ReturnValue;taint",
";Blob;true;init(bytes:length:);;;Argument[0];ReturnValue;taint",
]
}
}

View File

@@ -44,7 +44,14 @@ private class DataSummaries extends SummaryModelCsv {
";Data;true;shuffled();;;Argument[-1];ReturnValue;taint",
";Data;true;shuffled(using:);;;Argument[-1];ReturnValue;taint",
";Data;true;trimmingPrefix(_:);;;Argument[-1];ReturnValue;taint",
";Data;true;trimmingPrefix(while:);;;Argument[-1];ReturnValue;taint"
";Data;true;trimmingPrefix(while:);;;Argument[-1];ReturnValue;taint",
";Data;true;withUnsafeBytes(_:);;;Argument[-1];Argument[0].Parameter[0].CollectionElement;taint",
";Data;true;withUnsafeBytes(_:);;;Argument[-1].CollectionElement;Argument[0].Parameter[0].CollectionElement;taint",
";Data;true;withUnsafeBytes(_:);;;Argument[0].ReturnValue;ReturnValue;value",
";Data;true;withUnsafeMutableBytes(_:);;;Argument[-1];Argument[0].Parameter[0].CollectionElement;taint",
";Data;true;withUnsafeMutableBytes(_:);;;Argument[-1].CollectionElement;Argument[0].Parameter[0].CollectionElement;taint",
";Data;true;withUnsafeMutableBytes(_:);;;Argument[0].Parameter[0].CollectionElement;Argument[-1].CollectionElement;value",
";Data;true;withUnsafeMutableBytes(_:);;;Argument[0].ReturnValue;ReturnValue;value",
]
}
}

View File

@@ -71,6 +71,16 @@ private class EncryptionKeySinks extends SinkModelCsv {
";Realm.Configuration;true;init(fileURL:inMemoryIdentifier:syncConfiguration:encryptionKey:readOnly:schemaVersion:migrationBlock:deleteRealmIfMigrationNeeded:shouldCompactOnLaunch:objectTypes:);;;Argument[3];encryption-key",
";Realm.Configuration;true;init(fileURL:inMemoryIdentifier:syncConfiguration:encryptionKey:readOnly:schemaVersion:migrationBlock:deleteRealmIfMigrationNeeded:shouldCompactOnLaunch:objectTypes:seedFilePath:);;;Argument[3];encryption-key",
";Realm.Configuration;true;encryptionKey;;;PostUpdate;encryption-key",
// sqlite3 C API (Encryption Extension)
";;false;sqlite3_key(_:_:_:);;;Argument[1];encryption-key",
";;false;sqlite3_rekey(_:_:_:);;;Argument[1];encryption-key",
";;false;sqlite3_key_v2(_:_:_:_:);;;Argument[2];encryption-key",
";;false;sqlite3_rekey_v2(_:_:_:_:);;;Argument[2];encryption-key",
// SQLite.swift
";Connection;true;key(_:db:);;;Argument[0];encryption-key",
";Connection;true;keyAndMigrate(_:db:);;;Argument[0];encryption-key",
";Connection;true;rekey(_:db:);;;Argument[0];encryption-key",
";Connection;true;sqlcipher_export(_:key:);;;Argument[1];encryption-key",
// GRDB
";Database;true;usePassphrase(_:);;;Argument[0];encryption-key",
";Database;true;changePassphrase(_:);;;Argument[0];encryption-key",

View File

@@ -17,7 +17,9 @@ abstract class KeySource extends Expr { }
* A literal byte array is a key source.
*/
class ByteArrayLiteralSource extends KeySource {
ByteArrayLiteralSource() { this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") }
ByteArrayLiteralSource() {
this = any(ArrayExpr arr | arr.getType().getName() = ["Array<UInt8>", "[UInt8]"])
}
}
/**
@@ -39,6 +41,12 @@ module HardcodedKeyConfig implements DataFlow::ConfigSig {
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
any(HardcodedEncryptionKeyAdditionalFlowStep s).step(nodeFrom, nodeTo)
}
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
// flow out of collections at the sink
isSink(node) and
c.getAReadContent() instanceof DataFlow::Content::CollectionContent
}
}
module HardcodedKeyFlow = TaintTracking::Global<HardcodedKeyConfig>;

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added sqlite3 and SQLite.swift sinks and flow summaries for the `swift/hardcoded-key` query.

View File

@@ -1,5 +1,10 @@
edges
| SQLite.swift:54:25:54:33 | [...] | SQLite.swift:54:13:54:34 | call to Blob.init(bytes:) |
| cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:80:10:80:28 | call to getConstantString() |
| cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:92:18:92:36 | call to getConstantString() |
| cryptoswift.swift:80:2:80:34 | call to Array<Element>.init(_:) [Collection element] | cryptoswift.swift:91:13:91:30 | call to getConstantArray() [Collection element] |
| cryptoswift.swift:80:10:80:28 | call to getConstantString() | cryptoswift.swift:80:10:80:30 | .utf8 |
| cryptoswift.swift:80:10:80:30 | .utf8 | cryptoswift.swift:80:2:80:34 | call to Array<Element>.init(_:) [Collection element] |
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:117:22:117:22 | key |
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:118:22:118:22 | key |
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:128:26:128:26 | key |
@@ -10,6 +15,8 @@ edges
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:151:26:151:26 | key |
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:161:24:161:24 | key |
| cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:163:24:163:24 | key |
| cryptoswift.swift:91:13:91:30 | call to getConstantArray() [Collection element] | cryptoswift.swift:106:21:106:21 | key2 |
| cryptoswift.swift:91:13:91:30 | call to getConstantArray() [Collection element] | cryptoswift.swift:107:21:107:21 | key2 |
| cryptoswift.swift:92:18:92:36 | call to getConstantString() | cryptoswift.swift:108:21:108:21 | keyString |
| cryptoswift.swift:92:18:92:36 | call to getConstantString() | cryptoswift.swift:109:21:109:21 | keyString |
| cryptoswift.swift:92:18:92:36 | call to getConstantString() | cryptoswift.swift:119:22:119:22 | keyString |
@@ -57,10 +64,27 @@ edges
| rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:81:102:81:102 | myConstKey |
| rncryptor.swift:60:19:60:38 | call to Data.init(_:) | rncryptor.swift:83:92:83:92 | myConstKey |
| rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:60:19:60:38 | call to Data.init(_:) |
| sqlite3_c_api.swift:33:19:33:38 | call to Data.init(_:) | sqlite3_c_api.swift:40:2:40:2 | myConstKey |
| sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | sqlite3_c_api.swift:33:19:33:38 | call to Data.init(_:) |
| sqlite3_c_api.swift:40:2:40:2 | myConstKey | sqlite3_c_api.swift:40:31:40:31 | buffer [Collection element] |
| sqlite3_c_api.swift:40:31:40:31 | buffer [Collection element] | sqlite3_c_api.swift:41:36:41:36 | buffer |
| sqlite3_c_api.swift:40:31:40:31 | buffer [Collection element] | sqlite3_c_api.swift:42:38:42:38 | buffer |
nodes
| SQLite.swift:43:13:43:13 | hardcoded_key | semmle.label | hardcoded_key |
| SQLite.swift:45:23:45:23 | hardcoded_key | semmle.label | hardcoded_key |
| SQLite.swift:47:15:47:15 | hardcoded_key | semmle.label | hardcoded_key |
| SQLite.swift:49:79:49:79 | hardcoded_key | semmle.label | hardcoded_key |
| SQLite.swift:54:13:54:34 | call to Blob.init(bytes:) | semmle.label | call to Blob.init(bytes:) |
| SQLite.swift:54:25:54:33 | [...] | semmle.label | [...] |
| cryptoswift.swift:76:3:76:3 | this string is constant | semmle.label | this string is constant |
| cryptoswift.swift:80:2:80:34 | call to Array<Element>.init(_:) [Collection element] | semmle.label | call to Array<Element>.init(_:) [Collection element] |
| cryptoswift.swift:80:10:80:28 | call to getConstantString() | semmle.label | call to getConstantString() |
| cryptoswift.swift:80:10:80:30 | .utf8 | semmle.label | .utf8 |
| cryptoswift.swift:90:26:90:121 | [...] | semmle.label | [...] |
| cryptoswift.swift:91:13:91:30 | call to getConstantArray() [Collection element] | semmle.label | call to getConstantArray() [Collection element] |
| cryptoswift.swift:92:18:92:36 | call to getConstantString() | semmle.label | call to getConstantString() |
| cryptoswift.swift:106:21:106:21 | key2 | semmle.label | key2 |
| cryptoswift.swift:107:21:107:21 | key2 | semmle.label | key2 |
| cryptoswift.swift:108:21:108:21 | keyString | semmle.label | keyString |
| cryptoswift.swift:109:21:109:21 | keyString | semmle.label | keyString |
| cryptoswift.swift:117:22:117:22 | key | semmle.label | key |
@@ -119,12 +143,25 @@ nodes
| rncryptor.swift:80:94:80:94 | myConstKey | semmle.label | myConstKey |
| rncryptor.swift:81:102:81:102 | myConstKey | semmle.label | myConstKey |
| rncryptor.swift:83:92:83:92 | myConstKey | semmle.label | myConstKey |
| sqlite3_c_api.swift:33:19:33:38 | call to Data.init(_:) | semmle.label | call to Data.init(_:) |
| sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | semmle.label | abcdef123456 |
| sqlite3_c_api.swift:40:2:40:2 | myConstKey | semmle.label | myConstKey |
| sqlite3_c_api.swift:40:31:40:31 | buffer [Collection element] | semmle.label | buffer [Collection element] |
| sqlite3_c_api.swift:41:36:41:36 | buffer | semmle.label | buffer |
| sqlite3_c_api.swift:42:38:42:38 | buffer | semmle.label | buffer |
subpaths
| misc.swift:53:25:53:25 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self | misc.swift:53:2:53:2 | [post] config |
| misc.swift:53:25:53:25 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self [encryptionKey] | misc.swift:53:2:53:2 | [post] config [encryptionKey] |
| misc.swift:57:41:57:41 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self | misc.swift:57:2:57:18 | [post] getter for .config |
| misc.swift:57:41:57:41 | myConstKey | misc.swift:30:7:30:7 | value | file://:0:0:0:0 | [post] self [encryptionKey] | misc.swift:57:2:57:18 | [post] getter for .config [encryptionKey] |
#select
| SQLite.swift:43:13:43:13 | hardcoded_key | SQLite.swift:43:13:43:13 | hardcoded_key | SQLite.swift:43:13:43:13 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:43:13:43:13 | hardcoded_key | hardcoded_key |
| SQLite.swift:45:23:45:23 | hardcoded_key | SQLite.swift:45:23:45:23 | hardcoded_key | SQLite.swift:45:23:45:23 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:45:23:45:23 | hardcoded_key | hardcoded_key |
| SQLite.swift:47:15:47:15 | hardcoded_key | SQLite.swift:47:15:47:15 | hardcoded_key | SQLite.swift:47:15:47:15 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:47:15:47:15 | hardcoded_key | hardcoded_key |
| SQLite.swift:49:79:49:79 | hardcoded_key | SQLite.swift:49:79:49:79 | hardcoded_key | SQLite.swift:49:79:49:79 | hardcoded_key | The key 'hardcoded_key' has been initialized with hard-coded values from $@. | SQLite.swift:49:79:49:79 | hardcoded_key | hardcoded_key |
| SQLite.swift:54:13:54:34 | call to Blob.init(bytes:) | SQLite.swift:54:25:54:33 | [...] | SQLite.swift:54:13:54:34 | call to Blob.init(bytes:) | The key 'call to Blob.init(bytes:)' has been initialized with hard-coded values from $@. | SQLite.swift:54:25:54:33 | [...] | [...] |
| cryptoswift.swift:106:21:106:21 | key2 | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:106:21:106:21 | key2 | The key 'key2' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant |
| cryptoswift.swift:107:21:107:21 | key2 | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:107:21:107:21 | key2 | The key 'key2' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant |
| cryptoswift.swift:108:21:108:21 | keyString | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:108:21:108:21 | keyString | The key 'keyString' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant |
| cryptoswift.swift:109:21:109:21 | keyString | cryptoswift.swift:76:3:76:3 | this string is constant | cryptoswift.swift:109:21:109:21 | keyString | The key 'keyString' has been initialized with hard-coded values from $@. | cryptoswift.swift:76:3:76:3 | this string is constant | this string is constant |
| cryptoswift.swift:117:22:117:22 | key | cryptoswift.swift:90:26:90:121 | [...] | cryptoswift.swift:117:22:117:22 | key | The key 'key' has been initialized with hard-coded values from $@. | cryptoswift.swift:90:26:90:121 | [...] | [...] |
@@ -167,3 +204,5 @@ subpaths
| rncryptor.swift:80:94:80:94 | myConstKey | rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:80:94:80:94 | myConstKey | The key 'myConstKey' has been initialized with hard-coded values from $@. | rncryptor.swift:60:24:60:24 | abcdef123456 | abcdef123456 |
| rncryptor.swift:81:102:81:102 | myConstKey | rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:81:102:81:102 | myConstKey | The key 'myConstKey' has been initialized with hard-coded values from $@. | rncryptor.swift:60:24:60:24 | abcdef123456 | abcdef123456 |
| rncryptor.swift:83:92:83:92 | myConstKey | rncryptor.swift:60:24:60:24 | abcdef123456 | rncryptor.swift:83:92:83:92 | myConstKey | The key 'myConstKey' has been initialized with hard-coded values from $@. | rncryptor.swift:60:24:60:24 | abcdef123456 | abcdef123456 |
| sqlite3_c_api.swift:41:36:41:36 | buffer | sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | sqlite3_c_api.swift:41:36:41:36 | buffer | The key 'buffer' has been initialized with hard-coded values from $@. | sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | abcdef123456 |
| sqlite3_c_api.swift:42:38:42:38 | buffer | sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | sqlite3_c_api.swift:42:38:42:38 | buffer | The key 'buffer' has been initialized with hard-coded values from $@. | sqlite3_c_api.swift:33:24:33:24 | abcdef123456 | abcdef123456 |

View File

@@ -0,0 +1,66 @@
// --- stubs ---
enum URIQueryParameter {
}
struct Blob {
public init(bytes: [UInt8]) { }
public init(bytes: UnsafeRawPointer, length: Int) { }
}
class Connection {
enum Location {
case inMemory
case uri(String, parameters: [URIQueryParameter] = [])
}
init(_ location: Location = .inMemory, readonly: Bool = false) throws { }
convenience init(_ filename: String, readonly: Bool = false) throws { try self.init() }
}
extension Connection {
func key(_ key: String, db: String = "main") throws { }
func key(_ key: Blob, db: String = "main") throws { }
func keyAndMigrate(_ key: String, db: String = "main") throws { }
func keyAndMigrate(_ key: Blob, db: String = "main") throws { }
func rekey(_ key: String, db: String = "main") throws { }
func rekey(_ key: Blob, db: String = "main") throws { }
func sqlcipher_export(_ location: Location, key: String) throws { }
}
// --- tests ---
func test_sqlite_swift_api(dbPath: String, goodKey: String, goodArray: [UInt8]) throws {
let db = try Connection(dbPath)
let badArray: [UInt8] = [1, 2, 3]
// methods taking a string key
try db.key(goodKey)
try db.key("hardcoded_key") // BAD
try db.keyAndMigrate(goodKey)
try db.keyAndMigrate("hardcoded_key") // BAD
try db.rekey(goodKey)
try db.rekey("hardcoded_key") // BAD
try db.sqlcipher_export(Connection.Location.uri("encryptedDb.sqlite3"), key: goodKey)
try db.sqlcipher_export(Connection.Location.uri("encryptedDb.sqlite3"), key: "hardcoded_key") // BAD
// Blob variant
try db.key(Blob(bytes: goodArray))
try db.key(Blob(bytes: [1, 2, 3])) // BAD [NOT DETECTED]
try goodArray.withUnsafeBytes { bytes in
if let ptr = bytes.baseAddress {
try db.key(Blob(bytes: ptr, length: bytes.count))
}
}
try badArray.withUnsafeBytes { bytes in
if let ptr = bytes.baseAddress {
try db.key(Blob(bytes: ptr, length: bytes.count)) // BAD [NOT DETECTED]
}
}
}

View File

@@ -0,0 +1,44 @@
// --- stubs ---
struct Data {
init<S>(_ elements: S) { count = 0 }
func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType {
return 0 as! ResultType//body(0 as UnsafePointer<ContentType>())
}
var count: Int
}
var SQLITE_OK : Int32 = 0
func sqlite3_key_v2(
_ db: OpaquePointer?,
_ zDbName: UnsafePointer<CChar>?,
_ pKey: UnsafeRawPointer?,
_ nKey: Int32
) -> Int32 { return SQLITE_OK }
func sqlite3_rekey_v2(
_ db: OpaquePointer?,
_ zDbName: UnsafePointer<CChar>?,
_ pKey: UnsafeRawPointer?,
_ nKey: Int32
) -> Int32 { return SQLITE_OK }
// --- tests ---
func test_sqlite3_c_api(db: OpaquePointer?, myVarKey: Data) {
let myConstKey = Data("abcdef123456")
// SQLite (C API) Encryption Extension
myVarKey.withUnsafeBytes { buffer in
_ = sqlite3_key_v2(db, "dbname", buffer, Int32(myVarKey.count))
_ = sqlite3_rekey_v2(db, "dbname", buffer, Int32(myVarKey.count))
}
myConstKey.withUnsafeBytes { buffer in
_ = sqlite3_key_v2(db, "dbname", buffer, Int32(myVarKey.count)) // BAD
_ = sqlite3_rekey_v2(db, "dbname", buffer, Int32(myVarKey.count)) // BAD
}
}