Skip to content

Commit aa1284a

Browse files
committed
Ruby: Cache two more data flow predicates
1 parent 1e1b2e2 commit aa1284a

File tree

3 files changed

+61
-52
lines changed

3 files changed

+61
-52
lines changed

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

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,18 @@ private module Cached {
232232
)
233233
}
234234

235+
/** Gets a viable run-time target for the call `call`. */
236+
cached
237+
DataFlowCallable viableCallable(DataFlowCall call) {
238+
result = TCfgScope(getTarget(call.asCall())) and
239+
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
240+
or
241+
exists(LibraryCallable callable |
242+
result = TLibraryCallable(callable) and
243+
call.asCall().getExpr() = callable.getACall()
244+
)
245+
}
246+
235247
cached
236248
newtype TArgumentPosition =
237249
TSelfArgumentPosition() or
@@ -423,17 +435,6 @@ private DataFlow::LocalSourceNode trackModule(Module tp) {
423435
result = trackModule(tp, TypeTracker::end())
424436
}
425437

426-
/** Gets a viable run-time target for the call `call`. */
427-
DataFlowCallable viableCallable(DataFlowCall call) {
428-
result = TCfgScope(getTarget(call.asCall())) and
429-
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
430-
or
431-
exists(LibraryCallable callable |
432-
result = TLibraryCallable(callable) and
433-
call.asCall().getExpr() = callable.getACall()
434-
)
435-
}
436-
437438
/**
438439
* Holds if the set of viable implementations that can be called by `call`
439440
* might be improved by knowing the call context. This is the case if the

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

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -66,35 +66,53 @@ private CfgNodes::ExprNodes::VariableWriteAccessCfgNode variablesInPattern(
6666
)
6767
}
6868

69-
/**
70-
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
71-
* in all global taint flow configurations.
72-
*/
7369
cached
74-
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
75-
// value of `case` expression into variables in patterns
76-
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
77-
nodeFrom.asExpr() = case.getValue() and
78-
clause = case.getBranch(_) and
79-
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
80-
variablesInPattern(clause.getPattern())
81-
)
82-
or
83-
// operation involving `nodeFrom`
84-
exists(CfgNodes::ExprNodes::OperationCfgNode op |
85-
op = nodeTo.asExpr() and
86-
op.getAnOperand() = nodeFrom.asExpr() and
87-
not op.getExpr() instanceof AssignExpr
88-
)
89-
or
90-
// string interpolation of `nodeFrom` into `nodeTo`
91-
nodeFrom.asExpr() =
92-
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
93-
or
94-
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
95-
or
96-
// Although flow through arrays is modelled precisely using stores/reads, we still
97-
// allow flow out of a _tainted_ array. This is needed in order to support taint-
98-
// tracking configurations where the source is an array.
99-
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
70+
private module Cached {
71+
/**
72+
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
73+
* in all global taint flow configurations.
74+
*/
75+
cached
76+
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
77+
// value of `case` expression into variables in patterns
78+
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
79+
nodeFrom.asExpr() = case.getValue() and
80+
clause = case.getBranch(_) and
81+
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
82+
variablesInPattern(clause.getPattern())
83+
)
84+
or
85+
// operation involving `nodeFrom`
86+
exists(CfgNodes::ExprNodes::OperationCfgNode op |
87+
op = nodeTo.asExpr() and
88+
op.getAnOperand() = nodeFrom.asExpr() and
89+
not op.getExpr() instanceof AssignExpr
90+
)
91+
or
92+
// string interpolation of `nodeFrom` into `nodeTo`
93+
nodeFrom.asExpr() =
94+
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
95+
or
96+
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
97+
or
98+
// Although flow through arrays is modelled precisely using stores/reads, we still
99+
// allow flow out of a _tainted_ array. This is needed in order to support taint-
100+
// tracking configurations where the source is an array.
101+
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
102+
}
103+
104+
/**
105+
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
106+
* (intra-procedural) step.
107+
*/
108+
cached
109+
predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
110+
defaultAdditionalTaintStep(nodeFrom, nodeTo)
111+
or
112+
// Simple flow through library code is included in the exposed local
113+
// step relation, even though flow is technically inter-procedural
114+
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
115+
}
100116
}
117+
118+
import Cached

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

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,4 @@ predicate localExprTaint(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
2020
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
2121
}
2222

23-
/**
24-
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
25-
* (intra-procedural) step.
26-
*/
27-
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
28-
defaultAdditionalTaintStep(nodeFrom, nodeTo)
29-
or
30-
// Simple flow through library code is included in the exposed local
31-
// step relation, even though flow is technically inter-procedural
32-
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
33-
}
23+
predicate localTaintStep = localTaintStepCached/2;

0 commit comments

Comments
 (0)