Skip to content

Commit d0b6808

Browse files
committed
Java: Move common CSV logic for sources and sinks into shared library
1 parent 7382b34 commit d0b6808

File tree

7 files changed

+255
-176
lines changed

7 files changed

+255
-176
lines changed

java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 28 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import java
6868
private import semmle.code.java.dataflow.DataFlow::DataFlow
6969
private import internal.DataFlowPrivate
7070
private import internal.FlowSummaryImpl::Private::External
71+
private import internal.FlowSummaryImplSpecific
7172
private import FlowSummary
7273

7374
/**
@@ -359,7 +360,8 @@ private predicate summaryModel(string row) {
359360
any(SummaryModelCsv s).row(row)
360361
}
361362

362-
private predicate sourceModel(
363+
/** Holds if a source model exists for the given parameters. */
364+
predicate sourceModel(
363365
string namespace, string type, boolean subtypes, string name, string signature, string ext,
364366
string output, string kind
365367
) {
@@ -377,7 +379,8 @@ private predicate sourceModel(
377379
)
378380
}
379381

380-
private predicate sinkModel(
382+
/** Holds if a sink model exists for the given parameters. */
383+
predicate sinkModel(
381384
string namespace, string type, boolean subtypes, string name, string signature, string ext,
382385
string input, string kind
383386
) {
@@ -395,7 +398,8 @@ private predicate sinkModel(
395398
)
396399
}
397400

398-
private predicate summaryModel(
401+
/** Holds if a summary model exists for the given parameters. */
402+
predicate summaryModel(
399403
string namespace, string type, boolean subtypes, string name, string signature, string ext,
400404
string input, string output, string kind
401405
) {
@@ -600,7 +604,8 @@ private Element interpretElement0(
600604
)
601605
}
602606

603-
private Element interpretElement(
607+
/** Gets the source/sink/summary element corresponding to the supplied parameters. */
608+
Element interpretElement(
604609
string namespace, string type, boolean subtypes, string name, string signature, string ext
605610
) {
606611
elementSpec(namespace, type, subtypes, name, signature, ext) and
@@ -611,166 +616,25 @@ private Element interpretElement(
611616
)
612617
}
613618

614-
private predicate sourceElement(Element e, string output, string kind) {
615-
exists(
616-
string namespace, string type, boolean subtypes, string name, string signature, string ext
617-
|
618-
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind) and
619-
e = interpretElement(namespace, type, subtypes, name, signature, ext)
620-
)
621-
}
622-
623-
private predicate sinkElement(Element e, string input, string kind) {
624-
exists(
625-
string namespace, string type, boolean subtypes, string name, string signature, string ext
626-
|
627-
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind) and
628-
e = interpretElement(namespace, type, subtypes, name, signature, ext)
629-
)
630-
}
631-
632-
/**
633-
* Holds if an external flow summary exists for `e` with input specification
634-
* `input`, output specification `output`, and kind `kind`.
635-
*/
636-
predicate summaryElement(Element e, string input, string output, string kind) {
637-
exists(
638-
string namespace, string type, boolean subtypes, string name, string signature, string ext
639-
|
640-
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
641-
e = interpretElement(namespace, type, subtypes, name, signature, ext)
642-
)
643-
}
644-
645-
/** Gets a specification used in a source model, sink model, or summary model. */
646-
string inOutSpec() {
647-
sourceModel(_, _, _, _, _, _, result, _) or
648-
sinkModel(_, _, _, _, _, _, result, _) or
649-
summaryModel(_, _, _, _, _, _, result, _, _) or
650-
summaryModel(_, _, _, _, _, _, _, result, _)
651-
}
652-
653-
private predicate inputNeedsReference(string c) {
654-
c = "Argument" or
655-
parseArg(c, _)
656-
}
657-
658-
private predicate outputNeedsReference(string c) {
659-
c = "Argument" or
660-
parseArg(c, _) or
661-
c = "ReturnValue"
662-
}
663-
664-
private predicate sourceElementRef(Top ref, string output, string kind) {
665-
exists(Element e |
666-
sourceElement(e, output, kind) and
667-
if outputNeedsReference(specLast(output))
668-
then ref.(Call).getCallee().getSourceDeclaration() = e
669-
else ref = e
670-
)
671-
}
672-
673-
private predicate sinkElementRef(Top ref, string input, string kind) {
674-
exists(Element e |
675-
sinkElement(e, input, kind) and
676-
if inputNeedsReference(specLast(input))
677-
then ref.(Call).getCallee().getSourceDeclaration() = e
678-
else ref = e
679-
)
680-
}
681-
682-
private predicate summaryElementRef(Top ref, string input, string output, string kind) {
683-
exists(Element e |
684-
summaryElement(e, input, output, kind) and
685-
if inputNeedsReference(specLast(input))
686-
then ref.(Call).getCallee().getSourceDeclaration() = e
687-
else ref = e
688-
)
689-
}
690-
691-
private newtype TAstOrNode =
692-
TAst(Top t) or
693-
TNode(Node n)
694-
695-
private predicate interpretOutput(string output, int idx, Top ref, TAstOrNode node) {
696-
(
697-
sourceElementRef(ref, output, _) or
698-
summaryElementRef(ref, _, output, _)
699-
) and
700-
specLength(output, idx) and
701-
node = TAst(ref)
702-
or
703-
exists(Top mid, string c, Node n |
704-
interpretOutput(output, idx + 1, ref, TAst(mid)) and
705-
specSplit(output, c, idx) and
706-
node = TNode(n)
707-
|
708-
exists(int pos | n.(PostUpdateNode).getPreUpdateNode().(ArgumentNode).argumentOf(mid, pos) |
709-
c = "Argument" or parseArg(c, pos)
710-
)
711-
or
712-
exists(int pos | n.(ParameterNode).isParameterOf(mid, pos) |
713-
c = "Parameter" or parseParam(c, pos)
714-
)
715-
or
716-
(c = "Parameter" or c = "") and
717-
n.asParameter() = mid
718-
or
719-
c = "ReturnValue" and
720-
n.asExpr().(Call) = mid
721-
or
722-
c = "" and
723-
n.asExpr().(FieldRead).getField() = mid
724-
)
725-
}
726-
727-
private predicate interpretInput(string input, int idx, Top ref, TAstOrNode node) {
728-
(
729-
sinkElementRef(ref, input, _) or
730-
summaryElementRef(ref, input, _, _)
731-
) and
732-
specLength(input, idx) and
733-
node = TAst(ref)
734-
or
735-
exists(Top mid, string c, Node n |
736-
interpretInput(input, idx + 1, ref, TAst(mid)) and
737-
specSplit(input, c, idx) and
738-
node = TNode(n)
739-
|
740-
exists(int pos | n.(ArgumentNode).argumentOf(mid, pos) | c = "Argument" or parseArg(c, pos))
741-
or
742-
exists(ReturnStmt ret |
743-
c = "ReturnValue" and
744-
n.asExpr() = ret.getResult() and
745-
mid = ret.getEnclosingCallable()
746-
)
747-
or
748-
exists(FieldWrite fw |
749-
c = "" and
750-
fw.getField() = mid and
751-
n.asExpr() = fw.getRHS()
752-
)
753-
)
754-
}
619+
cached
620+
private module Cached {
621+
/**
622+
* Holds if `node` is specified as a source with the given kind in a CSV flow
623+
* model.
624+
*/
625+
cached
626+
predicate sourceNode(Node node, string kind) {
627+
exists(InterpretNode n | isSourceNode(n, kind) and n.asNode() = node)
628+
}
755629

756-
/**
757-
* Holds if `node` is specified as a source with the given kind in a CSV flow
758-
* model.
759-
*/
760-
predicate sourceNode(Node node, string kind) {
761-
exists(Top ref, string output |
762-
sourceElementRef(ref, output, kind) and
763-
interpretOutput(output, 0, ref, TNode(node))
764-
)
630+
/**
631+
* Holds if `node` is specified as a sink with the given kind in a CSV flow
632+
* model.
633+
*/
634+
cached
635+
predicate sinkNode(Node node, string kind) {
636+
exists(InterpretNode n | isSinkNode(n, kind) and n.asNode() = node)
637+
}
765638
}
766639

767-
/**
768-
* Holds if `node` is specified as a sink with the given kind in a CSV flow
769-
* model.
770-
*/
771-
predicate sinkNode(Node node, string kind) {
772-
exists(Top ref, string input |
773-
sinkElementRef(ref, input, kind) and
774-
interpretInput(input, 0, ref, TNode(node))
775-
)
776-
}
640+
import Cached

java/ql/src/semmle/code/java/dataflow/internal/DataFlowDispatch.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@ private import DataFlowUtil
44
private import semmle.code.java.dataflow.InstanceAccess
55
private import semmle.code.java.dataflow.FlowSummary
66
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
7+
private import semmle.code.java.dataflow.internal.FlowSummaryImplSpecific
78

89
private module DispatchImpl {
910
/** Gets a viable implementation of the target of the given `Call`. */
1011
Callable viableCallable(Call c) {
1112
result = VirtualDispatch::viableCallable(c)
1213
or
13-
result.(SummarizedCallable) = c.getCallee().getSourceDeclaration()
14+
result = c.getCallee().getSourceDeclaration() and
15+
(
16+
result instanceof SummarizedCallable
17+
or
18+
sourceElement(result, _, _)
19+
or
20+
sinkElement(result, _, _)
21+
)
1422
}
1523

1624
/**

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ private import semmle.code.java.controlflow.Guards
99
private import semmle.code.java.dataflow.ExternalFlow
1010
private import semmle.code.java.dataflow.FlowSteps
1111
private import semmle.code.java.dataflow.FlowSummary
12-
import semmle.code.java.dataflow.InstanceAccess
12+
private import semmle.code.java.dataflow.InstanceAccess
1313
private import FlowSummaryImpl as FlowSummaryImpl
1414
private import TaintTrackingUtil as TaintTrackingUtil
1515
import DataFlowNodes::Public
16+
import semmle.code.Unit
1617

1718
/** Holds if `n` is an access to an unqualified `this` at `cfgnode`. */
1819
private predicate thisAccess(Node n, ControlFlowNode cfgnode) {

0 commit comments

Comments
 (0)