mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Merge pull request #14394 from geoffw0/sqlpathinject3
Swift: Add sinks for sqlite3 and SQLite.swift to swift/hardcoded-key
This commit is contained in:
@@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>;
|
||||
|
||||
4
swift/ql/src/change-notes/2023-09-27-hardcoded-key.md
Normal file
4
swift/ql/src/change-notes/2023-09-27-hardcoded-key.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added sqlite3 and SQLite.swift sinks and flow summaries for the `swift/hardcoded-key` query.
|
||||
@@ -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 |
|
||||
|
||||
66
swift/ql/test/query-tests/Security/CWE-321/SQLite.swift
Normal file
66
swift/ql/test/query-tests/Security/CWE-321/SQLite.swift
Normal 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]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user