Java: Use shared flow summary library for csv models.

This commit is contained in:
Anders Schack-Mulligen
2021-03-19 15:16:57 +01:00
parent 36abf8733e
commit a27dac029f
4 changed files with 79 additions and 21 deletions

View File

@@ -67,6 +67,7 @@
import java
private import semmle.code.java.dataflow.DataFlow::DataFlow
private import internal.DataFlowPrivate
private import FlowSummary
/**
* A module importing the frameworks that provide external flow data,
@@ -459,7 +460,8 @@ module CsvValidation {
summaryModel(_, _, _, _, _, _, input, _, _) and pred = "summary"
|
specSplit(input, part, _) and
not part.regexpMatch("|Argument|ReturnValue") and
not part.regexpMatch("|ReturnValue|ArrayElement|Element") and
not (part = "Argument" and pred = "sink") and
not parseArg(part, _) and
msg = "Unrecognized input specification \"" + part + "\" in " + pred + " model."
)
@@ -470,7 +472,8 @@ module CsvValidation {
summaryModel(_, _, _, _, _, _, _, output, _) and pred = "summary"
|
specSplit(output, part, _) and
not part.regexpMatch("|Argument|Parameter|ReturnValue") and
not part.regexpMatch("|ReturnValue|ArrayElement|Element") and
not (part = ["Argument", "Parameter"] and pred = "source") and
not parseArg(part, _) and
not parseParam(part, _) and
msg = "Unrecognized output specification \"" + part + "\" in " + pred + " model."
@@ -675,6 +678,75 @@ private predicate summaryElementRef(Top ref, string input, string output, string
)
}
private SummaryComponent interpretComponent(string c) {
specSplit(_, c, _) and
(
exists(int pos | parseArg(c, pos) and result = SummaryComponent::argument(pos))
or
exists(int pos | parseParam(c, pos) and result = SummaryComponent::parameter(pos))
or
c = "ReturnValue" and result = SummaryComponent::return()
or
c = "ArrayElement" and result = SummaryComponent::content(any(ArrayContent c0))
or
c = "Element" and result = SummaryComponent::content(any(CollectionContent c0))
// or
// c = "MapKey" and result = SummaryComponent::content(any(MapKeyContent c0))
// or
// c = "MapValue" and result = SummaryComponent::content(any(MapValueContent c0))
)
}
private predicate interpretSpec(string spec, int idx, SummaryComponentStack stack) {
exists(string c |
summaryElement(_, spec, _, _) or
summaryElement(_, _, spec, _)
|
len(spec, idx + 1) and
specSplit(spec, c, idx) and
stack = SummaryComponentStack::singleton(interpretComponent(c))
)
or
exists(SummaryComponent head, SummaryComponentStack tail |
interpretSpec(spec, idx, head, tail) and
stack = SummaryComponentStack::push(head, tail)
)
}
private predicate interpretSpec(
string output, int idx, SummaryComponent head, SummaryComponentStack tail
) {
exists(string c |
interpretSpec(output, idx + 1, tail) and
specSplit(output, c, idx) and
head = interpretComponent(c)
)
}
private class MkStack extends RequiredSummaryComponentStack {
MkStack() { interpretSpec(_, _, _, this) }
override predicate required(SummaryComponent c) { interpretSpec(_, _, c, this) }
}
private class SummarizedCallableExternal extends SummarizedCallable {
SummarizedCallableExternal() { summaryElement(this, _, _, _) }
override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
exists(string inSpec, string outSpec, string kind |
summaryElement(this, inSpec, outSpec, kind) and
interpretSpec(inSpec, 0, input) and
interpretSpec(outSpec, 0, output)
|
kind = "value" and preservesValue = true
or
kind = "taint" and preservesValue = false
)
}
}
private newtype TAstOrNode =
TAst(Top t) or
TNode(Node n)
@@ -761,15 +833,3 @@ predicate sinkNode(Node node, string kind) {
interpretInput(input, 0, ref, TNode(node))
)
}
/**
* Holds if `node1` to `node2` is specified as a flow step with the given kind
* in a CSV flow model.
*/
predicate summaryStep(Node node1, Node node2, string kind) {
exists(Top ref, string input, string output |
summaryElementRef(ref, input, output, kind) and
interpretInput(input, 0, ref, TNode(node1)) and
interpretOutput(output, 0, ref, TNode(node2))
)
}

View File

@@ -8,7 +8,9 @@ private import internal.DataFlowDispatch
private import internal.DataFlowPrivate
// import all instances below
private module Summaries { }
private module Summaries {
private import semmle.code.java.dataflow.ExternalFlow
}
class SummaryComponent = Impl::Public::SummaryComponent;

View File

@@ -142,8 +142,6 @@ predicate simpleLocalFlowStep(Node node1, Node node2) {
or
node2.asExpr().(AssignExpr).getSource() = node1.asExpr()
or
summaryStep(node1, node2, "value")
or
exists(MethodAccess ma, ValuePreservingMethod m, int argNo |
ma.getCallee().getSourceDeclaration() = m and m.returnsValue(argNo)
|

View File

@@ -57,16 +57,14 @@ private predicate localAdditionalBasicTaintStep(DataFlow::Node src, DataFlow::No
localAdditionalTaintUpdateStep(src.asExpr(),
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
or
summaryStep(src, sink, "taint") and
not summaryStep(src, sink, "value")
or
exists(Argument arg |
src.asExpr() = arg and
arg.isVararg() and
sink.(DataFlow::ImplicitVarargsArray).getCall() = arg.getCall()
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false)
FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, false) and
not FlowSummaryImpl::Private::Steps::summaryLocalStep(src, sink, true)
}
/**