@@ -7,6 +7,7 @@ private import codeql.swift.dataflow.Ssa
7
7
private import codeql.swift.controlflow.BasicBlocks
8
8
private import codeql.swift.dataflow.FlowSummary as FlowSummary
9
9
private import codeql.swift.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
10
+ private import codeql.swift.dataflow.ExternalFlow
10
11
private import codeql.swift.frameworks.StandardLibrary.PointerTypes
11
12
private import codeql.swift.frameworks.StandardLibrary.Array
12
13
private import codeql.swift.frameworks.StandardLibrary.Dictionary
@@ -184,142 +185,145 @@ private module Cached {
184
185
nodeTo = getParameterDefNode ( nodeFrom .asParameter ( ) )
185
186
}
186
187
187
- private predicate localFlowStepCommon ( Node nodeFrom , Node nodeTo ) {
188
- exists ( Ssa:: Definition def |
189
- // Step from assignment RHS to def
190
- def .( Ssa:: WriteDefinition ) .assigns ( nodeFrom .getCfgNode ( ) ) and
191
- nodeTo .asDefinition ( ) = def
188
+ private predicate localFlowStepCommon ( Node nodeFrom , Node nodeTo , string model ) {
189
+ (
190
+ exists ( Ssa:: Definition def |
191
+ // Step from assignment RHS to def
192
+ def .( Ssa:: WriteDefinition ) .assigns ( nodeFrom .getCfgNode ( ) ) and
193
+ nodeTo .asDefinition ( ) = def
194
+ or
195
+ // step from def to first read
196
+ nodeFrom .asDefinition ( ) = def and
197
+ nodeTo .getCfgNode ( ) = def .getAFirstRead ( ) and
198
+ (
199
+ nodeTo instanceof InoutReturnNodeImpl
200
+ implies
201
+ nodeTo .( InoutReturnNodeImpl ) .getParameter ( ) = def .getSourceVariable ( ) .asVarDecl ( )
202
+ )
203
+ or
204
+ // use-use flow
205
+ localSsaFlowStepUseUse ( def , nodeFrom , nodeTo )
206
+ or
207
+ localSsaFlowStepUseUse ( def , nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
208
+ or
209
+ // step from previous read to Phi node
210
+ localFlowSsaInput ( nodeFrom , def , nodeTo .asDefinition ( ) )
211
+ )
192
212
or
193
- // step from def to first read
194
- nodeFrom .asDefinition ( ) = def and
195
- nodeTo .getCfgNode ( ) = def .getAFirstRead ( ) and
196
- (
197
- nodeTo instanceof InoutReturnNodeImpl
198
- implies
199
- nodeTo .( InoutReturnNodeImpl ) .getParameter ( ) = def .getSourceVariable ( ) .asVarDecl ( )
213
+ localFlowSsaParamInput ( nodeFrom , nodeTo )
214
+ or
215
+ // flow through `&` (inout argument)
216
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( InOutExpr ) .getSubExpr ( )
217
+ or
218
+ // reverse flow through `&` (inout argument)
219
+ nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) .( InOutExpr ) .getSubExpr ( ) =
220
+ nodeTo .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( )
221
+ or
222
+ // flow through `try!` and similar constructs
223
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( AnyTryExpr ) .getSubExpr ( )
224
+ or
225
+ // flow through `!`
226
+ // note: there's a case in `readStep` that handles when the source is the
227
+ // `OptionalSomeContentSet` within the RHS. This case is for when the
228
+ // `Optional` itself is tainted (which it usually shouldn't be, but
229
+ // retaining this case increases robustness of flow).
230
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( ForceValueExpr ) .getSubExpr ( )
231
+ or
232
+ // read of an optional .some member via `let x: T = y: T?` pattern matching
233
+ // note: similar to `ForceValueExpr` this is ideally a content `readStep` but
234
+ // in practice we sometimes have taint on the optional itself.
235
+ nodeTo .asPattern ( ) = nodeFrom .asPattern ( ) .( OptionalSomePattern ) .getSubPattern ( )
236
+ or
237
+ // flow through `?` and `?.`
238
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( BindOptionalExpr ) .getSubExpr ( )
239
+ or
240
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( OptionalEvaluationExpr ) .getSubExpr ( )
241
+ or
242
+ // flow through unary `+` (which does nothing)
243
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( UnaryPlusExpr ) .getOperand ( )
244
+ or
245
+ // flow through varargs expansions (that wrap an `ArrayExpr` where varargs enter a call)
246
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( VarargExpansionExpr ) .getSubExpr ( )
247
+ or
248
+ // flow through nil-coalescing operator `??`
249
+ exists ( BinaryExpr nco |
250
+ nco .getOperator ( ) .( FreeFunction ) .getName ( ) = "??(_:_:)" and
251
+ nodeTo .asExpr ( ) = nco
252
+ |
253
+ // value argument
254
+ nodeFrom .asExpr ( ) = nco .getAnOperand ( )
255
+ or
256
+ // unpack closure (the second argument is an `AutoClosureExpr` argument)
257
+ nodeFrom .asExpr ( ) = nco .getAnOperand ( ) .( AutoClosureExpr ) .getExpr ( )
200
258
)
201
259
or
202
- // use-use flow
203
- localSsaFlowStepUseUse ( def , nodeFrom , nodeTo )
260
+ // flow through ternary operator `? :`
261
+ exists ( IfExpr ie |
262
+ nodeTo .asExpr ( ) = ie and
263
+ nodeFrom .asExpr ( ) = ie .getBranch ( _)
264
+ )
204
265
or
205
- localSsaFlowStepUseUse ( def , nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) , nodeTo )
266
+ // flow through OpenExistentialExpr (compiler generated expression wrapper)
267
+ nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( OpenExistentialExpr ) .getSubExpr ( )
206
268
or
207
- // step from previous read to Phi node
208
- localFlowSsaInput ( nodeFrom , def , nodeTo .asDefinition ( ) )
209
- )
210
- or
211
- localFlowSsaParamInput ( nodeFrom , nodeTo )
212
- or
213
- // flow through `&` (inout argument)
214
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( InOutExpr ) .getSubExpr ( )
215
- or
216
- // reverse flow through `&` (inout argument)
217
- nodeFrom .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) .( InOutExpr ) .getSubExpr ( ) =
218
- nodeTo .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( )
219
- or
220
- // flow through `try!` and similar constructs
221
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( AnyTryExpr ) .getSubExpr ( )
222
- or
223
- // flow through `!`
224
- // note: there's a case in `readStep` that handles when the source is the
225
- // `OptionalSomeContentSet` within the RHS. This case is for when the
226
- // `Optional` itself is tainted (which it usually shouldn't be, but
227
- // retaining this case increases robustness of flow).
228
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( ForceValueExpr ) .getSubExpr ( )
229
- or
230
- // read of an optional .some member via `let x: T = y: T?` pattern matching
231
- // note: similar to `ForceValueExpr` this is ideally a content `readStep` but
232
- // in practice we sometimes have taint on the optional itself.
233
- nodeTo .asPattern ( ) = nodeFrom .asPattern ( ) .( OptionalSomePattern ) .getSubPattern ( )
234
- or
235
- // flow through `?` and `?.`
236
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( BindOptionalExpr ) .getSubExpr ( )
237
- or
238
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( OptionalEvaluationExpr ) .getSubExpr ( )
239
- or
240
- // flow through unary `+` (which does nothing)
241
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( UnaryPlusExpr ) .getOperand ( )
242
- or
243
- // flow through varargs expansions (that wrap an `ArrayExpr` where varargs enter a call)
244
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( VarargExpansionExpr ) .getSubExpr ( )
245
- or
246
- // flow through nil-coalescing operator `??`
247
- exists ( BinaryExpr nco |
248
- nco .getOperator ( ) .( FreeFunction ) .getName ( ) = "??(_:_:)" and
249
- nodeTo .asExpr ( ) = nco
250
- |
251
- // value argument
252
- nodeFrom .asExpr ( ) = nco .getAnOperand ( )
269
+ // flow from Expr to Pattern
270
+ exists ( Expr e , Pattern p |
271
+ nodeFrom .asExpr ( ) = e and
272
+ nodeTo .asPattern ( ) = p and
273
+ p .getImmediateMatchingExpr ( ) = e
274
+ )
253
275
or
254
- // unpack closure (the second argument is an `AutoClosureExpr` argument)
255
- nodeFrom .asExpr ( ) = nco .getAnOperand ( ) .( AutoClosureExpr ) .getExpr ( )
256
- )
257
- or
258
- // flow through ternary operator `? :`
259
- exists ( IfExpr ie |
260
- nodeTo .asExpr ( ) = ie and
261
- nodeFrom .asExpr ( ) = ie .getBranch ( _)
262
- )
263
- or
264
- // flow through OpenExistentialExpr (compiler generated expression wrapper)
265
- nodeFrom .asExpr ( ) = nodeTo .asExpr ( ) .( OpenExistentialExpr ) .getSubExpr ( )
266
- or
267
- // flow from Expr to Pattern
268
- exists ( Expr e , Pattern p |
269
- nodeFrom .asExpr ( ) = e and
270
- nodeTo .asPattern ( ) = p and
271
- p .getImmediateMatchingExpr ( ) = e
272
- )
273
- or
274
- // flow from Pattern to an identity-preserving sub-Pattern:
275
- nodeTo .asPattern ( ) =
276
- [
277
- nodeFrom .asPattern ( ) .( IsPattern ) .getSubPattern ( ) ,
278
- nodeFrom .asPattern ( ) .( TypedPattern ) .getSubPattern ( )
279
- ]
280
- or
281
- // Flow from the last component in a key path chain to
282
- // the return node for the key path.
283
- exists ( KeyPathExpr keyPath |
284
- nodeFrom .( KeyPathComponentNodeImpl ) .getComponent ( ) =
285
- keyPath .getComponent ( keyPath .getNumberOfComponents ( ) - 1 ) and
286
- nodeTo .( KeyPathReturnNodeImpl ) .getKeyPathExpr ( ) = keyPath
287
- )
288
- or
289
- exists ( KeyPathExpr keyPath |
290
- nodeTo .( KeyPathComponentPostUpdateNode ) .getComponent ( ) =
291
- keyPath .getComponent ( keyPath .getNumberOfComponents ( ) - 1 ) and
292
- nodeFrom .( KeyPathReturnPostUpdateNode ) .getKeyPathExpr ( ) = keyPath
293
- )
294
- or
295
- // Flow to the result of a keypath assignment
296
- exists ( KeyPathApplicationExpr apply , AssignExpr assign |
297
- apply = assign .getDest ( ) and
298
- nodeTo .asExpr ( ) = apply and
299
- nodeFrom .asExpr ( ) = assign .getSource ( )
300
- )
276
+ // flow from Pattern to an identity-preserving sub-Pattern:
277
+ nodeTo .asPattern ( ) =
278
+ [
279
+ nodeFrom .asPattern ( ) .( IsPattern ) .getSubPattern ( ) ,
280
+ nodeFrom .asPattern ( ) .( TypedPattern ) .getSubPattern ( )
281
+ ]
282
+ or
283
+ // Flow from the last component in a key path chain to
284
+ // the return node for the key path.
285
+ exists ( KeyPathExpr keyPath |
286
+ nodeFrom .( KeyPathComponentNodeImpl ) .getComponent ( ) =
287
+ keyPath .getComponent ( keyPath .getNumberOfComponents ( ) - 1 ) and
288
+ nodeTo .( KeyPathReturnNodeImpl ) .getKeyPathExpr ( ) = keyPath
289
+ )
290
+ or
291
+ exists ( KeyPathExpr keyPath |
292
+ nodeTo .( KeyPathComponentPostUpdateNode ) .getComponent ( ) =
293
+ keyPath .getComponent ( keyPath .getNumberOfComponents ( ) - 1 ) and
294
+ nodeFrom .( KeyPathReturnPostUpdateNode ) .getKeyPathExpr ( ) = keyPath
295
+ )
296
+ or
297
+ // Flow to the result of a keypath assignment
298
+ exists ( KeyPathApplicationExpr apply , AssignExpr assign |
299
+ apply = assign .getDest ( ) and
300
+ nodeTo .asExpr ( ) = apply and
301
+ nodeFrom .asExpr ( ) = assign .getSource ( )
302
+ )
303
+ or
304
+ // flow step according to the closure capture library
305
+ captureValueStep ( nodeFrom , nodeTo )
306
+ ) and
307
+ model = ""
301
308
or
302
309
// flow through a flow summary (extension of `SummaryModelCsv`)
303
310
FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom .( FlowSummaryNode ) .getSummaryNode ( ) ,
304
- nodeTo .( FlowSummaryNode ) .getSummaryNode ( ) , true )
305
- or
306
- // flow step according to the closure capture library
307
- captureValueStep ( nodeFrom , nodeTo )
311
+ nodeTo .( FlowSummaryNode ) .getSummaryNode ( ) , true , model )
308
312
}
309
313
310
314
/**
311
315
* This is the local flow predicate that is used as a building block in global
312
316
* data flow.
313
317
*/
314
318
cached
315
- predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
316
- localFlowStepCommon ( nodeFrom , nodeTo )
319
+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo , string model ) {
320
+ localFlowStepCommon ( nodeFrom , nodeTo , model )
317
321
}
318
322
319
323
/** This is the local flow predicate that is exposed. */
320
324
cached
321
325
predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
322
- localFlowStepCommon ( nodeFrom , nodeTo ) or
326
+ localFlowStepCommon ( nodeFrom , nodeTo , _ ) or
323
327
FlowSummaryImpl:: Private:: Steps:: summaryThroughStepValue ( nodeFrom , nodeTo , _)
324
328
}
325
329
@@ -1396,6 +1400,10 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
1396
1400
/** Extra data-flow steps needed for lambda flow analysis. */
1397
1401
predicate additionalLambdaFlowStep ( Node nodeFrom , Node nodeTo , boolean preservesValue ) { none ( ) }
1398
1402
1403
+ predicate knownSourceModel ( Node source , string model ) { sourceNode ( source , _, model ) }
1404
+
1405
+ predicate knownSinkModel ( Node sink , string model ) { sinkNode ( sink , _, model ) }
1406
+
1399
1407
/**
1400
1408
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
1401
1409
* side-effect, resulting in a summary from `p` to itself.
0 commit comments