Merge pull request #9972 from MathiasVP/swift-taint-through-interpolated-strings

Swift: Taint through interpolated strings
This commit is contained in:
Mathias Vorreiter Pedersen
2022-08-05 15:55:35 +01:00
committed by GitHub
17 changed files with 545 additions and 43 deletions

View File

@@ -96,21 +96,31 @@ module Stmts {
override predicate propagatesAbnormal(ControlFlowElement node) { none() }
private predicate isBodyOfTapExpr() { any(TapExpr tap).getBody() = ast }
// Note: If the brace statement is the body of a `TapExpr`, the first element is the variable
// declaration (see https://github.com/apple/swift/blob/main/include/swift/AST/Expr.h#L848)
// that's initialized by the `TapExpr`. In `TapExprTree` we've already visited this declaration,
// along with its initializer. So we skip the first element here.
private AstNode getFirstElement() {
if this.isBodyOfTapExpr() then result = ast.getElement(1) else result = ast.getFirstElement()
}
override predicate first(ControlFlowElement first) {
this.firstInner(first)
or
not exists(ast.getFirstElement()) and first.asAstNode() = ast
not exists(this.getFirstElement()) and first.asAstNode() = ast
}
override predicate last(ControlFlowElement last, Completion c) {
this.lastInner(last, c)
or
not exists(ast.getFirstElement()) and
not exists(this.getFirstElement()) and
last.asAstNode() = ast and
c instanceof SimpleCompletion
}
predicate firstInner(ControlFlowElement first) { astFirst(ast.getFirstElement(), first) }
predicate firstInner(ControlFlowElement first) { astFirst(this.getFirstElement(), first) }
/** Gets the body of the i'th `defer` statement. */
private BraceStmt getDeferStmtBody(int i) {
@@ -1334,10 +1344,38 @@ module Exprs {
override InterpolatedStringLiteralExpr ast;
final override ControlFlowElement getChildElement(int i) {
none() // TODO
i = 0 and
result.asAstNode() = ast.getAppendingExpr().getFullyConverted()
}
}
/** Control-flow for a `TapExpr`. See the QLDoc for `TapExpr` for the semantics of a `TapExpr`. */
private class TapExprTree extends AstStandardPostOrderTree {
override TapExpr ast;
final override ControlFlowElement getChildElement(int i) {
// We first visit the local variable declaration.
i = 0 and
result.asAstNode() = ast.getVar()
or
// Then we visit the expression that gives the local variable its initial value.
i = 1 and
result.asAstNode() = ast.getSubExpr().getFullyConverted()
or
// And finally, we visit the body that potentially mutates the local variable.
// Note that the CFG for the body will skip the first element in the
// body because it's guarenteed to be the variable declaration
// that we've already visited at i = 0. See the explanation
// in `BraceStmtTree` for why this is necessary.
i = 2 and
result.asAstNode() = ast.getBody()
}
}
private class OpaqueValueExprTree extends AstLeafTree {
override OpaqueValueExpr ast;
}
module DeclRefExprs {
class DeclRefExprLValueTree extends AstLeafTree {
override DeclRefExpr ast;

View File

@@ -80,7 +80,7 @@ module Ssa {
cached
predicate isInoutDef(ExprCfgNode argument) {
exists(
CallExpr c, BasicBlock bb, int blockIndex, int argIndex, VarDecl v, InOutExpr argExpr // TODO: use CFG node for assignment expr
ApplyExpr c, BasicBlock bb, int blockIndex, int argIndex, VarDecl v, InOutExpr argExpr // TODO: use CFG node for assignment expr
|
this.definesAt(v, bb, blockIndex) and
bb.getNode(blockIndex).getNode().asAstNode() = c and

View File

@@ -64,10 +64,7 @@ private module Cached {
TExprNode(CfgNode n, Expr e) { hasExprNode(n, e) } or
TSsaDefinitionNode(Ssa::Definition def) or
TInoutReturnNode(ParamDecl param) { param.isInout() } or
TInOutUpdateNode(ParamDecl param, CallExpr call) {
param.isInout() and
call.getStaticTarget() = param.getDeclaringFunction()
} or
TInOutUpdateNode(Argument arg) { arg.getExpr() instanceof InOutExpr } or
TSummaryNode(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state)
private predicate hasExprNode(CfgNode n, Expr e) {
@@ -202,7 +199,7 @@ abstract class ArgumentNode extends Node {
private module ArgumentNodes {
class NormalArgumentNode extends ExprNode, ArgumentNode {
NormalArgumentNode() { exists(CallExpr call | call.getAnArgument().getExpr() = this.asExpr()) }
NormalArgumentNode() { exists(ApplyExpr call | call.getAnArgument().getExpr() = this.asExpr()) }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call.asCall().getArgument(pos.(PositionalArgumentPosition).getIndex()).getExpr() =
@@ -280,23 +277,22 @@ private module OutNodes {
}
class InOutUpdateNode extends OutNode, TInOutUpdateNode, NodeImpl {
ParamDecl param;
CallExpr call;
Argument arg;
InOutUpdateNode() { this = TInOutUpdateNode(param, call) }
InOutUpdateNode() { this = TInOutUpdateNode(arg) }
override DataFlowCall getCall(ReturnKind kind) {
result.asCall().getExpr() = call and
kind.(ParamReturnKind).getIndex() = param.getIndex()
result.asCall().getExpr() = arg.getApplyExpr() and
kind.(ParamReturnKind).getIndex() = arg.getIndex()
}
override DataFlowCallable getEnclosingCallable() {
result = this.getCall(_).getEnclosingCallable()
}
override Location getLocationImpl() { result = call.getLocation() }
override Location getLocationImpl() { result = arg.getLocation() }
override string toStringImpl() { result = param.toString() }
override string toStringImpl() { result = arg.toString() }
}
}

View File

@@ -29,7 +29,7 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
certain = true
)
or
exists(CallExpr call, Argument arg |
exists(ApplyExpr call, Argument arg |
arg.getExpr().(InOutExpr).getSubExpr() = v.getAnAccess() and
call.getAnArgument() = arg and
bb.getNode(i).getNode().asAstNode() = call and
@@ -39,6 +39,13 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
v instanceof ParamDecl and
bb.getNode(i).getNode().asAstNode() = v and
certain = true
or
// Mark the subexpression as a write of the local variable declared in the `TapExpr`.
exists(TapExpr tap |
v = tap.getVar() and
bb.getNode(i).getNode().asAstNode() = tap.getSubExpr() and
certain = true
)
}
private predicate isLValue(DeclRefExpr ref) { any(AssignExpr assign).getDest() = ref }
@@ -58,4 +65,11 @@ predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain)
bb.getScope() = func and
certain = true
)
or
// Mark the `TapExpr` as a read of the of the local variable.
exists(TapExpr tap |
v = tap.getVar() and
bb.getNode(i).getNode().asAstNode() = tap and
certain = true
)
}

View File

@@ -2,6 +2,8 @@ private import swift
private import DataFlowPrivate
private import TaintTrackingPublic
private import codeql.swift.dataflow.DataFlow
private import codeql.swift.dataflow.Ssa
private import codeql.swift.controlflow.CfgNodes
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
@@ -16,7 +18,30 @@ private module Cached {
* in all global taint flow configurations.
*/
cached
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Flow through one argument of `appendLiteral` and `appendInterpolation` and to the second argument.
// This is needed for string interpolation generated by the compiler. An interpolated string
// like `"I am \(n) years old."` is represented as
// ```
// $interpolated = ""
// appendLiteral(&$interpolated, "I am ")
// appendInterpolation(&$interpolated, n)
// appendLiteral(&$interpolated, " years old.")
// ```
exists(ApplyExpr apply1, ApplyExpr apply2, ExprCfgNode e |
nodeFrom.asExpr() = [apply1, apply2].getAnArgument().getExpr() and
apply1.getFunction() = apply2 and
apply2.getStaticTarget().getName() = ["appendLiteral(_:)", "appendInterpolation(_:)"] and
e.getExpr() = apply2.getAnArgument().getExpr() and
nodeTo.asDefinition().(Ssa::WriteDefinition).isInoutDef(e)
)
or
// Flow from the computation of the interpolated string literal to the result of the interpolation.
exists(InterpolatedStringLiteralExpr interpolated |
nodeTo.asExpr() = interpolated and
nodeFrom.asExpr() = interpolated.getAppendingExpr()
)
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local

View File

@@ -5,4 +5,6 @@ class Argument extends ArgumentBase {
override string toString() { result = this.getLabel() + ": " + this.getExpr().toString() }
int getIndex() { any(ApplyExpr apply).getArgument(result) = this }
ApplyExpr getApplyExpr() { result.getAnArgument() = this }
}

View File

@@ -1,4 +1,11 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.expr.TapExpr
/**
* A `TapExpr` is an internal expression generated by the Swift compiler.
*
* If `e` is a `TapExpr`, the semantics of evaluating `e` is:
* 1. Create a local variable `e.getVar()` and assign it the value `e.getSubExpr()`.
* 2. Execute `e.getBody()` which potentially modifies the local variable.
* 3. Return the value of the local variable.
*/
class TapExpr extends TapExprBase { }

View File

@@ -324,7 +324,6 @@ cfg.swift:
#-----| -> error
# 40| print(_:separator:terminator:)
#-----| -> "..."
# 40| call to print(_:separator:terminator:)
#-----| -> 0
@@ -341,12 +340,64 @@ cfg.swift:
# 40| (Any) ...
#-----| -> [...]
# 40| OpaqueValueExpr
# 40| TapExpr
#-----| -> "..."
# 40| Unknown error
#-----| -> call to ...
# 40| [...]
#-----| -> default separator
# 40| [...]
#-----| -> [...]
# 40| call to ...
#-----| -> appendInterpolation(_:)
# 40| $interpolation
#-----| -> &...
# 40| &...
#-----| -> call to appendLiteral(_:)
# 40| call to appendLiteral(_:)
#-----| -> Unknown error
# 40| $interpolation
#-----| -> &...
# 40| &...
#-----| -> call to appendInterpolation(_:)
# 40| appendInterpolation(_:)
#-----| -> $interpolation
# 40| call to appendInterpolation(_:)
#-----| -> error
# 40| call to ...
# 40| error
#-----| -> call to ...
# 40|
#-----| -> call to ...
# 40| $interpolation
#-----| -> &...
# 40| &...
#-----| -> call to appendLiteral(_:)
# 40| call to ...
#-----| -> TapExpr
# 40| call to appendLiteral(_:)
#-----| ->
# 42| return ...
#-----| return -> exit tryCatch(x:) (normal)
@@ -2817,14 +2868,179 @@ cfg.swift:
#-----| -> y
# 262| y
#-----| -> "..."
# 263| return ...
#-----| return -> exit interpolatedString(x:y:) (normal)
# 263|
#-----| -> call to ...
# 263| "..."
#-----| -> return ...
# 263| OpaqueValueExpr
# 263| TapExpr
#-----| -> "..."
# 263| call to ...
#-----| -> appendInterpolation(_:)
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendLiteral(_:)
# 263| call to appendLiteral(_:)
#-----| ->
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendInterpolation(_:)
# 263| appendInterpolation(_:)
#-----| -> $interpolation
# 263| call to appendInterpolation(_:)
#-----| -> x
# 263| call to ...
# 263| x
#-----| -> call to ...
# 263| +
#-----| -> call to ...
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendLiteral(_:)
# 263| call to ...
#-----| -> appendInterpolation(_:)
# 263| call to appendLiteral(_:)
#-----| -> +
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendInterpolation(_:)
# 263| appendInterpolation(_:)
#-----| -> $interpolation
# 263| call to appendInterpolation(_:)
#-----| -> y
# 263| call to ...
# 263| y
#-----| -> call to ...
# 263| is equal to
#-----| -> call to ...
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendLiteral(_:)
# 263| call to ...
#-----| -> appendInterpolation(_:)
# 263| call to appendLiteral(_:)
#-----| -> is equal to
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendInterpolation(_:)
# 263| appendInterpolation(_:)
#-----| -> $interpolation
# 263| call to appendInterpolation(_:)
#-----| -> +(_:_:)
# 263| call to ...
# 263| x
#-----| -> y
# 263| ... call to +(_:_:) ...
#-----| -> call to ...
# 263| +(_:_:)
#-----| -> Int.Type
# 263| Int.Type
#-----| -> call to +(_:_:)
# 263| call to +(_:_:)
#-----| -> x
# 263| y
#-----| -> ... call to +(_:_:) ...
# 263| and here is a zero:
#-----| -> call to ...
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendLiteral(_:)
# 263| call to ...
#-----| -> appendInterpolation(_:)
# 263| call to appendLiteral(_:)
#-----| -> and here is a zero:
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendInterpolation(_:)
# 263| appendInterpolation(_:)
#-----| -> $interpolation
# 263| call to appendInterpolation(_:)
#-----| -> returnZero()
# 263| call to ...
# 263| returnZero()
#-----| -> call to returnZero()
# 263| call to returnZero()
#-----| -> call to ...
# 263|
#-----| -> call to ...
# 263| $interpolation
#-----| -> &...
# 263| &...
#-----| -> call to appendLiteral(_:)
# 263| call to ...
#-----| -> TapExpr
# 263| call to appendLiteral(_:)
#-----| ->
# 266| enter testSubscriptExpr()
#-----| -> testSubscriptExpr()

View File

@@ -12,23 +12,23 @@ edges
| test.swift:29:26:29:29 | y : | test.swift:31:15:31:15 | y |
| test.swift:35:12:35:19 | call to source() : | test.swift:39:15:39:29 | call to callee_source() |
| test.swift:43:19:43:26 | call to source() : | test.swift:50:15:50:15 | t |
| test.swift:53:1:56:1 | arg[return] : | test.swift:61:5:61:24 | arg : |
| test.swift:53:1:56:1 | arg[return] : | test.swift:61:17:61:23 | arg: &... : |
| test.swift:54:11:54:18 | call to source() : | test.swift:53:1:56:1 | arg[return] : |
| test.swift:61:5:61:24 | arg : | test.swift:62:15:62:15 | x |
| test.swift:61:17:61:23 | arg: &... : | test.swift:62:15:62:15 | x |
| test.swift:65:16:65:28 | WriteDef : | test.swift:65:1:70:1 | arg2[return] : |
| test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : |
| test.swift:73:18:73:25 | call to source() : | test.swift:75:21:75:22 | &... : |
| test.swift:75:5:75:33 | arg2 : | test.swift:77:15:77:15 | y |
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | WriteDef : |
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : |
| test.swift:75:21:75:22 | &... : | test.swift:75:5:75:33 | arg2 : |
| test.swift:80:1:82:1 | arg[return] : | test.swift:97:9:97:41 | arg : |
| test.swift:75:21:75:22 | &... : | test.swift:75:25:75:32 | arg2: &... : |
| test.swift:75:25:75:32 | arg2: &... : | test.swift:77:15:77:15 | y |
| test.swift:80:1:82:1 | arg[return] : | test.swift:97:34:97:40 | arg: &... : |
| test.swift:81:11:81:18 | call to source() : | test.swift:80:1:82:1 | arg[return] : |
| test.swift:84:1:91:1 | arg[return] : | test.swift:104:9:104:54 | arg : |
| test.swift:84:1:91:1 | arg[return] : | test.swift:104:35:104:41 | arg: &... : |
| test.swift:86:15:86:22 | call to source() : | test.swift:84:1:91:1 | arg[return] : |
| test.swift:89:15:89:22 | call to source() : | test.swift:84:1:91:1 | arg[return] : |
| test.swift:97:9:97:41 | arg : | test.swift:98:19:98:19 | x |
| test.swift:104:9:104:54 | arg : | test.swift:105:19:105:19 | x |
| test.swift:97:34:97:40 | arg: &... : | test.swift:98:19:98:19 | x |
| test.swift:104:35:104:41 | arg: &... : | test.swift:105:19:105:19 | x |
| test.swift:109:9:109:14 | WriteDef : | test.swift:110:12:110:12 | arg : |
| test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : |
| test.swift:113:14:113:19 | WriteDef : | test.swift:114:19:114:19 | arg : |
@@ -88,7 +88,7 @@ nodes
| test.swift:50:15:50:15 | t | semmle.label | t |
| test.swift:53:1:56:1 | arg[return] : | semmle.label | arg[return] : |
| test.swift:54:11:54:18 | call to source() : | semmle.label | call to source() : |
| test.swift:61:5:61:24 | arg : | semmle.label | arg : |
| test.swift:61:17:61:23 | arg: &... : | semmle.label | arg: &... : |
| test.swift:62:15:62:15 | x | semmle.label | x |
| test.swift:65:1:70:1 | arg2[return] : | semmle.label | arg2[return] : |
| test.swift:65:16:65:28 | WriteDef : | semmle.label | WriteDef : |
@@ -96,17 +96,17 @@ nodes
| test.swift:65:16:65:28 | arg1 : | semmle.label | WriteDef : |
| test.swift:65:16:65:28 | arg1 : | semmle.label | arg1 : |
| test.swift:73:18:73:25 | call to source() : | semmle.label | call to source() : |
| test.swift:75:5:75:33 | arg2 : | semmle.label | arg2 : |
| test.swift:75:21:75:22 | &... : | semmle.label | &... : |
| test.swift:75:25:75:32 | arg2: &... : | semmle.label | arg2: &... : |
| test.swift:77:15:77:15 | y | semmle.label | y |
| test.swift:80:1:82:1 | arg[return] : | semmle.label | arg[return] : |
| test.swift:81:11:81:18 | call to source() : | semmle.label | call to source() : |
| test.swift:84:1:91:1 | arg[return] : | semmle.label | arg[return] : |
| test.swift:86:15:86:22 | call to source() : | semmle.label | call to source() : |
| test.swift:89:15:89:22 | call to source() : | semmle.label | call to source() : |
| test.swift:97:9:97:41 | arg : | semmle.label | arg : |
| test.swift:97:34:97:40 | arg: &... : | semmle.label | arg: &... : |
| test.swift:98:19:98:19 | x | semmle.label | x |
| test.swift:104:9:104:54 | arg : | semmle.label | arg : |
| test.swift:104:35:104:41 | arg: &... : | semmle.label | arg: &... : |
| test.swift:105:19:105:19 | x | semmle.label | x |
| test.swift:109:9:109:14 | WriteDef : | semmle.label | WriteDef : |
| test.swift:109:9:109:14 | WriteDef : | semmle.label | arg : |
@@ -155,8 +155,8 @@ nodes
| test.swift:157:16:157:23 | call to source() : | semmle.label | call to source() : |
| test.swift:159:16:159:29 | call to ... : | semmle.label | call to ... : |
subpaths
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | WriteDef : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:5:75:33 | arg2 : |
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:5:75:33 | arg2 : |
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | WriteDef : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:25:75:32 | arg2: &... : |
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:25:75:32 | arg2: &... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | WriteDef : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
| test.swift:114:19:114:19 | arg : | test.swift:123:10:123:13 | WriteDef : | test.swift:124:16:124:16 | i : | test.swift:114:12:114:22 | call to ... : |

View File

@@ -29,7 +29,7 @@
| test.swift:59:18:59:18 | 0 | test.swift:59:9:59:12 | WriteDef |
| test.swift:60:15:60:15 | x | test.swift:61:23:61:23 | x |
| test.swift:61:5:61:24 | WriteDef | test.swift:62:15:62:15 | x |
| test.swift:61:5:61:24 | arg | test.swift:61:5:61:24 | WriteDef |
| test.swift:61:17:61:23 | arg: &... | test.swift:61:5:61:24 | WriteDef |
| test.swift:61:23:61:23 | x | test.swift:61:22:61:23 | &... |
| test.swift:65:16:65:28 | WriteDef | test.swift:66:21:66:21 | arg1 |
| test.swift:65:16:65:28 | arg1 | test.swift:66:21:66:21 | arg1 |
@@ -47,9 +47,9 @@
| test.swift:74:18:74:18 | 0 | test.swift:74:9:74:12 | WriteDef |
| test.swift:75:5:75:33 | WriteDef | test.swift:76:15:76:15 | x |
| test.swift:75:5:75:33 | WriteDef | test.swift:77:15:77:15 | y |
| test.swift:75:5:75:33 | arg1 | test.swift:75:5:75:33 | WriteDef |
| test.swift:75:5:75:33 | arg2 | test.swift:75:5:75:33 | WriteDef |
| test.swift:75:15:75:22 | arg1: &... | test.swift:75:5:75:33 | WriteDef |
| test.swift:75:22:75:22 | x | test.swift:75:21:75:22 | &... |
| test.swift:75:25:75:32 | arg2: &... | test.swift:75:5:75:33 | WriteDef |
| test.swift:75:32:75:32 | y | test.swift:75:31:75:32 | &... |
| test.swift:81:5:81:18 | WriteDef | test.swift:80:1:82:1 | arg[return] |
| test.swift:81:11:81:18 | call to source() | test.swift:81:5:81:18 | WriteDef |
@@ -66,13 +66,13 @@
| test.swift:95:22:95:22 | 0 | test.swift:95:13:95:16 | WriteDef |
| test.swift:96:19:96:19 | x | test.swift:97:40:97:40 | x |
| test.swift:97:9:97:41 | WriteDef | test.swift:98:19:98:19 | x |
| test.swift:97:9:97:41 | arg | test.swift:97:9:97:41 | WriteDef |
| test.swift:97:34:97:40 | arg: &... | test.swift:97:9:97:41 | WriteDef |
| test.swift:97:40:97:40 | x | test.swift:97:39:97:40 | &... |
| test.swift:102:13:102:16 | WriteDef | test.swift:103:19:103:19 | x |
| test.swift:102:22:102:22 | 0 | test.swift:102:13:102:16 | WriteDef |
| test.swift:103:19:103:19 | x | test.swift:104:41:104:41 | x |
| test.swift:104:9:104:54 | WriteDef | test.swift:105:19:105:19 | x |
| test.swift:104:9:104:54 | arg | test.swift:104:9:104:54 | WriteDef |
| test.swift:104:35:104:41 | arg: &... | test.swift:104:9:104:54 | WriteDef |
| test.swift:104:41:104:41 | x | test.swift:104:40:104:41 | &... |
| test.swift:109:9:109:14 | WriteDef | test.swift:110:12:110:12 | arg |
| test.swift:109:9:109:14 | arg | test.swift:110:12:110:12 | arg |

View File

@@ -0,0 +1,121 @@
| file://:0:0:0:0 | Phi | test.swift:7:14:7:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:9:14:9:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:11:14:11:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:14:14:14:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:16:14:16:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:18:14:18:14 | $interpolation |
| file://:0:0:0:0 | Phi | test.swift:21:14:21:14 | $interpolation |
| test.swift:5:7:5:7 | WriteDef | test.swift:7:16:7:16 | x |
| test.swift:5:11:5:18 | call to source() | test.swift:5:7:5:7 | WriteDef |
| test.swift:7:13:7:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:7:14:7:14 | $interpolation | test.swift:7:14:7:14 | &... |
| test.swift:7:14:7:14 | : &... | test.swift:7:14:7:14 | WriteDef |
| test.swift:7:14:7:14 | WriteDef | test.swift:7:15:7:15 | $interpolation |
| test.swift:7:15:7:15 | $interpolation | test.swift:7:15:7:15 | &... |
| test.swift:7:15:7:15 | : &... | test.swift:7:15:7:15 | WriteDef |
| test.swift:7:15:7:15 | WriteDef | test.swift:7:18:7:18 | $interpolation |
| test.swift:7:16:7:16 | x | test.swift:9:16:9:16 | x |
| test.swift:7:18:7:18 | $interpolation | test.swift:7:18:7:18 | &... |
| test.swift:7:18:7:18 | : &... | test.swift:7:18:7:18 | WriteDef |
| test.swift:7:18:7:18 | WriteDef | test.swift:7:13:7:13 | TapExpr |
| test.swift:9:13:9:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:9:14:9:14 | $interpolation | test.swift:9:14:9:14 | &... |
| test.swift:9:14:9:14 | : &... | test.swift:9:14:9:14 | WriteDef |
| test.swift:9:14:9:14 | WriteDef | test.swift:9:15:9:15 | $interpolation |
| test.swift:9:15:9:15 | $interpolation | test.swift:9:15:9:15 | &... |
| test.swift:9:15:9:15 | : &... | test.swift:9:15:9:15 | WriteDef |
| test.swift:9:15:9:15 | WriteDef | test.swift:9:18:9:18 | $interpolation |
| test.swift:9:16:9:16 | x | test.swift:9:21:9:21 | x |
| test.swift:9:18:9:18 | $interpolation | test.swift:9:18:9:18 | &... |
| test.swift:9:18:9:18 | : &... | test.swift:9:18:9:18 | WriteDef |
| test.swift:9:18:9:18 | WriteDef | test.swift:9:20:9:20 | $interpolation |
| test.swift:9:20:9:20 | $interpolation | test.swift:9:20:9:20 | &... |
| test.swift:9:20:9:20 | : &... | test.swift:9:20:9:20 | WriteDef |
| test.swift:9:20:9:20 | WriteDef | test.swift:9:23:9:23 | $interpolation |
| test.swift:9:21:9:21 | x | test.swift:11:16:11:16 | x |
| test.swift:9:23:9:23 | $interpolation | test.swift:9:23:9:23 | &... |
| test.swift:9:23:9:23 | : &... | test.swift:9:23:9:23 | WriteDef |
| test.swift:9:23:9:23 | WriteDef | test.swift:9:13:9:13 | TapExpr |
| test.swift:11:13:11:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:11:14:11:14 | $interpolation | test.swift:11:14:11:14 | &... |
| test.swift:11:14:11:14 | : &... | test.swift:11:14:11:14 | WriteDef |
| test.swift:11:14:11:14 | WriteDef | test.swift:11:15:11:15 | $interpolation |
| test.swift:11:15:11:15 | $interpolation | test.swift:11:15:11:15 | &... |
| test.swift:11:15:11:15 | : &... | test.swift:11:15:11:15 | WriteDef |
| test.swift:11:15:11:15 | WriteDef | test.swift:11:18:11:18 | $interpolation |
| test.swift:11:16:11:16 | x | test.swift:11:26:11:26 | x |
| test.swift:11:18:11:18 | $interpolation | test.swift:11:18:11:18 | &... |
| test.swift:11:18:11:18 | : &... | test.swift:11:18:11:18 | WriteDef |
| test.swift:11:18:11:18 | WriteDef | test.swift:11:20:11:20 | $interpolation |
| test.swift:11:20:11:20 | $interpolation | test.swift:11:20:11:20 | &... |
| test.swift:11:20:11:20 | : &... | test.swift:11:20:11:20 | WriteDef |
| test.swift:11:20:11:20 | WriteDef | test.swift:11:23:11:23 | $interpolation |
| test.swift:11:23:11:23 | $interpolation | test.swift:11:23:11:23 | &... |
| test.swift:11:23:11:23 | : &... | test.swift:11:23:11:23 | WriteDef |
| test.swift:11:23:11:23 | WriteDef | test.swift:11:25:11:25 | $interpolation |
| test.swift:11:25:11:25 | $interpolation | test.swift:11:25:11:25 | &... |
| test.swift:11:25:11:25 | : &... | test.swift:11:25:11:25 | WriteDef |
| test.swift:11:25:11:25 | WriteDef | test.swift:11:28:11:28 | $interpolation |
| test.swift:11:26:11:26 | x | test.swift:16:16:16:16 | x |
| test.swift:11:28:11:28 | $interpolation | test.swift:11:28:11:28 | &... |
| test.swift:11:28:11:28 | : &... | test.swift:11:28:11:28 | WriteDef |
| test.swift:11:28:11:28 | WriteDef | test.swift:11:13:11:13 | TapExpr |
| test.swift:13:7:13:7 | WriteDef | test.swift:14:16:14:16 | y |
| test.swift:13:11:13:11 | 42 | test.swift:13:7:13:7 | WriteDef |
| test.swift:14:13:14:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:14:14:14:14 | $interpolation | test.swift:14:14:14:14 | &... |
| test.swift:14:14:14:14 | : &... | test.swift:14:14:14:14 | WriteDef |
| test.swift:14:14:14:14 | WriteDef | test.swift:14:15:14:15 | $interpolation |
| test.swift:14:15:14:15 | $interpolation | test.swift:14:15:14:15 | &... |
| test.swift:14:15:14:15 | : &... | test.swift:14:15:14:15 | WriteDef |
| test.swift:14:15:14:15 | WriteDef | test.swift:14:18:14:18 | $interpolation |
| test.swift:14:16:14:16 | y | test.swift:16:27:16:27 | y |
| test.swift:14:18:14:18 | $interpolation | test.swift:14:18:14:18 | &... |
| test.swift:14:18:14:18 | : &... | test.swift:14:18:14:18 | WriteDef |
| test.swift:14:18:14:18 | WriteDef | test.swift:14:13:14:13 | TapExpr |
| test.swift:16:13:16:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:16:14:16:14 | $interpolation | test.swift:16:14:16:14 | &... |
| test.swift:16:14:16:14 | : &... | test.swift:16:14:16:14 | WriteDef |
| test.swift:16:14:16:14 | WriteDef | test.swift:16:15:16:15 | $interpolation |
| test.swift:16:15:16:15 | $interpolation | test.swift:16:15:16:15 | &... |
| test.swift:16:15:16:15 | : &... | test.swift:16:15:16:15 | WriteDef |
| test.swift:16:15:16:15 | WriteDef | test.swift:16:18:16:18 | $interpolation |
| test.swift:16:16:16:16 | x | test.swift:18:27:18:27 | x |
| test.swift:16:18:16:18 | $interpolation | test.swift:16:18:16:18 | &... |
| test.swift:16:18:16:18 | : &... | test.swift:16:18:16:18 | WriteDef |
| test.swift:16:18:16:18 | WriteDef | test.swift:16:26:16:26 | $interpolation |
| test.swift:16:26:16:26 | $interpolation | test.swift:16:26:16:26 | &... |
| test.swift:16:26:16:26 | : &... | test.swift:16:26:16:26 | WriteDef |
| test.swift:16:26:16:26 | WriteDef | test.swift:16:29:16:29 | $interpolation |
| test.swift:16:27:16:27 | y | test.swift:18:16:18:16 | y |
| test.swift:16:29:16:29 | $interpolation | test.swift:16:29:16:29 | &... |
| test.swift:16:29:16:29 | : &... | test.swift:16:29:16:29 | WriteDef |
| test.swift:16:29:16:29 | WriteDef | test.swift:16:13:16:13 | TapExpr |
| test.swift:18:13:18:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:18:14:18:14 | $interpolation | test.swift:18:14:18:14 | &... |
| test.swift:18:14:18:14 | : &... | test.swift:18:14:18:14 | WriteDef |
| test.swift:18:14:18:14 | WriteDef | test.swift:18:15:18:15 | $interpolation |
| test.swift:18:15:18:15 | $interpolation | test.swift:18:15:18:15 | &... |
| test.swift:18:15:18:15 | : &... | test.swift:18:15:18:15 | WriteDef |
| test.swift:18:15:18:15 | WriteDef | test.swift:18:18:18:18 | $interpolation |
| test.swift:18:18:18:18 | $interpolation | test.swift:18:18:18:18 | &... |
| test.swift:18:18:18:18 | : &... | test.swift:18:18:18:18 | WriteDef |
| test.swift:18:18:18:18 | WriteDef | test.swift:18:26:18:26 | $interpolation |
| test.swift:18:26:18:26 | $interpolation | test.swift:18:26:18:26 | &... |
| test.swift:18:26:18:26 | : &... | test.swift:18:26:18:26 | WriteDef |
| test.swift:18:26:18:26 | WriteDef | test.swift:18:29:18:29 | $interpolation |
| test.swift:18:29:18:29 | $interpolation | test.swift:18:29:18:29 | &... |
| test.swift:18:29:18:29 | : &... | test.swift:18:29:18:29 | WriteDef |
| test.swift:18:29:18:29 | WriteDef | test.swift:18:13:18:13 | TapExpr |
| test.swift:20:3:20:7 | WriteDef | test.swift:21:16:21:16 | x |
| test.swift:20:7:20:7 | 0 | test.swift:20:3:20:7 | WriteDef |
| test.swift:21:13:21:13 | WriteDef | file://:0:0:0:0 | Phi |
| test.swift:21:14:21:14 | $interpolation | test.swift:21:14:21:14 | &... |
| test.swift:21:14:21:14 | : &... | test.swift:21:14:21:14 | WriteDef |
| test.swift:21:14:21:14 | WriteDef | test.swift:21:15:21:15 | $interpolation |
| test.swift:21:15:21:15 | $interpolation | test.swift:21:15:21:15 | &... |
| test.swift:21:15:21:15 | : &... | test.swift:21:15:21:15 | WriteDef |
| test.swift:21:15:21:15 | WriteDef | test.swift:21:18:21:18 | $interpolation |
| test.swift:21:18:21:18 | $interpolation | test.swift:21:18:21:18 | &... |
| test.swift:21:18:21:18 | : &... | test.swift:21:18:21:18 | WriteDef |
| test.swift:21:18:21:18 | WriteDef | test.swift:21:13:21:13 | TapExpr |

View File

@@ -0,0 +1,6 @@
import swift
import codeql.swift.dataflow.DataFlow
from DataFlow::Node pred, DataFlow::Node succ
where DataFlow::localFlowStep(pred, succ)
select pred, succ

View File

@@ -0,0 +1,20 @@
edges
| test.swift:5:11:5:18 | call to source() : | test.swift:7:13:7:13 | "..." |
| test.swift:5:11:5:18 | call to source() : | test.swift:9:13:9:13 | "..." |
| test.swift:5:11:5:18 | call to source() : | test.swift:11:13:11:13 | "..." |
| test.swift:5:11:5:18 | call to source() : | test.swift:16:13:16:13 | "..." |
| test.swift:5:11:5:18 | call to source() : | test.swift:18:13:18:13 | "..." |
nodes
| test.swift:5:11:5:18 | call to source() : | semmle.label | call to source() : |
| test.swift:7:13:7:13 | "..." | semmle.label | "..." |
| test.swift:9:13:9:13 | "..." | semmle.label | "..." |
| test.swift:11:13:11:13 | "..." | semmle.label | "..." |
| test.swift:16:13:16:13 | "..." | semmle.label | "..." |
| test.swift:18:13:18:13 | "..." | semmle.label | "..." |
subpaths
#select
| test.swift:7:13:7:13 | "..." | test.swift:5:11:5:18 | call to source() : | test.swift:7:13:7:13 | "..." | result |
| test.swift:9:13:9:13 | "..." | test.swift:5:11:5:18 | call to source() : | test.swift:9:13:9:13 | "..." | result |
| test.swift:11:13:11:13 | "..." | test.swift:5:11:5:18 | call to source() : | test.swift:11:13:11:13 | "..." | result |
| test.swift:16:13:16:13 | "..." | test.swift:5:11:5:18 | call to source() : | test.swift:16:13:16:13 | "..." | result |
| test.swift:18:13:18:13 | "..." | test.swift:5:11:5:18 | call to source() : | test.swift:18:13:18:13 | "..." | result |

View File

@@ -0,0 +1,29 @@
/**
* @kind path-problem
*/
import swift
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.DataFlow::DataFlow
import PathGraph
class TestConfiguration extends TaintTracking::Configuration {
TestConfiguration() { this = "TestConfiguration" }
override predicate isSource(Node src) {
src.asExpr().(CallExpr).getStaticTarget().getName() = "source()"
}
override predicate isSink(Node sink) {
exists(CallExpr sinkCall |
sinkCall.getStaticTarget().getName() = "sink(arg:)" and
sinkCall.getAnArgument().getExpr() = sink.asExpr()
)
}
override int explorationLimit() { result = 100 }
}
from PathNode src, PathNode sink, TestConfiguration test
where test.hasFlowPath(src, sink)
select sink, src, sink, "result"

View File

@@ -0,0 +1,22 @@
func source() -> Int { return 0; }
func sink(arg: String) {}
func taintThroughInterpolatedStrings() {
var x = source()
sink(arg: "\(x)") // tainted
sink(arg: "\(x) \(x)") // tainted
sink(arg: "\(x) \(0) \(x)") // tainted
var y = 42
sink(arg: "\(y)") // clean
sink(arg: "\(x) hello \(y)") // tainted
sink(arg: "\(y) world \(x)") // tainted
x = 0
sink(arg: "\(x)") // clean
}

View File

@@ -7,6 +7,7 @@ edges
| UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:94:10:94:37 | try ... : |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:127:25:127:25 | "..." |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:135:25:135:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:137:25:137:25 | remoteString |
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:138:47:138:56 | ...! |
@@ -19,6 +20,7 @@ edges
| UnsafeWebViewFetch.swift:117:21:117:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:154:86:154:95 | ...! |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:174:25:174:25 | "..." |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:182:25:182:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:184:25:184:25 | remoteString |
| UnsafeWebViewFetch.swift:164:21:164:35 | call to getRemoteData() : | UnsafeWebViewFetch.swift:185:47:185:56 | ...! |
@@ -38,6 +40,7 @@ nodes
| UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | semmle.label | call to getRemoteData() |
| UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:127:25:127:25 | "..." | semmle.label | "..." |
| UnsafeWebViewFetch.swift:135:25:135:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:137:25:137:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:138:47:138:56 | ...! | semmle.label | ...! |
@@ -52,6 +55,7 @@ nodes
| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | semmle.label | call to getRemoteData() |
| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | semmle.label | ... call to +(_:_:) ... |
| UnsafeWebViewFetch.swift:174:25:174:25 | "..." | semmle.label | "..." |
| UnsafeWebViewFetch.swift:182:25:182:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:184:25:184:25 | remoteString | semmle.label | remoteString |
| UnsafeWebViewFetch.swift:185:47:185:56 | ...! | semmle.label | ...! |
@@ -70,11 +74,13 @@ subpaths
| UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:120:25:120:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:121:25:121:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:124:25:124:51 | ... call to +(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:127:25:127:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:127:25:127:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:139:25:139:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:141:25:141:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:167:25:167:39 | call to getRemoteData() | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:168:25:168:25 | remoteString | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:171:25:171:51 | ... call to +(_:_:) ... | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:174:25:174:25 | "..." | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:174:25:174:25 | "..." | Tainted data is used in a WebView fetch without restricting the base URL. |
| UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:186:25:186:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:188:25:188:25 | remoteString | Tainted data is used in a WebView fetch with a tainted base URL. |
| UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | UnsafeWebViewFetch.swift:94:14:94:37 | call to ... : | UnsafeWebViewFetch.swift:210:25:210:25 | htmlData | Tainted data is used in a WebView fetch without restricting the base URL. |

View File

@@ -124,7 +124,7 @@ func testUIWebView() {
webview.loadHTMLString("<html>" + remoteString + "</html>", baseURL: nil) // BAD
webview.loadHTMLString("<html>\(localStringFragment)</html>", baseURL: nil) // GOOD: the HTML data is local
webview.loadHTMLString("<html>\(remoteString)</html>", baseURL: nil) // BAD [NOT DETECTED]
webview.loadHTMLString("<html>\(remoteString)</html>", baseURL: nil) // BAD
let localSafeURL = URL(string: "about:blank")
let localURL = URL(string: "http://example.com/")
@@ -171,7 +171,7 @@ func testWKWebView() {
webview.loadHTMLString("<html>" + remoteString + "</html>", baseURL: nil) // BAD
webview.loadHTMLString("<html>\(localStringFragment)</html>", baseURL: nil) // GOOD: the HTML data is local
webview.loadHTMLString("<html>\(remoteString)</html>", baseURL: nil) // BAD [NOT DETECTED]
webview.loadHTMLString("<html>\(remoteString)</html>", baseURL: nil) // BAD
let localSafeURL = URL(string: "about:blank")
let localURL = URL(string: "http://example.com/")