Skip to content

Commit 14f9a5c

Browse files
committed
Java: Move some CSV flow summary code into shared library
1 parent 6d7b95c commit 14f9a5c

File tree

3 files changed

+139
-188
lines changed

3 files changed

+139
-188
lines changed

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

Lines changed: 24 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import java
6868
private import semmle.code.java.dataflow.DataFlow::DataFlow
6969
private import internal.DataFlowPrivate
70+
private import internal.FlowSummaryImpl::Private::External
7071
private import FlowSummary
7172

7273
/**
@@ -498,10 +499,15 @@ module CsvValidation {
498499
or
499500
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
500501
|
501-
specSplit(input, part, _) and
502-
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
503-
not (part = "Argument" and pred = "sink") and
504-
not parseArg(part, _) and
502+
(
503+
invalidSpecComponent(input, part) and
504+
not part = "" and
505+
not (part = "Argument" and pred = "sink") and
506+
not parseArg(part, _)
507+
or
508+
specSplit(input, part, _) and
509+
parseParam(part, _)
510+
) and
505511
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
506512
)
507513
or
@@ -510,11 +516,9 @@ module CsvValidation {
510516
or
511517
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
512518
|
513-
specSplit(output, part, _) and
514-
not part.regexpMatch("|ReturnValue|ArrayElement|Element|MapKey|MapValue") and
519+
invalidSpecComponent(output, part) and
520+
not part = "" and
515521
not (part = ["Argument", "Parameter"] and pred = "source") and
516-
not parseArg(part, _) and
517-
not parseParam(part, _) and
518522
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
519523
)
520524
or
@@ -624,7 +628,11 @@ private predicate sinkElement(Element e, string input, string kind) {
624628
)
625629
}
626630

627-
private predicate summaryElement(Element e, string input, string output, string kind) {
631+
/**
632+
* Holds if an external flow summary exists for `e` with input specification
633+
* `input`, output specification `output`, and kind `kind`.
634+
*/
635+
predicate summaryElement(Element e, string input, string output, string kind) {
628636
exists(
629637
string namespace, string type, boolean subtypes, string name, string signature, string ext
630638
|
@@ -633,52 +641,14 @@ private predicate summaryElement(Element e, string input, string output, string
633641
)
634642
}
635643

636-
private string inOutSpec() {
644+
/** Gets a specification used in a source model, sink model, or summary model. */
645+
string inOutSpec() {
637646
sourceModel(_, _, _, _, _, _, result, _) or
638647
sinkModel(_, _, _, _, _, _, result, _) or
639648
summaryModel(_, _, _, _, _, _, result, _, _) or
640649
summaryModel(_, _, _, _, _, _, _, result, _)
641650
}
642651

643-
private predicate specSplit(string s, string c, int n) {
644-
inOutSpec() = s and s.splitAt(" of ", n) = c
645-
}
646-
647-
private predicate len(string s, int len) { len = 1 + max(int n | specSplit(s, _, n)) }
648-
649-
private string getLast(string s) {
650-
exists(int len |
651-
len(s, len) and
652-
specSplit(s, result, len - 1)
653-
)
654-
}
655-
656-
private predicate parseParam(string c, int n) {
657-
specSplit(_, c, _) and
658-
(
659-
c.regexpCapture("Parameter\\[([-0-9]+)\\]", 1).toInt() = n
660-
or
661-
exists(int n1, int n2 |
662-
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
663-
c.regexpCapture("Parameter\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
664-
n = [n1 .. n2]
665-
)
666-
)
667-
}
668-
669-
private predicate parseArg(string c, int n) {
670-
specSplit(_, c, _) and
671-
(
672-
c.regexpCapture("Argument\\[([-0-9]+)\\]", 1).toInt() = n
673-
or
674-
exists(int n1, int n2 |
675-
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 1).toInt() = n1 and
676-
c.regexpCapture("Argument\\[([-0-9]+)\\.\\.([0-9]+)\\]", 2).toInt() = n2 and
677-
n = [n1 .. n2]
678-
)
679-
)
680-
}
681-
682652
private predicate inputNeedsReference(string c) {
683653
c = "Argument" or
684654
parseArg(c, _)
@@ -693,7 +663,7 @@ private predicate outputNeedsReference(string c) {
693663
private predicate sourceElementRef(Top ref, string output, string kind) {
694664
exists(Element e |
695665
sourceElement(e, output, kind) and
696-
if outputNeedsReference(getLast(output))
666+
if outputNeedsReference(specLast(output))
697667
then ref.(Call).getCallee().getSourceDeclaration() = e
698668
else ref = e
699669
)
@@ -702,7 +672,7 @@ private predicate sourceElementRef(Top ref, string output, string kind) {
702672
private predicate sinkElementRef(Top ref, string input, string kind) {
703673
exists(Element e |
704674
sinkElement(e, input, kind) and
705-
if inputNeedsReference(getLast(input))
675+
if inputNeedsReference(specLast(input))
706676
then ref.(Call).getCallee().getSourceDeclaration() = e
707677
else ref = e
708678
)
@@ -711,81 +681,12 @@ private predicate sinkElementRef(Top ref, string input, string kind) {
711681
private predicate summaryElementRef(Top ref, string input, string output, string kind) {
712682
exists(Element e |
713683
summaryElement(e, input, output, kind) and
714-
if inputNeedsReference(getLast(input))
684+
if inputNeedsReference(specLast(input))
715685
then ref.(Call).getCallee().getSourceDeclaration() = e
716686
else ref = e
717687
)
718688
}
719689

720-
private SummaryComponent interpretComponent(string c) {
721-
specSplit(_, c, _) and
722-
(
723-
exists(int pos | parseArg(c, pos) and result = SummaryComponent::argument(pos))
724-
or
725-
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
726-
or
727-
c = "ReturnValue" and result = SummaryComponent::return()
728-
or
729-
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
730-
or
731-
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
732-
or
733-
c = "MapKey" and result = SummaryComponent::content(any(MapKeyContent c0))
734-
or
735-
c = "MapValue" and result = SummaryComponent::content(any(MapValueContent c0))
736-
)
737-
}
738-
739-
private predicate interpretSpec(string spec, int idx, SummaryComponentStack stack) {
740-
exists(string c |
741-
summaryElement(_, spec, _, _) or
742-
summaryElement(_, _, spec, _)
743-
|
744-
len(spec, idx + 1) and
745-
specSplit(spec, c, idx) and
746-
stack = SummaryComponentStack::singleton(interpretComponent(c))
747-
)
748-
or
749-
exists(SummaryComponent head, SummaryComponentStack tail |
750-
interpretSpec(spec, idx, head, tail) and
751-
stack = SummaryComponentStack::push(head, tail)
752-
)
753-
}
754-
755-
private predicate interpretSpec(
756-
string output, int idx, SummaryComponent head, SummaryComponentStack tail
757-
) {
758-
exists(string c |
759-
interpretSpec(output, idx + 1, tail) and
760-
specSplit(output, c, idx) and
761-
head = interpretComponent(c)
762-
)
763-
}
764-
765-
private class MkStack extends RequiredSummaryComponentStack {
766-
MkStack() { interpretSpec(_, _, _, this) }
767-
768-
override predicate required(SummaryComponent c) { interpretSpec(_, _, c, this) }
769-
}
770-
771-
private class SummarizedCallableExternal extends SummarizedCallable {
772-
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
773-
774-
override predicate propagatesFlow(
775-
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
776-
) {
777-
exists(string inSpec, string outSpec, string kind |
778-
summaryElement(this, inSpec, outSpec, kind) and
779-
interpretSpec(inSpec, 0, input) and
780-
interpretSpec(outSpec, 0, output)
781-
|
782-
kind = "value" and preservesValue = true
783-
or
784-
kind = "taint" and preservesValue = false
785-
)
786-
}
787-
}
788-
789690
private newtype TAstOrNode =
790691
TAst(Top t) or
791692
TNode(Node n)
@@ -795,7 +696,7 @@ private predicate interpretOutput(string output, int idx, Top ref, TAstOrNode no
795696
sourceElementRef(ref, output, _) or
796697
summaryElementRef(ref, _, output, _)
797698
) and
798-
len(output, idx) and
699+
specLength(output, idx) and
799700
node = TAst(ref)
800701
or
801702
exists(Top mid, string c, Node n |
@@ -827,7 +728,7 @@ private predicate interpretInput(string input, int idx, Top ref, TAstOrNode node
827728
sinkElementRef(ref, input, _) or
828729
summaryElementRef(ref, input, _, _)
829730
) and
830-
len(input, idx) and
731+
specLength(input, idx) and
831732
node = TAst(ref)
832733
or
833734
exists(Top mid, string c, Node n |

0 commit comments

Comments
 (0)