Skip to content

Commit

Permalink
Merge pull request #13276 from geoffw0/sqlpathinject
Browse files Browse the repository at this point in the history
Swift: Add path injection sinks for sqlite3 and SQLite.swift
  • Loading branch information
geoffw0 authored Sep 12, 2023
2 parents 596f701 + 3fd5de8 commit 0d7769f
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 89 deletions.
32 changes: 32 additions & 0 deletions swift/ql/lib/codeql/swift/elements/decl/EnumElementDecl.qll
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
private import codeql.swift.generated.decl.EnumElementDecl
private import codeql.swift.elements.decl.EnumDecl

/**
* An enum element declaration, for example `enumElement` and `anotherEnumElement` in:
* ```
* enum MyEnum {
* case enumElement
* case anotherEnumElement(Int)
* }
* ```
*/
class EnumElementDecl extends Generated::EnumElementDecl {
override string toString() { result = this.getName() }

/**
* Holds if this enum element declaration is called `enumElementName` and is a member of an
* enum called `enumName`.
*/
cached
predicate hasQualifiedName(string enumName, string enumElementName) {
this.getName() = enumElementName and
exists(EnumDecl d |
d.getFullName() = enumName and
d.getAMember() = this
)
}

/**
* Holds if this enum element declaration is called `enumElementName` and is a member of an
* enumcalled `enumName` in a module called `moduleName`.
*/
predicate hasQualifiedName(string moduleName, string enumName, string enumElementName) {
this.hasQualifiedName(enumName, enumElementName) and
this.getModule().getFullName() = moduleName
}
}
9 changes: 8 additions & 1 deletion swift/ql/lib/codeql/swift/elements/expr/EnumElementExpr.qll
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ private import codeql.swift.elements.expr.MethodLookupExpr
private import codeql.swift.elements.decl.EnumElementDecl

/**
* An expression that constructs a case of an enum.
* An expression that references a case of an enum. For example both `enumElement` in:
* ```
* let value = MyEnum.enumElement
* ...
* switch (anotherValue) {
* case .enumElement:
* ...
* ```
*/
class EnumElementExpr extends Expr {
EnumElementDecl decl;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ class ManagedBufferPointerType extends BoundGenericType {
private class PointerSummaries extends SummaryModelCsv {
override predicate row(string row) {
row =
";UnsafeMutableBufferPointer;true;update(repeating:);;;Argument[0];Argument[-1].CollectionElement;value"
[
";UnsafeMutablePointer;true;init(mutating:);;;Argument[0];ReturnValue;taint",
";UnsafeMutableBufferPointer;true;update(repeating:);;;Argument[0];Argument[-1].CollectionElement;value",
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ private import NsData
private import NsObject
private import NsString
private import NsUrl
private import PointerTypes
private import Sequence
private import Set
private import String
Expand Down
39 changes: 39 additions & 0 deletions swift/ql/lib/codeql/swift/security/PathInjectionExtensions.qll
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,34 @@ private class DefaultPathInjectionSink extends PathInjectionSink {
DefaultPathInjectionSink() { sinkNode(this, "path-injection") }
}

/**
* A sink that is a write to a global variable.
*/
private class GlobalVariablePathInjectionSink extends PathInjectionSink {
GlobalVariablePathInjectionSink() {
// value assigned to the sqlite3 global variable `sqlite3_temp_directory`
// the sink should be the `DeclRefExpr` itself, but we don't currently have taint flow to globals.
exists(AssignExpr ae |
ae.getDest().(DeclRefExpr).getDecl().(VarDecl).getName() = "sqlite3_temp_directory" and
ae.getSource() = this.asExpr()
)
}
}

/**
* A sink that is an argument to an enum element.
*/
private class EnumConstructorPathInjectionSink extends PathInjectionSink {
EnumConstructorPathInjectionSink() {
// first argument to SQLite.swift's `Connection.Location.uri(_:parameters:)`
exists(ApplyExpr ae, EnumElementDecl decl |
ae.getFunction().(MethodLookupExpr).getMember() = decl and
decl.hasQualifiedName("Connection.Location", "uri") and
this.asExpr() = ae.getArgument(0).getExpr()
)
}
}

private class DefaultPathInjectionBarrier extends PathInjectionBarrier {
DefaultPathInjectionBarrier() {
// This is a simplified implementation.
Expand Down Expand Up @@ -130,6 +158,17 @@ private class PathInjectionSinks extends SinkModelCsv {
";Realm.Configuration;true;init(fileURL:inMemoryIdentifier:syncConfiguration:encryptionKey:readOnly:schemaVersion:migrationBlock:deleteRealmIfMigrationNeeded:shouldCompactOnLaunch:objectTypes:seedFilePath:);;;Argument[10];path-injection",
";Realm.Configuration;true;fileURL;;;PostUpdate;path-injection",
";Realm.Configuration;true;seedFilePath;;;PostUpdate;path-injection",
// sqlite3
";;false;sqlite3_open(_:_:);;;Argument[0];path-injection",
";;false;sqlite3_open16(_:_:);;;Argument[0];path-injection",
";;false;sqlite3_open_v2(_:_:_:_:);;;Argument[0];path-injection",
";;false;sqlite3_database_file_object(_:);;;Argument[0];path-injection",
";;false;sqlite3_filename_database(_:);;;Argument[0];path-injection",
";;false;sqlite3_filename_journal(_:);;;Argument[0];path-injection",
";;false;sqlite3_filename_wal(_:);;;Argument[0];path-injection",
";;false;sqlite3_free_filename(_:);;;Argument[0];path-injection",
// SQLite.swift
";Connection;true;init(_:readonly:);;;Argument[0];path-injection",
]
}
}
4 changes: 4 additions & 0 deletions swift/ql/src/change-notes/2023-05-23-path-injection-sinks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added sqlite3 and SQLite.swift path injection sinks for the `swift/path-injection` query.
Loading

0 comments on commit 0d7769f

Please sign in to comment.