mirror of
https://github.com/github/codeql.git
synced 2026-07-07 04:25:30 +02:00
233 lines
6.6 KiB
Plaintext
233 lines
6.6 KiB
Plaintext
/**
|
|
* @name Capture summary models.
|
|
* @description Finds applicable summary models to be used by other queries.
|
|
* @id java/utils/model-generator/summary-models
|
|
*/
|
|
|
|
import java
|
|
import semmle.code.java.dataflow.TaintTracking
|
|
import semmle.code.java.dataflow.internal.DataFlowImplCommon
|
|
import semmle.code.java.dataflow.internal.DataFlowNodes
|
|
import semmle.code.java.dataflow.internal.DataFlowPrivate
|
|
import semmle.code.java.dataflow.InstanceAccess
|
|
import ModelGeneratorUtils
|
|
|
|
string captureFlow(TargetAPI api) {
|
|
result = captureQualifierFlow(api) or
|
|
result = captureParameterFlowToReturnValue(api) or
|
|
result = captureFieldFlowIn(api) or
|
|
result = captureParameterToParameterFlow(api) or
|
|
result = captureFieldFlow(api)
|
|
}
|
|
|
|
/**
|
|
* Capture fluent APIs that return `this`.
|
|
* Example of a fluent API:
|
|
* ```
|
|
* public class Foo {
|
|
* public Foo someAPI() {
|
|
* // some side-effect
|
|
* return this;
|
|
* }
|
|
* }
|
|
* ```
|
|
*/
|
|
string captureQualifierFlow(TargetAPI api) {
|
|
exists(ReturnStmt rtn |
|
|
rtn.getEnclosingCallable() = api and
|
|
rtn.getResult().(ThisAccess).isOwnInstanceAccess()
|
|
) and
|
|
result = asValueModel(api, "Argument[-1]", "ReturnValue")
|
|
}
|
|
|
|
class FieldToReturnConfig extends TaintTracking::Configuration {
|
|
FieldToReturnConfig() { this = "FieldToReturnConfig" }
|
|
|
|
override predicate isSource(DataFlow::Node source) {
|
|
source instanceof DataFlow::InstanceParameterNode
|
|
}
|
|
|
|
override predicate isSink(DataFlow::Node sink) {
|
|
sink instanceof ReturnNodeExt and
|
|
not sink.(ReturnNode).asExpr().(ThisAccess).isOwnInstanceAccess() and
|
|
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable()))
|
|
}
|
|
|
|
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
isRelevantTaintStep(node1, node2)
|
|
}
|
|
|
|
override DataFlow::FlowFeature getAFeature() {
|
|
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Capture APIs that return tainted instance data.
|
|
* Example of an API that returns tainted instance data:
|
|
* ```
|
|
* public class Foo {
|
|
* private String tainted;
|
|
*
|
|
* public String returnsTainted() {
|
|
* return tainted;
|
|
* }
|
|
*
|
|
* public void putsTaintIntoParameter(List<String> foo) {
|
|
* foo.add(tainted);
|
|
* }
|
|
* }
|
|
* ```
|
|
* Captured Model:
|
|
* ```
|
|
* p;Foo;true;returnsTainted;;Argument[-1];ReturnValue;taint
|
|
* p;Foo;true;putsTaintIntoParameter;(List);Argument[-1];Argument[0];taint
|
|
* ```
|
|
*/
|
|
string captureFieldFlow(TargetAPI api) {
|
|
exists(FieldToReturnConfig config, ReturnNodeExt returnNodeExt |
|
|
config.hasFlow(_, returnNodeExt) and
|
|
returnNodeExt.getEnclosingCallable() = api and
|
|
not api.getDeclaringType() instanceof EnumType and
|
|
isRelevantType(returnNodeExt.getType())
|
|
|
|
|
result = asTaintModel(api, "Argument[-1]", returnNodeAsOutput(api, returnNodeExt))
|
|
)
|
|
}
|
|
|
|
class ParameterToFieldConfig extends TaintTracking::Configuration {
|
|
ParameterToFieldConfig() { this = "ParameterToFieldConfig" }
|
|
|
|
override predicate isSource(DataFlow::Node source) {
|
|
source instanceof DataFlow::ParameterNode and
|
|
isRelevantType(source.getType())
|
|
}
|
|
|
|
override predicate isSink(DataFlow::Node sink) {
|
|
thisAccess(sink.(DataFlow::PostUpdateNode).getPreUpdateNode())
|
|
}
|
|
|
|
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
store(node1, _, node2, _)
|
|
}
|
|
|
|
override DataFlow::FlowFeature getAFeature() {
|
|
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
|
}
|
|
}
|
|
|
|
private predicate thisAccess(DataFlow::Node n) {
|
|
n.asExpr().(InstanceAccess).isOwnInstanceAccess()
|
|
or
|
|
n.(DataFlow::ImplicitInstanceAccess).getInstanceAccess() instanceof OwnInstanceAccess
|
|
}
|
|
|
|
/**
|
|
* Captures APIs that accept input and store them in a field.
|
|
* Example:
|
|
* ```
|
|
* public class Foo {
|
|
* private String tainted;
|
|
* public void doSomething(String input) {
|
|
* tainted = input;
|
|
* }
|
|
* ```
|
|
* Captured Model:
|
|
* `p;Foo;true;doSomething;(String);Argument[0];Argument[-1];taint`
|
|
*/
|
|
string captureFieldFlowIn(TargetAPI api) {
|
|
exists(DataFlow::Node source, ParameterToFieldConfig config |
|
|
config.hasFlow(source, _) and
|
|
source.asParameter().getCallable() = api
|
|
|
|
|
result =
|
|
asTaintModel(api, "Argument[" + source.asParameter().getPosition() + "]", "Argument[-1]")
|
|
)
|
|
}
|
|
|
|
class ParameterToReturnValueTaintConfig extends TaintTracking::Configuration {
|
|
ParameterToReturnValueTaintConfig() { this = "ParameterToReturnValueTaintConfig" }
|
|
|
|
override predicate isSource(DataFlow::Node source) {
|
|
exists(TargetAPI api |
|
|
api = source.asParameter().getCallable() and
|
|
isRelevantType(api.getReturnType()) and
|
|
isRelevantType(source.asParameter().getType())
|
|
)
|
|
}
|
|
|
|
override predicate isSink(DataFlow::Node sink) { sink instanceof ReturnNode }
|
|
|
|
// consider store steps to track taint across objects to model factory methods returning tainted objects
|
|
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
|
store(node1, _, node2, _)
|
|
}
|
|
|
|
override DataFlow::FlowFeature getAFeature() {
|
|
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
|
}
|
|
}
|
|
|
|
predicate paramFlowToReturnValueExists(Parameter p) {
|
|
exists(ParameterToReturnValueTaintConfig config, ReturnStmt rtn |
|
|
config.hasFlow(DataFlow::parameterNode(p), DataFlow::exprNode(rtn.getResult()))
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Capture APIs that return (parts of) data passed in as a parameter.
|
|
* Example:
|
|
* ```
|
|
* public class Foo {
|
|
*
|
|
* public String returnData(String tainted) {
|
|
* return tainted.substring(0,10)
|
|
* }
|
|
* }
|
|
* ```
|
|
* Captured Model:
|
|
* ```
|
|
* p;Foo;true;returnData;;Argument[0];ReturnValue;taint
|
|
* ```
|
|
*/
|
|
string captureParameterFlowToReturnValue(TargetAPI api) {
|
|
exists(Parameter p |
|
|
p = api.getAParameter() and
|
|
paramFlowToReturnValueExists(p)
|
|
|
|
|
result = asTaintModel(api, parameterAccess(p), "ReturnValue")
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Capture APIs that pass tainted data from a parameter to a parameter.
|
|
* Example:
|
|
* ```
|
|
* public class Foo {
|
|
*
|
|
* public void addToList(String tainted, List<String> foo) {
|
|
* foo.add(tainted);
|
|
* }
|
|
* }
|
|
* ```
|
|
* Captured Model:
|
|
* ```
|
|
* p;Foo;true;addToList;;Argument[0];Argument[1];taint
|
|
* ```
|
|
*/
|
|
string captureParameterToParameterFlow(TargetAPI api) {
|
|
exists(DataFlow::ParameterNode source, DataFlow::PostUpdateNode sink |
|
|
source.getEnclosingCallable() = api and
|
|
sink.getPreUpdateNode().asExpr() = api.getAParameter().getAnAccess() and
|
|
TaintTracking::localTaint(source, sink)
|
|
|
|
|
result =
|
|
asTaintModel(api, parameterAccess(source.asParameter()),
|
|
parameterAccess(sink.getPreUpdateNode().asExpr().(VarAccess).getVariable().(Parameter)))
|
|
)
|
|
}
|
|
|
|
from TargetAPI api, string flow
|
|
where flow = captureFlow(api)
|
|
select flow order by flow
|