Skip to content

Commit 9c48ce1

Browse files
committed
Swift: Flow (1) through the internal function calls generated by the compiler during string interpolation, and (2) out of the internal 'TapExpr' and into the interpolated string result.
1 parent 52b78b6 commit 9c48ce1

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
3939
v instanceof ParamDecl and
4040
bb.getNode(i).getNode().asAstNode() = v and
4141
certain = true
42+
or
43+
// Mark the subexpression as a write of the local variable declared in the `TapExpr`.
44+
exists(TapExpr tap |
45+
v = tap.getVar() and
46+
bb.getNode(i).getNode().asAstNode() = tap.getSubExpr() and
47+
certain = true
48+
)
4249
}
4350

4451
private predicate isLValue(DeclRefExpr ref) { any(AssignExpr assign).getDest() = ref }
@@ -58,4 +65,11 @@ predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain)
5865
bb.getScope() = func and
5966
certain = true
6067
)
68+
or
69+
// Mark the `TapExpr` as a read of the of the local variable.
70+
exists(TapExpr tap |
71+
v = tap.getVar() and
72+
bb.getNode(i).getNode().asAstNode() = tap and
73+
certain = true
74+
)
6175
}

swift/ql/lib/codeql/swift/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ private import swift
22
private import DataFlowPrivate
33
private import TaintTrackingPublic
44
private import codeql.swift.dataflow.DataFlow
5+
private import codeql.swift.dataflow.Ssa
6+
private import codeql.swift.controlflow.CfgNodes
57

68
/**
79
* Holds if `node` should be a sanitizer in all global taint flow configurations
@@ -16,7 +18,22 @@ private module Cached {
1618
* in all global taint flow configurations.
1719
*/
1820
cached
19-
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
21+
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
22+
// Flow through one argument of `appendLiteral` and `appendInterpolation` and to the second argument.
23+
exists(ApplyExpr apply1, ApplyExpr apply2, ExprCfgNode e |
24+
nodeFrom.asExpr() = [apply1, apply2].getAnArgument().getExpr() and
25+
apply1.getFunction() = apply2 and
26+
apply2.getStaticTarget().getName() = ["appendLiteral(_:)", "appendInterpolation(_:)"] and
27+
e.getExpr() = apply2.getAnArgument().getExpr() and
28+
nodeTo.asDefinition().(Ssa::WriteDefinition).isInoutDef(e)
29+
)
30+
or
31+
// Flow from the computation of the interpolated string literal to the result of the interpolation.
32+
exists(InterpolatedStringLiteralExpr interpolated |
33+
nodeTo.asExpr() = interpolated and
34+
nodeFrom.asExpr() = interpolated.getAppendingExpr()
35+
)
36+
}
2037

2138
/**
2239
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local

0 commit comments

Comments
 (0)