Merge pull request #14502 from geoffw0/xmlquery

Swift: Model RawRepresentable
This commit is contained in:
Geoffrey White
2023-10-24 16:25:15 +01:00
committed by GitHub
6 changed files with 102 additions and 21 deletions

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Added taint flow models for `RawRepresentable`.

View File

@@ -0,0 +1,28 @@
/**
* Provides models the `RawRepresentable` Swift class.
*/
import swift
private import codeql.swift.dataflow.DataFlow
private import codeql.swift.dataflow.ExternalFlow
private import codeql.swift.dataflow.FlowSteps
/**
* A model for `RawRepresentable` class members that permit taint flow.
*/
private class RawRepresentableSummaries extends SummaryModelCsv {
override predicate row(string row) {
row = ";RawRepresentable;true;init(rawValue:);;;Argument[0];ReturnValue;taint"
}
}
/**
* A content implying that, if a `RawRepresentable` is tainted, then the
* `rawValue` field is tainted as well. This model has been extended to assume
* that any object's `rawValue` field also inherits taint.
*/
private class RawRepresentableFieldsInheritTaint extends TaintInheritingContent,
DataFlow::Content::FieldContent
{
RawRepresentableFieldsInheritTaint() { this.getField().getName() = "rawValue" }
}

View File

@@ -17,6 +17,7 @@ private import NsObject
private import NsString
private import NsUrl
private import Numeric
private import RawRepresentable
private import PointerTypes
private import Sequence
private import Set

View File

@@ -172,31 +172,12 @@ private class Libxml2XxeSink extends XxeSink {
Libxml2XxeSink() {
exists(Libxml2ParseCall c, Libxml2BadOption opt |
this.asExpr() = c.getXml() and
lib2xmlOptionLocalTaintStep*(DataFlow::exprNode(opt.getAnAccess()),
TaintTracking::localTaintStep*(DataFlow::exprNode(opt.getAnAccess()),
DataFlow::exprNode(c.getOptions()))
)
}
}
/**
* Holds if taint can flow from `source` to `sink` in one local step,
* including bitwise operations, accesses to `.rawValue`, and casts to `Int32`.
*/
private predicate lib2xmlOptionLocalTaintStep(DataFlow::Node source, DataFlow::Node sink) {
TaintTracking::localTaintStep(source, sink)
or
exists(MemberRefExpr rawValue | rawValue.getMember().(VarDecl).getName() = "rawValue" |
source.asExpr() = rawValue.getBase() and sink.asExpr() = rawValue
)
or
exists(ApplyExpr int32Init |
int32Init.getStaticTarget().(Initializer).getEnclosingDecl().asNominalTypeDecl().getName() =
"SignedInteger"
|
source.asExpr() = int32Init.getAnArgument().getExpr() and sink.asExpr() = int32Init
)
}
/**
* A sink defined in a CSV model.
*/

View File

@@ -0,0 +1,66 @@
// --- stubs ---
// --- tests ---
func sourceInt() -> Int { return 0 }
func sourceUInt() -> UInt { return 0 }
func sink(arg: Any) {}
// ---
enum MyRawRepresentable : RawRepresentable {
case valueOne
case valueTwo
init?(rawValue: Int) {
switch rawValue {
case 1: self = .valueOne
case 2: self = .valueTwo
default: return nil
}
}
var rawValue: Int {
switch self {
case .valueOne: return 1
case .valueTwo: return 2
}
}
}
func testRawRepresentable() {
let rr1 = MyRawRepresentable.valueOne
let rr2 = MyRawRepresentable(rawValue: 1)!
let rr3 = MyRawRepresentable(rawValue: sourceInt())!
sink(arg: rr1)
sink(arg: rr2)
sink(arg: rr3) // $ tainted=35
sink(arg: rr1.rawValue)
sink(arg: rr2.rawValue)
sink(arg: rr3.rawValue) // $ tainted=35
}
// ---
struct MyOptionSet : OptionSet {
let rawValue: UInt
static let red = MyOptionSet(rawValue: 1 << 0)
static let green = MyOptionSet(rawValue: 1 << 1)
static let blue = MyOptionSet(rawValue: 1 << 2)
}
func testOptionSet() {
sink(arg: MyOptionSet.red)
sink(arg: MyOptionSet([.red, .green]))
sink(arg: MyOptionSet(rawValue: 0))
sink(arg: MyOptionSet(rawValue: sourceUInt())) // $ tainted=60
sink(arg: MyOptionSet.red.rawValue)
sink(arg: MyOptionSet([.red, .green]).rawValue)
sink(arg: MyOptionSet(rawValue: 0).rawValue)
sink(arg: MyOptionSet(rawValue: sourceUInt()).rawValue) // $ tainted=65
}

View File

@@ -1,2 +1,2 @@
failures
testFailures
failures