mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #14797 from geoffw0/sqlsinks
Swift: Heuristic sinks for swift/sql-injection
This commit is contained in:
@@ -147,6 +147,36 @@ private class GrdbDefaultSqlInjectionSink extends SqlInjectionSink {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f`, `ix` describe `pd` and `pd` is a parameter that might be
|
||||
* executed as SQL.
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate sqlLikeHeuristic(Callable f, int ix, ParamDecl pd) {
|
||||
pd.getName() = "sql" and
|
||||
pd = f.getParam(ix)
|
||||
}
|
||||
|
||||
/**
|
||||
* An SQL injection sink that is determined by imprecise methods.
|
||||
*/
|
||||
private class HeuristicSqlInjectionSink extends SqlInjectionSink {
|
||||
HeuristicSqlInjectionSink() {
|
||||
// by parameter name
|
||||
exists(CallExpr ce, Callable f, int ix |
|
||||
sqlLikeHeuristic(f, ix, _) and
|
||||
f = ce.getStaticTarget() and
|
||||
this.asExpr() = ce.getArgument(ix).getExpr()
|
||||
)
|
||||
or
|
||||
// by argument name
|
||||
exists(Argument a |
|
||||
a.getLabel() = "sql" and
|
||||
this.asExpr() = a.getExpr()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sink defined in a CSV model.
|
||||
*/
|
||||
|
||||
5
swift/ql/src/change-notes/2023-11-14-sql-injection.md
Normal file
5
swift/ql/src/change-notes/2023-11-14-sql-injection.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
|
||||
* Added heuristic (imprecise) sinks for the "Database query built from user-controlled sources" (`swift/sql-injection`) query.
|
||||
@@ -97,6 +97,13 @@ edges
|
||||
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:117:16:117:16 | unsafeQuery1 |
|
||||
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:119:16:119:16 | unsafeQuery1 |
|
||||
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:132:20:132:20 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:50:22:50:22 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:52:14:52:14 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:53:14:53:14 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:54:31:54:31 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:55:14:55:14 | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:57:16:57:16 | remoteString |
|
||||
| other.swift:54:31:54:31 | remoteString | other.swift:54:14:54:43 | call to NSString.init(string:) |
|
||||
| sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 |
|
||||
| sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 |
|
||||
| sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 |
|
||||
@@ -222,6 +229,14 @@ nodes
|
||||
| SQLite.swift:117:16:117:16 | unsafeQuery1 | semmle.label | unsafeQuery1 |
|
||||
| SQLite.swift:119:16:119:16 | unsafeQuery1 | semmle.label | unsafeQuery1 |
|
||||
| SQLite.swift:132:20:132:20 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:46:25:46:79 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) |
|
||||
| other.swift:50:22:50:22 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:52:14:52:14 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:53:14:53:14 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:54:14:54:43 | call to NSString.init(string:) | semmle.label | call to NSString.init(string:) |
|
||||
| other.swift:54:31:54:31 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:55:14:55:14 | remoteString | semmle.label | remoteString |
|
||||
| other.swift:57:16:57:16 | remoteString | semmle.label | remoteString |
|
||||
| sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) |
|
||||
| sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | semmle.label | unsafeQuery1 |
|
||||
| sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | semmle.label | unsafeQuery2 |
|
||||
@@ -336,6 +351,12 @@ subpaths
|
||||
| SQLite.swift:117:16:117:16 | unsafeQuery1 | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:117:16:117:16 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| SQLite.swift:119:16:119:16 | unsafeQuery1 | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:119:16:119:16 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| SQLite.swift:132:20:132:20 | remoteString | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | SQLite.swift:132:20:132:20 | remoteString | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:50:22:50:22 | remoteString | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:50:22:50:22 | remoteString | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:52:14:52:14 | remoteString | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:52:14:52:14 | remoteString | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:53:14:53:14 | remoteString | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:53:14:53:14 | remoteString | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:54:14:54:43 | call to NSString.init(string:) | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:54:14:54:43 | call to NSString.init(string:) | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:55:14:55:14 | remoteString | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:55:14:55:14 | remoteString | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| other.swift:57:16:57:16 | remoteString | other.swift:46:25:46:79 | call to String.init(contentsOf:) | other.swift:57:16:57:16 | remoteString | This query depends on a $@. | other.swift:46:25:46:79 | call to String.init(contentsOf:) | user-provided value |
|
||||
| sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | user-provided value |
|
||||
| sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | user-provided value |
|
||||
| sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to String.init(contentsOf:) | user-provided value |
|
||||
|
||||
64
swift/ql/test/query-tests/Security/CWE-089/other.swift
Normal file
64
swift/ql/test/query-tests/Security/CWE-089/other.swift
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
// --- stubs ---
|
||||
|
||||
struct URL
|
||||
{
|
||||
init?(string: String) {}
|
||||
}
|
||||
|
||||
extension String {
|
||||
init(contentsOf: URL) throws {
|
||||
self.init("")
|
||||
}
|
||||
}
|
||||
|
||||
class NSObject {
|
||||
}
|
||||
|
||||
class NSString : NSObject {
|
||||
init(string: String) { }
|
||||
}
|
||||
|
||||
class Sql {
|
||||
}
|
||||
|
||||
class MyDatabase {
|
||||
init(sql code: String? = nil) { }
|
||||
|
||||
func execute1(_ sql: String) { }
|
||||
func execute2(_ sql: String?) { }
|
||||
func execute3(_ sql: NSString) { }
|
||||
func execute4(_ sql: Sql) { }
|
||||
|
||||
func query(sql: String) { }
|
||||
func query(sqlLiteral: String) { }
|
||||
func query(sqlStatement: String) { }
|
||||
func query(sqliteStatement: String) { }
|
||||
|
||||
// non-examples
|
||||
func doSomething(sqlIndex: Int) { }
|
||||
func doSomething(sqliteContext: Sql) { }
|
||||
}
|
||||
|
||||
// --- tests ---
|
||||
|
||||
func test_heuristic(db: MyDatabase) throws {
|
||||
let remoteString = try String(contentsOf: URL(string: "http://example.com/")!)
|
||||
|
||||
_ = MyDatabase() // GOOD
|
||||
_ = MyDatabase(sql: "some_fixed_sql") // GOOD
|
||||
_ = MyDatabase(sql: remoteString) // BAD
|
||||
|
||||
db.execute1(remoteString) // BAD
|
||||
db.execute2(remoteString) // BAD
|
||||
db.execute3(NSString(string: remoteString)) // BAD
|
||||
db.execute4(remoteString as! Sql) // BAD
|
||||
|
||||
db.query(sql: remoteString) // BAD
|
||||
db.query(sqlLiteral: remoteString) // BAD [NOT DETECTED]
|
||||
db.query(sqlStatement: remoteString) // BAD [NOT DETECTED]
|
||||
db.query(sqliteStatement: remoteString) // BAD [NOT DETECTED]
|
||||
|
||||
db.doSomething(sqlIndex: Int(remoteString) ?? 0) // GOOD
|
||||
db.doSomething(sqliteContext: remoteString as! Sql) // GOOD
|
||||
}
|
||||
Reference in New Issue
Block a user