Java: Refactor the model generator configurations to use the new API.

This commit is contained in:
Michael Nebel
2023-03-15 11:56:55 +01:00
parent 71c37dba32
commit eed8c72ce6
5 changed files with 77 additions and 83 deletions

View File

@@ -8,10 +8,6 @@
import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateToSinkConfig() { any() }
}
from DataFlowTargetApi api, string sink
where sink = captureSink(api)
select sink order by sink

View File

@@ -8,10 +8,6 @@
import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateFromSourceConfig() { any() }
}
from DataFlowTargetApi api, string source
where source = captureSource(api)
select source order by source

View File

@@ -5,14 +5,6 @@
private import CaptureModelsSpecific
class ActiveConfiguration extends Unit {
predicate activateThroughFlowConfig() { none() }
predicate activateFromSourceConfig() { none() }
predicate activateToSinkConfig() { none() }
}
class DataFlowTargetApi extends TargetApiSpecific {
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
}
@@ -46,6 +38,20 @@ private predicate isRelevantContent(DataFlow::Content c) {
DataFlowPrivate::containerContent(c)
}
/**
* Gets the MaD string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = qualifierString() and p instanceof InstanceParameterNode
}
/**
* Gets the MaD input string representation of `source`.
*/
string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific(source) }
/**
* Gets the summary model for `api` with `input`, `output` and `kind`.
*/
@@ -111,61 +117,70 @@ string captureQualifierFlow(TargetApiSpecific api) {
private int accessPathLimit() { result = 2 }
private newtype TTaintState =
TTaintRead(int n) { n in [0 .. accessPathLimit()] } or
TTaintStore(int n) { n in [1 .. accessPathLimit()] }
abstract private class TaintState extends TTaintState {
abstract string toString();
}
/**
* A FlowState representing a tainted read.
*/
private class TaintRead extends DataFlow::FlowState {
private class TaintRead extends TaintState, TTaintRead {
private int step;
TaintRead() { this = "TaintRead(" + step + ")" and step in [0 .. accessPathLimit()] }
TaintRead() { this = TTaintRead(step) }
/**
* Gets the flow state step number.
*/
int getStep() { result = step }
override string toString() { result = "TaintRead(" + step + ")" }
}
/**
* A FlowState representing a tainted write.
*/
private class TaintStore extends DataFlow::FlowState {
private class TaintStore extends TaintState, TTaintStore {
private int step;
TaintStore() { this = "TaintStore(" + step + ")" and step in [1 .. accessPathLimit()] }
TaintStore() { this = TTaintStore(step) }
/**
* Gets the flow state step number.
*/
int getStep() { result = step }
override string toString() { result = "TaintStore(" + step + ")" }
}
/**
* A TaintTracking Configuration used for tracking flow through APIs.
* A data-flow configuration for tracking flow through APIs.
* The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters.
*
* This can be used to generate Flow summaries for APIs from parameter to return.
*/
private class ThroughFlowConfig extends TaintTracking::Configuration {
ThroughFlowConfig() {
this = "ThroughFlowConfig" and any(ActiveConfiguration ac).activateThroughFlowConfig()
}
module ThroughFlowConfig implements DataFlow::StateConfigSig {
class FlowState = TaintState;
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
predicate isSource(DataFlow::Node source, FlowState state) {
source instanceof DataFlow::ParameterNode and
source.getEnclosingCallable() instanceof DataFlowTargetApi and
state.(TaintRead).getStep() = 0
}
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
predicate isSink(DataFlow::Node sink, FlowState state) {
sink instanceof DataFlowImplCommon::ReturnNodeExt and
not isOwnInstanceAccessNode(sink) and
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
(state instanceof TaintRead or state instanceof TaintStore)
}
override predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
exists(DataFlowImplCommon::TypedContent tc |
DataFlowImplCommon::store(node1, tc, node2, _) and
@@ -184,24 +199,28 @@ private class ThroughFlowConfig extends TaintTracking::Configuration {
)
}
override predicate isSanitizer(DataFlow::Node n) {
predicate isBarrier(DataFlow::Node n) {
exists(Type t | t = n.getType() and not isRelevantType(t))
}
override DataFlow::FlowFeature getAFeature() {
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private module ThroughFlow = TaintTracking::MakeWithState<ThroughFlowConfig>;
/**
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
*/
string captureThroughFlow(DataFlowTargetApi api) {
exists(
ThroughFlowConfig config, DataFlow::ParameterNode p,
DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input, string output
DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input,
string output
|
config.hasFlow(p, returnNodeExt) and
ThroughFlow::hasFlow(p, returnNodeExt) and
returnNodeExt.getEnclosingCallable() = api and
input = parameterNodeAsInput(p) and
output = returnNodeAsOutput(returnNodeExt) and
@@ -211,41 +230,37 @@ string captureThroughFlow(DataFlowTargetApi api) {
}
/**
* A TaintTracking Configuration used for tracking flow through APIs.
* A dataflow configuration used for finding new sources.
* The sources are the already known existing sources and the sinks are the API return nodes.
*
* This can be used to generate Source summaries for an API, if the API expose an already known source
* via its return (then the API itself becomes a source).
*/
private class FromSourceConfiguration extends TaintTracking::Configuration {
FromSourceConfiguration() {
this = "FromSourceConfiguration" and any(ActiveConfiguration ac).activateFromSourceConfig()
}
module FromSourceConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) }
override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) }
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(DataFlowTargetApi c |
sink instanceof DataFlowImplCommon::ReturnNodeExt and
sink.getEnclosingCallable() = c
)
}
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSinkCallContext
}
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSinkCallContext }
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
isRelevantTaintStep(node1, node2)
}
}
private module FromSource = TaintTracking::Make<FromSourceConfig>;
/**
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
*/
string captureSource(DataFlowTargetApi api) {
exists(DataFlow::Node source, DataFlow::Node sink, FromSourceConfiguration config, string kind |
config.hasFlow(source, sink) and
exists(DataFlow::Node source, DataFlow::Node sink, string kind |
FromSource::hasFlow(source, sink) and
ExternalFlow::sourceNode(source, kind) and
api = sink.getEnclosingCallable() and
isRelevantSourceKind(kind) and
@@ -254,35 +269,30 @@ string captureSource(DataFlowTargetApi api) {
}
/**
* A TaintTracking Configuration used for tracking flow through APIs.
* A dataflow configuration used for finding new sinks.
* The sources are the parameters of the API and the fields of the enclosing type.
*
* This can be used to generate Sink summaries for APIs, if the API propagates a parameter (or enclosing type field)
* into an existing known sink (then the API itself becomes a sink).
*/
private class PropagateToSinkConfiguration extends TaintTracking::Configuration {
PropagateToSinkConfiguration() {
this = "parameters or fields flowing into sinks" and
any(ActiveConfiguration ac).activateToSinkConfig()
}
module PropagateToSinkConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { apiSource(source) }
override predicate isSource(DataFlow::Node source) { apiSource(source) }
predicate isSink(DataFlow::Node sink) { ExternalFlow::sinkNode(sink, _) }
override predicate isSink(DataFlow::Node sink) { ExternalFlow::sinkNode(sink, _) }
predicate isBarrier(DataFlow::Node node) { sinkModelSanitizer(node) }
override predicate isSanitizer(DataFlow::Node node) { sinkModelSanitizer(node) }
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSourceCallContext
}
DataFlow::FlowFeature getAFeature() { result instanceof DataFlow::FeatureHasSourceCallContext }
}
private module PropagateToSink = TaintTracking::Make<PropagateToSinkConfig>;
/**
* Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink.
*/
string captureSink(DataFlowTargetApi api) {
exists(DataFlow::Node src, DataFlow::Node sink, PropagateToSinkConfiguration config, string kind |
config.hasFlow(src, sink) and
exists(DataFlow::Node src, DataFlow::Node sink, string kind |
PropagateToSink::hasFlow(src, sink) and
ExternalFlow::sinkNode(sink, kind) and
api = src.getEnclosingCallable() and
isRelevantSinkKind(kind) and

View File

@@ -130,7 +130,7 @@ private predicate partialModel(TargetApiSpecific api, string type, string name,
}
/**
* Computes the first 6 columns for CSV rows.
* Computes the first 6 columns for MaD rows.
*/
string asPartialModel(TargetApiSpecific api) {
exists(string type, string name, string parameters |
@@ -145,7 +145,7 @@ string asPartialModel(TargetApiSpecific api) {
}
/**
* Computes the first 4 columns for neutral CSV rows.
* Computes the first 4 columns for neutral MaD rows.
*/
string asPartialNeutralModel(TargetApiSpecific api) {
exists(string type, string name, string parameters |
@@ -187,11 +187,14 @@ predicate isRelevantType(J::Type t) {
}
/**
* Gets the CSV string representation of the qualifier.
* Gets the MaD string representation of the qualifier.
*/
string qualifierString() { result = "Argument[this]" }
private string parameterAccess(J::Parameter p) {
/**
* Gets the MaD string representation of the parameter `p`.
*/
string parameterAccess(J::Parameter p) {
if
p.getType() instanceof J::Array and
not isPrimitiveTypeUsedForBulkData(p.getType().(J::Array).getElementType())
@@ -202,17 +205,10 @@ private string parameterAccess(J::Parameter p) {
else result = "Argument[" + p.getPosition() + "]"
}
/**
* Gets the CSV string representation of the parameter node `p`.
*/
string parameterNodeAsInput(DataFlow::ParameterNode p) {
result = parameterAccess(p.asParameter())
or
result = qualifierString() and p instanceof DataFlow::InstanceParameterNode
}
class InstanceParameterNode = DataFlow::InstanceParameterNode;
/**
* Gets the CSV string represention of the the return node `node`.
* Gets the MaD string represention of the the return node `node`.
*/
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
@@ -268,9 +264,9 @@ predicate apiSource(DataFlow::Node source) {
}
/**
* Gets the CSV input string representation of `source`.
* Gets the MaD input string representation of `source`.
*/
string asInputArgument(DataFlow::Node source) {
string asInputArgumentSpecific(DataFlow::Node source) {
exists(int pos |
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
result = "Argument[" + pos + "]"

View File

@@ -1,9 +1,5 @@
private import CaptureModels
private class Activate extends ActiveConfiguration {
override predicate activateThroughFlowConfig() { any() }
}
/**
* Capture fluent APIs that return `this`.
* Example of a fluent API: