From 254d60c8260ab976f32911001550bd95eab7db84 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 23 May 2023 10:48:11 +0200 Subject: [PATCH] Dataflow: Refactor FlowSummaryImpl to synthesize nodes independently from DataFlow::Node. --- .../semmle/code/java/dataflow/FlowSummary.qll | 5 +- .../java/dataflow/internal/DataFlowNodes.qll | 80 ++++---- .../dataflow/internal/DataFlowPrivate.qll | 28 +-- .../java/dataflow/internal/DataFlowUtil.qll | 3 +- .../dataflow/internal/FlowSummaryImpl.qll | 173 ++++++++++++------ .../internal/FlowSummaryImplSpecific.qll | 5 +- .../dataflow/internal/TaintTrackingUtil.qll | 4 +- 7 files changed, 178 insertions(+), 120 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll index 6d6af4f82b4..e45ba0be27e 100644 --- a/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll +++ b/java/ql/lib/semmle/code/java/dataflow/FlowSummary.qll @@ -149,8 +149,9 @@ class SummarizedCallableBase extends TSummarizedCallableBase { or result = this.asSyntheticCallable().getParameterType(pos) or - exists(SyntheticCallable sc | sc = this.asSyntheticCallable() | - Impl::Private::summaryParameterNodeRange(this, pos) and + exists(SyntheticCallable sc, Impl::Private::SummaryNode p | sc = this.asSyntheticCallable() | + Impl::Private::summaryParameterNode(p, pos) and + this = p.getSummarizedCallable() and not exists(sc.getParameterType(pos)) and result instanceof TypeObject ) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll index 22d79d7da15..8758d0e7c24 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowNodes.qll @@ -54,12 +54,7 @@ private module Cached { fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa) ) } or - TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { - FlowSummaryImpl::Private::summaryNodeRange(c, state) - } or - TSummaryParameterNode(SummarizedCallable c, int pos) { - FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) - } or + TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or TFieldValueNode(Field f) cached @@ -378,8 +373,7 @@ module Private { result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or - n = TSummaryInternalNode(result.asSummarizedCallable(), _) or - n = TSummaryParameterNode(result.asSummarizedCallable(), _) or + result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or result.asFieldScope() = n.(FieldValueNode).getField() } @@ -407,7 +401,7 @@ module Private { or this = getInstanceArgument(_) or - this.(SummaryNode).isArgumentOf(_, _) + this.(FlowSummaryNode).isArgumentOf(_, _) } /** @@ -424,7 +418,7 @@ module Private { or pos = -1 and this = getInstanceArgument(call.asCall()) or - this.(SummaryNode).isArgumentOf(call, pos) + this.(FlowSummaryNode).isArgumentOf(call, pos) } /** Gets the call in which this node is an argument. */ @@ -435,7 +429,7 @@ module Private { class ReturnNode extends Node { ReturnNode() { exists(ReturnStmt ret | this.asExpr() = ret.getResult()) or - this.(SummaryNode).isReturn() + this.(FlowSummaryNode).isReturn() } /** Gets the kind of this returned value. */ @@ -447,61 +441,61 @@ module Private { OutNode() { this.asExpr() instanceof MethodAccess or - this.(SummaryNode).isOut(_) + this.(FlowSummaryNode).isOut(_) } /** Gets the underlying call. */ DataFlowCall getCall() { result.asCall() = this.asExpr() or - this.(SummaryNode).isOut(result) + this.(FlowSummaryNode).isOut(result) } } /** * A data-flow node used to model flow summaries. */ - class SummaryNode extends Node, TSummaryInternalNode { - private SummarizedCallable c; - private FlowSummaryImpl::Private::SummaryNodeState state; + class FlowSummaryNode extends Node, TFlowSummaryNode { + FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) } - SummaryNode() { this = TSummaryInternalNode(c, state) } + SummarizedCallable getSummarizedCallable() { + result = this.getSummaryNode().getSummarizedCallable() + } - override Location getLocation() { result = c.getLocation() } + override Location getLocation() { result = this.getSummarizedCallable().getLocation() } - override string toString() { result = "[summary] " + state + " in " + c } + override string toString() { result = this.getSummaryNode().toString() } /** Holds if this summary node is the `i`th argument of `call`. */ predicate isArgumentOf(DataFlowCall call, int i) { - FlowSummaryImpl::Private::summaryArgumentNode(call, this, i) + FlowSummaryImpl::Private::summaryArgumentNode(call, this.getSummaryNode(), i) } /** Holds if this summary node is a return node. */ - predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this, _) } + predicate isReturn() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), _) } /** Holds if this summary node is an out node for `call`. */ - predicate isOut(DataFlowCall call) { FlowSummaryImpl::Private::summaryOutNode(call, this, _) } + predicate isOut(DataFlowCall call) { + FlowSummaryImpl::Private::summaryOutNode(call, this.getSummaryNode(), _) + } } - SummaryNode getSummaryNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) { - result = TSummaryInternalNode(c, state) - } - - class SummaryParameterNode extends ParameterNode, TSummaryParameterNode { - private SummarizedCallable sc; - private int pos_; - - SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) } - - override Location getLocation() { result = sc.getLocation() } - - override string toString() { result = "[summary param] " + pos_ + " in " + sc } - - override predicate isParameterOf(DataFlowCallable c, int pos) { - c.asSummarizedCallable() = sc and pos = pos_ + class SummaryParameterNode extends ParameterNode, FlowSummaryNode { + SummaryParameterNode() { + FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), _) } - Type getTypeImpl() { result = sc.getParameterType(pos_) } + private int getPosition() { + FlowSummaryImpl::Private::summaryParameterNode(this.getSummaryNode(), result) + } + + override predicate isParameterOf(DataFlowCallable c, int pos) { + c.asSummarizedCallable() = this.getSummarizedCallable() and pos = this.getPosition() + } + + Type getTypeImpl() { + result = this.getSummarizedCallable().getParameterType(this.getPosition()) + } } } @@ -523,10 +517,12 @@ private class MallocNode extends Node, TMallocNode { ClassInstanceExpr getClassInstanceExpr() { result = cie } } -private class SummaryPostUpdateNode extends SummaryNode, PostUpdateNode { - private Node pre; +private class SummaryPostUpdateNode extends FlowSummaryNode, PostUpdateNode { + private FlowSummaryNode pre; - SummaryPostUpdateNode() { FlowSummaryImpl::Private::summaryPostUpdateNode(this, pre) } + SummaryPostUpdateNode() { + FlowSummaryImpl::Private::summaryPostUpdateNode(this.getSummaryNode(), pre.getSummaryNode()) + } override Node getPreUpdateNode() { result = pre } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 01bf90cb7ba..ea393dad0bf 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -85,7 +85,8 @@ predicate jumpStep(Node node1, Node node2) { any(AdditionalValueStep a).step(node1, node2) and node1.getEnclosingCallable() != node2.getEnclosingCallable() or - FlowSummaryImpl::Private::Steps::summaryJumpStep(node1, node2) + FlowSummaryImpl::Private::Steps::summaryJumpStep(node1.(FlowSummaryNode).getSummaryNode(), + node2.(FlowSummaryNode).getSummaryNode()) } /** @@ -114,7 +115,8 @@ predicate storeStep(Node node1, Content f, Node node2) { or f instanceof ArrayContent and arrayStoreStep(node1, node2) or - FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, f, node2) + FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), f, + node2.(FlowSummaryNode).getSummaryNode()) } /** @@ -145,7 +147,8 @@ predicate readStep(Node node1, Content f, Node node2) { or f instanceof CollectionContent and collectionReadStep(node1, node2) or - FlowSummaryImpl::Private::Steps::summaryReadStep(node1, f, node2) + FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), f, + node2.(FlowSummaryNode).getSummaryNode()) } /** @@ -160,7 +163,7 @@ predicate clearsContent(Node n, Content c) { c.(FieldContent).getField() = fa.getField() ) or - FlowSummaryImpl::Private::Steps::summaryClearsContent(n, c) + FlowSummaryImpl::Private::Steps::summaryClearsContent(n.(FlowSummaryNode).getSummaryNode(), c) } /** @@ -168,7 +171,7 @@ predicate clearsContent(Node n, Content c) { * at node `n`. */ predicate expectsContent(Node n, ContentSet c) { - FlowSummaryImpl::Private::Steps::summaryExpectsContent(n, c) + FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c) } /** @@ -200,7 +203,7 @@ pragma[noinline] DataFlowType getNodeType(Node n) { result = getErasedRepr(n.getTypeBound()) or - result = FlowSummaryImpl::Private::summaryNodeType(n) + result = FlowSummaryImpl::Private::summaryNodeType(n.(FlowSummaryNode).getSummaryNode()) } /** Gets a string representation of a type returned by `getErasedRepr`. */ @@ -268,7 +271,7 @@ class DataFlowExpr = Expr; private newtype TDataFlowCall = TCall(Call c) or - TSummaryCall(SummarizedCallable c, Node receiver) { + TSummaryCall(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) } @@ -318,12 +321,12 @@ class SrcCall extends DataFlowCall, TCall { /** A synthesized call inside a `SummarizedCallable`. */ class SummaryCall extends DataFlowCall, TSummaryCall { private SummarizedCallable c; - private Node receiver; + private FlowSummaryImpl::Private::SummaryNode receiver; SummaryCall() { this = TSummaryCall(c, receiver) } /** Gets the data flow node that this call targets. */ - Node getReceiver() { result = receiver } + FlowSummaryImpl::Private::SummaryNode getReceiver() { result = receiver } override DataFlowCallable getEnclosingCallable() { result.asSummarizedCallable() = c } @@ -383,10 +386,7 @@ predicate forceHighPrecision(Content c) { } /** Holds if `n` should be hidden from path explanations. */ -predicate nodeIsHidden(Node n) { - n instanceof SummaryNode or - n instanceof SummaryParameterNode -} +predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode } class LambdaCallKind = Method; // the "apply" method in the functional interface @@ -404,7 +404,7 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) /** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { - receiver = call.(SummaryCall).getReceiver() and + receiver.(FlowSummaryNode).getSummaryNode() = call.(SummaryCall).getReceiver() and getNodeDataFlowType(receiver) .getSourceDeclaration() .(FunctionalInterface) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll index ff064cc8405..29758d4b972 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll @@ -183,7 +183,8 @@ private predicate simpleLocalFlowStep0(Node node1, Node node2) { node1.(ArgumentNode).argumentOf(any(DataFlowCall c | c.asCall() = ma), argNo) ) or - FlowSummaryImpl::Private::Steps::summaryLocalStep(node1, node2, true) + FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(), + node2.(FlowSummaryNode).getSummaryNode(), true) } /** diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll index fb2dc49bae3..fa803e6cc92 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll @@ -530,7 +530,7 @@ module Private { * this state represents that the components in `s` _remain to be written_ to * the output. */ - class SummaryNodeState extends TSummaryNodeState { + private class SummaryNodeState extends TSummaryNodeState { /** Holds if this state is a valid input state for `c`. */ pragma[nomagic] predicate isInputState(SummarizedCallable c, SummaryComponentStack s) { @@ -559,6 +559,42 @@ module Private { } } + private newtype TSummaryNode = + TSummaryInternalNode(SummarizedCallable c, SummaryNodeState state) { + summaryNodeRange(c, state) + } or + TSummaryParameterNode(SummarizedCallable c, ParameterPosition pos) { + summaryParameterNodeRange(c, pos) + } + + class SummaryNode extends TSummaryNode { + abstract string toString(); + + abstract SummarizedCallable getSummarizedCallable(); + } + + private class SummaryInternalNode extends SummaryNode, TSummaryInternalNode { + private SummarizedCallable c; + private SummaryNodeState state; + + SummaryInternalNode() { this = TSummaryInternalNode(c, state) } + + override string toString() { result = "[summary] " + state + " in " + c } + + override SummarizedCallable getSummarizedCallable() { result = c } + } + + private class SummaryParamNode extends SummaryNode, TSummaryParameterNode { + private SummarizedCallable c; + private ParameterPosition pos; + + SummaryParamNode() { this = TSummaryParameterNode(c, pos) } + + override string toString() { result = "[summary param] " + pos + " in " + c } + + override SummarizedCallable getSummarizedCallable() { result = c } + } + /** * Holds if `state` represents having read from a parameter at position * `pos` in `c`. In this case we are not synthesizing a data-flow node, @@ -574,7 +610,7 @@ module Private { * Holds if a synthesized summary node is needed for the state `state` in summarized * callable `c`. */ - predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) { + private predicate summaryNodeRange(SummarizedCallable c, SummaryNodeState state) { state.isInputState(c, _) and not parameterReadState(c, state, _) or @@ -582,22 +618,22 @@ module Private { } pragma[noinline] - private Node summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) { + private SummaryNode summaryNodeInputState(SummarizedCallable c, SummaryComponentStack s) { exists(SummaryNodeState state | state.isInputState(c, s) | - result = summaryNode(c, state) + result = TSummaryInternalNode(c, state) or exists(ParameterPosition pos | parameterReadState(c, state, pos) and - result.(ParamNode).isParameterOf(inject(c), pos) + result = TSummaryParameterNode(c, pos) ) ) } pragma[noinline] - private Node summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) { + private SummaryNode summaryNodeOutputState(SummarizedCallable c, SummaryComponentStack s) { exists(SummaryNodeState state | state.isOutputState(c, s) and - result = summaryNode(c, state) + result = TSummaryInternalNode(c, state) ) } @@ -605,12 +641,14 @@ module Private { * Holds if a write targets `post`, which is a post-update node for a * parameter at position `pos` in `c`. */ - private predicate isParameterPostUpdate(Node post, SummarizedCallable c, ParameterPosition pos) { + private predicate isParameterPostUpdate( + SummaryNode post, SummarizedCallable c, ParameterPosition pos + ) { post = summaryNodeOutputState(c, SummaryComponentStack::argument(pos)) } /** Holds if a parameter node at position `pos` is required for `c`. */ - predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) { + private predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) { parameterReadState(c, _, pos) or // Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context @@ -618,7 +656,7 @@ module Private { } private predicate callbackOutput( - SummarizedCallable c, SummaryComponentStack s, Node receiver, ReturnKind rk + SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ReturnKind rk ) { any(SummaryNodeState state).isInputState(c, s) and s.head() = TReturnSummaryComponent(rk) and @@ -626,7 +664,7 @@ module Private { } private predicate callbackInput( - SummarizedCallable c, SummaryComponentStack s, Node receiver, ArgumentPosition pos + SummarizedCallable c, SummaryComponentStack s, SummaryNode receiver, ArgumentPosition pos ) { any(SummaryNodeState state).isOutputState(c, s) and s.head() = TParameterSummaryComponent(pos) and @@ -634,7 +672,7 @@ module Private { } /** Holds if a call targeting `receiver` should be synthesized inside `c`. */ - predicate summaryCallbackRange(SummarizedCallable c, Node receiver) { + predicate summaryCallbackRange(SummarizedCallable c, SummaryNode receiver) { callbackOutput(c, _, receiver, _) or callbackInput(c, _, receiver, _) @@ -647,10 +685,10 @@ module Private { * `getContentType()`, `getReturnType()`, `getCallbackParameterType()`, and * `getCallbackReturnType()`. */ - DataFlowType summaryNodeType(Node n) { - exists(Node pre | + DataFlowType summaryNodeType(SummaryNode n) { + exists(SummaryNode pre | summaryPostUpdateNode(n, pre) and - result = getNodeType(pre) + result = summaryNodeType(pre) ) or exists(SummarizedCallable c, SummaryComponentStack s, SummaryComponent head | head = s.head() | @@ -662,12 +700,12 @@ module Private { ) or head = TWithoutContentSummaryComponent(_) and - result = getNodeType(summaryNodeInputState(c, s.tail())) + result = summaryNodeType(summaryNodeInputState(c, s.tail())) or exists(ReturnKind rk | head = TReturnSummaryComponent(rk) and result = - getCallbackReturnType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c), + getCallbackReturnType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), s.tail())), rk) ) or @@ -691,7 +729,7 @@ module Private { or exists(ArgumentPosition pos | head = TParameterSummaryComponent(pos) | result = - getCallbackParameterType(getNodeType(summaryNodeInputState(pragma[only_bind_out](c), + getCallbackParameterType(summaryNodeType(summaryNodeInputState(pragma[only_bind_out](c), s.tail())), pos) ) or @@ -703,9 +741,14 @@ module Private { ) } + /** Holds if summary node `p` is a parameter with position `pos`. */ + predicate summaryParameterNode(SummaryNode p, ParameterPosition pos) { + p = TSummaryParameterNode(_, pos) + } + /** Holds if summary node `out` contains output of kind `rk` from call `c`. */ - predicate summaryOutNode(DataFlowCall c, Node out, ReturnKind rk) { - exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver | + predicate summaryOutNode(DataFlowCall c, SummaryNode out, ReturnKind rk) { + exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver | callbackOutput(callable, s, receiver, rk) and out = summaryNodeInputState(callable, s) and c = summaryDataFlowCall(receiver) @@ -713,8 +756,8 @@ module Private { } /** Holds if summary node `arg` is at position `pos` in the call `c`. */ - predicate summaryArgumentNode(DataFlowCall c, Node arg, ArgumentPosition pos) { - exists(SummarizedCallable callable, SummaryComponentStack s, Node receiver | + predicate summaryArgumentNode(DataFlowCall c, SummaryNode arg, ArgumentPosition pos) { + exists(SummarizedCallable callable, SummaryComponentStack s, SummaryNode receiver | callbackInput(callable, s, receiver, pos) and arg = summaryNodeOutputState(callable, s) and c = summaryDataFlowCall(receiver) @@ -722,10 +765,10 @@ module Private { } /** Holds if summary node `post` is a post-update node with pre-update node `pre`. */ - predicate summaryPostUpdateNode(Node post, Node pre) { + predicate summaryPostUpdateNode(SummaryNode post, SummaryNode pre) { exists(SummarizedCallable c, ParameterPosition pos | isParameterPostUpdate(post, c, pos) and - pre.(ParamNode).isParameterOf(inject(c), pos) + pre = TSummaryParameterNode(c, pos) ) or exists(SummarizedCallable callable, SummaryComponentStack s | @@ -736,7 +779,7 @@ module Private { } /** Holds if summary node `ret` is a return node of kind `rk`. */ - predicate summaryReturnNode(Node ret, ReturnKind rk) { + predicate summaryReturnNode(SummaryNode ret, ReturnKind rk) { exists(SummaryComponentStack s | ret = summaryNodeOutputState(_, s) and s = TSingletonSummaryComponentStack(TReturnSummaryComponent(rk)) @@ -748,7 +791,9 @@ module Private { * node, and back out to `p`. */ predicate summaryAllowParameterReturnInSelf(ParamNode p) { - exists(SummarizedCallable c, ParameterPosition ppos | p.isParameterOf(inject(c), ppos) | + exists(SummarizedCallable c, ParameterPosition ppos | + p.isParameterOf(inject(c), pragma[only_bind_into](ppos)) + | exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents | summary(c, inputContents, outputContents, _) and inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(ppos)) and @@ -763,7 +808,7 @@ module Private { * Holds if there is a local step from `pred` to `succ`, which is synthesized * from a flow summary. */ - predicate summaryLocalStep(Node pred, Node succ, boolean preservesValue) { + predicate summaryLocalStep(SummaryNode pred, SummaryNode succ, boolean preservesValue) { exists( SummarizedCallable c, SummaryComponentStack inputContents, SummaryComponentStack outputContents @@ -789,7 +834,7 @@ module Private { * Holds if there is a read step of content `c` from `pred` to `succ`, which * is synthesized from a flow summary. */ - predicate summaryReadStep(Node pred, ContentSet c, Node succ) { + predicate summaryReadStep(SummaryNode pred, ContentSet c, SummaryNode succ) { exists(SummarizedCallable sc, SummaryComponentStack s | pred = summaryNodeInputState(sc, s.tail()) and succ = summaryNodeInputState(sc, s) and @@ -801,7 +846,7 @@ module Private { * Holds if there is a store step of content `c` from `pred` to `succ`, which * is synthesized from a flow summary. */ - predicate summaryStoreStep(Node pred, ContentSet c, Node succ) { + predicate summaryStoreStep(SummaryNode pred, ContentSet c, SummaryNode succ) { exists(SummarizedCallable sc, SummaryComponentStack s | pred = summaryNodeOutputState(sc, s) and succ = summaryNodeOutputState(sc, s.tail()) and @@ -813,7 +858,7 @@ module Private { * Holds if there is a jump step from `pred` to `succ`, which is synthesized * from a flow summary. */ - predicate summaryJumpStep(Node pred, Node succ) { + predicate summaryJumpStep(SummaryNode pred, SummaryNode succ) { exists(SummaryComponentStack s | s = SummaryComponentStack::singleton(SummaryComponent::syntheticGlobal(_)) and pred = summaryNodeOutputState(_, s) and @@ -840,9 +885,9 @@ module Private { * `a` on line 2 to the post-update node for `a` on that line (via an intermediate * node where field `b` is cleared). */ - predicate summaryClearsContent(Node n, ContentSet c) { + predicate summaryClearsContent(SummaryNode n, ContentSet c) { exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | - n = summaryNode(sc, state) and + n = TSummaryInternalNode(sc, state) and state.isInputState(sc, stack) and stack.head() = SummaryComponent::withoutContent(c) ) @@ -852,9 +897,9 @@ module Private { * Holds if the value that is being tracked is expected to be stored inside * content `c` at `n`. */ - predicate summaryExpectsContent(Node n, ContentSet c) { + predicate summaryExpectsContent(SummaryNode n, ContentSet c) { exists(SummarizedCallable sc, SummaryNodeState state, SummaryComponentStack stack | - n = summaryNode(sc, state) and + n = TSummaryInternalNode(sc, state) and state.isInputState(sc, stack) and stack.head() = SummaryComponent::withContent(c) ) @@ -862,17 +907,17 @@ module Private { pragma[noinline] private predicate viableParam( - DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, ParamNode p + DataFlowCall call, SummarizedCallable sc, ParameterPosition ppos, SummaryParamNode p ) { exists(DataFlowCallable c | c = inject(sc) and - p.isParameterOf(c, ppos) and + p = TSummaryParameterNode(sc, ppos) and c = viableCallable(call) ) } pragma[nomagic] - private ParamNode summaryArgParam(DataFlowCall call, ArgNode arg, SummarizedCallable sc) { + private SummaryParamNode summaryArgParam(DataFlowCall call, ArgNode arg, SummarizedCallable sc) { exists(ParameterPosition ppos | argumentPositionMatch(call, arg, ppos) and viableParam(call, sc, ppos, result) @@ -884,12 +929,12 @@ module Private { * local steps. `clearsOrExpects` records whether any node on the path from `p` to * `n` either clears or expects contents. */ - private predicate paramReachesLocal(ParamNode p, Node n, boolean clearsOrExpects) { + private predicate paramReachesLocal(SummaryParamNode p, SummaryNode n, boolean clearsOrExpects) { viableParam(_, _, _, p) and n = p and clearsOrExpects = false or - exists(Node mid, boolean clearsOrExpectsMid | + exists(SummaryNode mid, boolean clearsOrExpectsMid | paramReachesLocal(p, mid, clearsOrExpectsMid) and summaryLocalStep(mid, n, true) and if @@ -909,21 +954,33 @@ module Private { */ pragma[nomagic] predicate prohibitsUseUseFlow(ArgNode arg, SummarizedCallable sc) { - exists(ParamNode p, ParameterPosition ppos, Node ret | + exists(SummaryParamNode p, ParameterPosition ppos, SummaryNode ret | paramReachesLocal(p, ret, true) and p = summaryArgParam(_, arg, sc) and - p.isParameterOf(_, pragma[only_bind_into](ppos)) and + p = TSummaryParameterNode(_, pragma[only_bind_into](ppos)) and isParameterPostUpdate(ret, _, pragma[only_bind_into](ppos)) ) } + pragma[nomagic] + private predicate summaryReturnNodeExt(SummaryNode ret, ReturnKindExt rk) { + summaryReturnNode(ret, rk.(ValueReturnKind).getKind()) + or + exists(SummaryParamNode p, SummaryNode pre, ParameterPosition pos | + paramReachesLocal(p, pre, _) and + summaryPostUpdateNode(ret, pre) and + p = TSummaryParameterNode(_, pos) and + rk.(ParamUpdateReturnKind).getPosition() = pos + ) + } + bindingset[ret] - private ParamNode summaryArgParamRetOut( - ArgNode arg, ReturnNodeExt ret, OutNodeExt out, SummarizedCallable sc + private SummaryParamNode summaryArgParamRetOut( + ArgNode arg, SummaryNode ret, OutNodeExt out, SummarizedCallable sc ) { exists(DataFlowCall call, ReturnKindExt rk | result = summaryArgParam(call, arg, sc) and - ret.getKind() = pragma[only_bind_into](rk) and + summaryReturnNodeExt(ret, pragma[only_bind_into](rk)) and out = pragma[only_bind_into](rk).getAnOutNode(call) ) } @@ -936,9 +993,9 @@ module Private { * be useful to include in the exposed local data-flow/taint-tracking relations. */ predicate summaryThroughStepValue(ArgNode arg, Node out, SummarizedCallable sc) { - exists(ReturnKind rk, ReturnNode ret, DataFlowCall call | + exists(ReturnKind rk, SummaryNode ret, DataFlowCall call | summaryLocalStep(summaryArgParam(call, arg, sc), ret, true) and - ret.getKind() = pragma[only_bind_into](rk) and + summaryReturnNode(ret, pragma[only_bind_into](rk)) and out = getAnOutNode(call, pragma[only_bind_into](rk)) ) } @@ -951,7 +1008,9 @@ module Private { * be useful to include in the exposed local data-flow/taint-tracking relations. */ predicate summaryThroughStepTaint(ArgNode arg, Node out, SummarizedCallable sc) { - exists(ReturnNodeExt ret | summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false)) + exists(SummaryNode ret | + summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), ret, false) + ) } /** @@ -962,7 +1021,7 @@ module Private { * be useful to include in the exposed local data-flow/taint-tracking relations. */ predicate summaryGetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { - exists(Node mid, ReturnNodeExt ret | + exists(SummaryNode mid, SummaryNode ret | summaryReadStep(summaryArgParamRetOut(arg, ret, out, sc), c, mid) and summaryLocalStep(mid, ret, _) ) @@ -976,7 +1035,7 @@ module Private { * be useful to include in the exposed local data-flow/taint-tracking relations. */ predicate summarySetterStep(ArgNode arg, ContentSet c, Node out, SummarizedCallable sc) { - exists(Node mid, ReturnNodeExt ret | + exists(SummaryNode mid, SummaryNode ret | summaryLocalStep(summaryArgParamRetOut(arg, ret, out, sc), mid, _) and summaryStoreStep(mid, c, ret) ) @@ -1344,11 +1403,11 @@ module Private { } private newtype TNodeOrCall = - MkNode(Node n) { + MkNode(SummaryNode n) { exists(RelevantSummarizedCallable c | - n = summaryNode(c, _) + n = TSummaryInternalNode(c, _) or - n.(ParamNode).isParameterOf(inject(c), _) + n = TSummaryParameterNode(c, _) ) } or MkCall(DataFlowCall call) { @@ -1357,7 +1416,7 @@ module Private { } private class NodeOrCall extends TNodeOrCall { - Node asNode() { this = MkNode(result) } + SummaryNode asNode() { this = MkNode(result) } DataFlowCall asCall() { this = MkCall(result) } @@ -1377,9 +1436,11 @@ module Private { predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - this.asNode().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - or - this.asCall().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + filepath = "" and + startline = 0 and + startcolumn = 0 and + endline = 0 and + endcolumn = 0 } } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll index 1a0e06553d4..0d948b7dada 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll @@ -26,11 +26,8 @@ DataFlowCallable inject(SummarizedCallable c) { result.asSummarizedCallable() = /** Gets the parameter position of the instance parameter. */ ArgumentPosition callbackSelfParameterPosition() { result = -1 } -/** Gets the synthesized summary data-flow node for the given values. */ -Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = getSummaryNode(c, state) } - /** Gets the synthesized data-flow call for `receiver`. */ -SummaryCall summaryDataFlowCall(Node receiver) { result.getReceiver() = receiver } +SummaryCall summaryDataFlowCall(SummaryNode receiver) { result.getReceiver() = receiver } /** Gets the type of content `c`. */ DataFlowType getContentType(Content c) { result = c.getType() } diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll index af8f2273cbe..a43aa5be4f1 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/TaintTrackingUtil.qll @@ -86,6 +86,7 @@ module LocalTaintFlow { cached private module Cached { private import DataFlowImplCommon as DataFlowImplCommon + private import DataFlowPrivate as DataFlowPrivate cached predicate forceCachingInSameStage() { DataFlowImplCommon::forceCachingInSameStage() } @@ -136,7 +137,8 @@ private module Cached { ) ) or - FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false) + FlowSummaryImpl::Private::Steps::summaryLocalStep(src.(DataFlowPrivate::FlowSummaryNode) + .getSummaryNode(), sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false) } /**