Swift: Add heuristic sink. We don't catch everything, but the simple heuristic was better than anything else I tried.

This commit is contained in:
Geoffrey White
2023-11-14 10:03:47 +00:00
parent 80cfb934ce
commit 6783707e2c
3 changed files with 47 additions and 6 deletions

View File

@@ -147,6 +147,26 @@ private class GrdbDefaultSqlInjectionSink extends SqlInjectionSink {
}
}
/**
* An SQL injection sink that is determined by imprecise methods.
*/
private class HeuristicSqlInjectionSink extends SqlInjectionSink {
HeuristicSqlInjectionSink() {
// by parameter name
exists(CallExpr ce, int ix, ParamDecl pd |
pd.getName() = "sql" and
pd = ce.getStaticTarget().getParam(ix) 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.
*/

View File

@@ -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 |

View File

@@ -47,14 +47,14 @@ func test_heuristic(db: MyDatabase) throws {
_ = MyDatabase()
_ = MyDatabase(sql: "some_fixed_sql")
_ = MyDatabase(sql: remoteString) // BAD [NOT DETECTED]
_ = MyDatabase(sql: remoteString) // BAD
db.execute1(remoteString) // BAD [NOT DETECTED]
db.execute2(remoteString) // BAD [NOT DETECTED]
db.execute3(NSString(string: remoteString)) // BAD [NOT DETECTED]
db.execute4(remoteString as! Sql) // BAD [NOT DETECTED]
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 [NOT DETECTED]
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]