|
|
|
|
@@ -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
|
|
|
|
|
|