Skip to content

Commit 25fda20

Browse files
committed
Java: Prevent accidental recursion through AdditionalValueStep.
1 parent 1d3b320 commit 25fda20

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,15 @@ predicate hasNonlocalValue(FieldRead fr) {
100100
/**
101101
* Holds if data can flow from `node1` to `node2` in one local step.
102102
*/
103+
cached
103104
predicate localFlowStep(Node node1, Node node2) {
104-
simpleLocalFlowStep(node1, node2)
105+
simpleLocalFlowStep0(node1, node2)
105106
or
106107
adjacentUseUse(node1.asExpr(), node2.asExpr())
107108
or
108109
// Simple flow through library code is included in the exposed local
109110
// step relation, even though flow is technically inter-procedural
110-
FlowSummaryImpl::Private::Steps::summaryThroughStep(node1, node2, true)
111+
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(node1, node2)
111112
}
112113

113114
/**
@@ -118,6 +119,16 @@ predicate localFlowStep(Node node1, Node node2) {
118119
*/
119120
cached
120121
predicate simpleLocalFlowStep(Node node1, Node node2) {
122+
simpleLocalFlowStep0(node1, node2)
123+
or
124+
any(AdditionalValueStep a).step(node1, node2) and
125+
pragma[only_bind_out](node1.getEnclosingCallable()) =
126+
pragma[only_bind_out](node2.getEnclosingCallable()) and
127+
// prevent recursive call
128+
(any() or strictcount(Node n1, Node n2, AdditionalValueStep a | a.step(n1, n2)) < 0)
129+
}
130+
131+
private predicate simpleLocalFlowStep0(Node node1, Node node2) {
121132
TaintTrackingUtil::forceCachingInSameStage() and
122133
// Variable flow steps through adjacent def-use and use-use pairs.
123134
exists(SsaExplicitUpdate upd |
@@ -166,10 +177,6 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
166177
)
167178
or
168179
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2, true)
169-
or
170-
any(AdditionalValueStep a).step(node1, node2) and
171-
pragma[only_bind_out](node1.getEnclosingCallable()) =
172-
pragma[only_bind_out](node2.getEnclosingCallable())
173180
}
174181

175182
private newtype TContent =

java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -791,15 +791,30 @@ module Private {
791791
}
792792

793793
/**
794-
* Holds if `arg` flows to `out` using a simple flow summary, that is, a flow
795-
* summary without reads and stores.
794+
* Holds if `arg` flows to `out` using a simple value-preserving flow
795+
* summary, that is, a flow summary without reads and stores.
796796
*
797797
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
798798
* be useful to include in the exposed local data-flow/taint-tracking relations.
799799
*/
800-
predicate summaryThroughStep(ArgNode arg, Node out, boolean preservesValue) {
800+
predicate summaryThroughStepValue(ArgNode arg, Node out) {
801+
exists(ReturnKind rk, ReturnNode ret, DataFlowCall call |
802+
summaryLocalStep(summaryArgParam0(call, arg), ret, true) and
803+
ret.getKind() = rk and
804+
out = getAnOutNode(call, rk)
805+
)
806+
}
807+
808+
/**
809+
* Holds if `arg` flows to `out` using a simple flow summary involving taint
810+
* step, that is, a flow summary without reads and stores.
811+
*
812+
* NOTE: This step should not be used in global data-flow/taint-tracking, but may
813+
* be useful to include in the exposed local data-flow/taint-tracking relations.
814+
*/
815+
predicate summaryThroughStepTaint(ArgNode arg, Node out) {
801816
exists(ReturnNodeExt ret |
802-
summaryLocalStep(summaryArgParam(arg, ret, out), ret, preservesValue)
817+
summaryLocalStep(summaryArgParam(arg, ret, out), ret, false)
803818
)
804819
}
805820

java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private module Cached {
5151
or
5252
// Simple flow through library code is included in the exposed local
5353
// step relation, even though flow is technically inter-procedural
54-
FlowSummaryImpl::Private::Steps::summaryThroughStep(src, sink, false)
54+
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(src, sink)
5555
or
5656
// Treat container flow as taint for the local taint flow relation
5757
exists(DataFlow::Content c | containerContent(c) |

0 commit comments

Comments
 (0)