Skip to content

Commit f888382

Browse files
authored
Merge pull request github#12906 from hvitved/ruby/track-block-no-self
Ruby: Prevent flow into `self` in `trackBlock`
2 parents 5a77dfb + b94289f commit f888382

File tree

2 files changed

+26
-16
lines changed

2 files changed

+26
-16
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,7 @@ private predicate moduleFlowsToMethodCallReceiver(RelevantCall call, Module m, s
191191
flowsToMethodCallReceiver(call, trackModuleAccess(m), method)
192192
}
193193

194-
private Block yieldCall(RelevantCall call) {
195-
call.getExpr() instanceof YieldCall and
196-
exists(BlockParameterNode node |
197-
node = trackBlock(result) and
198-
node.getMethod() = call.getExpr().getEnclosingMethod()
199-
)
200-
}
194+
private Block blockCall(RelevantCall call) { lambdaSourceCall(call, _, trackBlock(result)) }
201195

202196
pragma[nomagic]
203197
private predicate superCall(RelevantCall call, Module cls, string method) {
@@ -297,7 +291,7 @@ predicate isUserDefinedNew(SingletonMethod new) {
297291

298292
private Callable viableSourceCallableNonInit(RelevantCall call) {
299293
result = getTarget(call) and
300-
not call.getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
294+
not result = blockCall(call) // handled by `lambdaCreation`/`lambdaCall`
301295
}
302296

303297
private Callable viableSourceCallableInit(RelevantCall call) { result = getInitializeTarget(call) }
@@ -394,7 +388,7 @@ private module Cached {
394388
result = lookupMethod(cls.getAnImmediateAncestor(), method)
395389
)
396390
or
397-
result = yieldCall(call)
391+
result = blockCall(call)
398392
}
399393

400394
/** Gets a viable run-time target for the call `call`. */
@@ -700,13 +694,19 @@ private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) {
700694
t.start() and result.asExpr().getExpr() = block
701695
or
702696
exists(TypeTracker t2, StepSummary summary |
703-
result = trackBlockRec(block, t2, summary) and t = t2.append(summary)
697+
result = trackBlockRec(block, t2, summary) and
698+
t = t2.append(summary)
704699
)
705700
}
706701

702+
/**
703+
* We exclude steps into `self` parameters, which may happen when the code
704+
* base contains implementations of `call`.
705+
*/
707706
pragma[nomagic]
708707
private DataFlow::LocalSourceNode trackBlockRec(Block block, TypeTracker t, StepSummary summary) {
709-
StepSummary::step(trackBlock(block, t), result, summary)
708+
StepSummary::step(trackBlock(block, t), result, summary) and
709+
not result instanceof SelfParameterNode
710710
}
711711

712712
pragma[nomagic]

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,18 +1377,28 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)
13771377
)
13781378
}
13791379

1380-
/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
1381-
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
1380+
/**
1381+
* Holds if `call` is a from-source lambda call of kind `kind` where `receiver`
1382+
* is the lambda expression.
1383+
*/
1384+
predicate lambdaSourceCall(CfgNodes::ExprNodes::CallCfgNode call, LambdaCallKind kind, Node receiver) {
13821385
kind = TYieldCallKind() and
1383-
receiver.(BlockParameterNode).getMethod() =
1384-
call.asCall().getExpr().(YieldCall).getEnclosingMethod()
1386+
receiver.(BlockParameterNode).getMethod() = call.getExpr().(YieldCall).getEnclosingMethod()
13851387
or
13861388
kind = TLambdaCallKind() and
1387-
call.asCall() =
1389+
call =
13881390
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
13891391
receiver.asExpr() = mc.getReceiver() and
13901392
mc.getExpr().getMethodName() = "call"
13911393
)
1394+
}
1395+
1396+
/**
1397+
* Holds if `call` is a (from-source or from-summary) lambda call of kind `kind`
1398+
* where `receiver` is the lambda expression.
1399+
*/
1400+
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
1401+
lambdaSourceCall(call.asCall(), kind, receiver)
13921402
or
13931403
receiver = call.(SummaryCall).getReceiver() and
13941404
if receiver.(ParameterNodeImpl).isParameterOf(_, any(ParameterPosition pos | pos.isBlock()))

0 commit comments

Comments
 (0)