mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
C#/Java: Initial merge ModelGeneratorUtils into CaptureModels.
This commit is contained in:
@@ -75,10 +75,6 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - Utils": [
|
||||
"java/ql/src/utils/model-generator/internal/ModelGeneratorUtils.qll",
|
||||
"csharp/ql/src/utils/model-generator/internal/ModelGeneratorUtils.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - CaptureModels": [
|
||||
"java/ql/src/utils/model-generator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/model-generator/internal/CaptureModels.qll"
|
||||
@@ -549,4 +545,4 @@
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id csharp/utils/model-generator/sink-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
from TargetApi api, string sink
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id csharp/utils/model-generator/sink-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
from TargetApi api, string source
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id csharp/utils/model-generator/summary-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,9 +3,82 @@
|
||||
* and sink models of the Standard or a 3rd party library.
|
||||
*/
|
||||
|
||||
private import ModelGeneratorUtils
|
||||
private import CaptureModelsSpecific
|
||||
|
||||
class TargetApi = TargetApiSpecific;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
|
||||
*/
|
||||
private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::Content f |
|
||||
DataFlowPrivate::readStep(node1, f, node2) and
|
||||
if f instanceof DataFlow::FieldContent
|
||||
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
|
||||
else
|
||||
if f instanceof DataFlow::SyntheticFieldContent
|
||||
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
|
||||
else any()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
|
||||
DataFlowPrivate::containerContent(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if content `c` is either a field or synthetic field of a relevant type
|
||||
* or a container like content.
|
||||
*/
|
||||
private predicate isRelevantContent(DataFlow::Content c) {
|
||||
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
|
||||
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
|
||||
DataFlowPrivate::containerContent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model for `api` with `input`, `output` and `kind`.
|
||||
*/
|
||||
bindingset[input, output, kind]
|
||||
private string asSummaryModel(TargetApi api, string input, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ output + ";" //
|
||||
+ kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
private string asValueModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "value")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
private string asTaintModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "taint")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sink model for `api` with `input` and `kind`.
|
||||
*/
|
||||
bindingset[input, kind]
|
||||
private string asSinkModel(TargetApi api, string input, string kind) {
|
||||
result = asPartialModel(api) + input + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source model for `api` with `output` and `kind`.
|
||||
*/
|
||||
bindingset[output, kind]
|
||||
private string asSourceModel(TargetApi api, string output, string kind) {
|
||||
result = asPartialModel(api) + output + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
|
||||
@@ -4,10 +4,78 @@
|
||||
|
||||
import csharp
|
||||
private import semmle.code.csharp.dataflow.TaintTracking
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||
private import ModelGeneratorUtils
|
||||
private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
/**
|
||||
* Holds if it is relevant to generate models for `api`.
|
||||
*/
|
||||
private predicate isRelevantForModels(Callable api) {
|
||||
[api.(Modifiable), api.(Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||
not api instanceof Util::MainMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are relevant generating summary, source and sinks models for.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it the callables that can be called
|
||||
* from outside the library itself.
|
||||
*/
|
||||
class TargetApiSpecific extends DataFlowCallable {
|
||||
TargetApiSpecific() {
|
||||
this.fromSource() and
|
||||
isRelevantForModels(this)
|
||||
}
|
||||
}
|
||||
|
||||
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
|
||||
|
||||
/**
|
||||
* Holds for type `t` for fields that are relevant as an intermediate
|
||||
* read or write step in the data flow analysis.
|
||||
*/
|
||||
predicate isRelevantType(Type t) { not t instanceof Enum }
|
||||
|
||||
private string parameterAccess(Parameter p) {
|
||||
if isCollectionType(p.getType())
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
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 = "Argument[Qualifier]" and p instanceof DataFlowPrivate::InstanceParameterNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Parameter getParameter(DataFlowImplCommon::ReturnNodeExt node, ParameterPosition pos) {
|
||||
result = node.getEnclosingCallable().getParameter(pos.getPosition())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSV string represention of the the return node `node`.
|
||||
*/
|
||||
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
|
||||
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(ParameterPosition pos |
|
||||
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
||||
|
|
||||
result = parameterAccess(getParameter(node, pos))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = "Argument[Qualifier]"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
@@ -19,7 +87,9 @@ Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
|
||||
/**
|
||||
* Holds if `node` is an own instance access.
|
||||
*/
|
||||
predicate isOwnInstanceAccessNode(ReturnNode node) { node.asExpr() instanceof ThisAccess }
|
||||
predicate isOwnInstanceAccessNode(DataFlowPrivate::ReturnNode node) {
|
||||
node.asExpr() instanceof ThisAccess
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSV string representation of the qualifier.
|
||||
@@ -65,6 +135,6 @@ string asInputArgument(DataFlow::Node source) {
|
||||
result = "Argument[" + pos + "]"
|
||||
)
|
||||
or
|
||||
source.asExpr() instanceof FieldOrPropertyAccess and
|
||||
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
|
||||
result = qualifierString()
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import ModelGeneratorUtilsSpecific
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
|
||||
*/
|
||||
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::Content f |
|
||||
DataFlowPrivate::readStep(node1, f, node2) and
|
||||
if f instanceof DataFlow::FieldContent
|
||||
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
|
||||
else
|
||||
if f instanceof DataFlow::SyntheticFieldContent
|
||||
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
|
||||
else any()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
|
||||
DataFlowPrivate::containerContent(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if content `c` is either a field or synthetic field of a relevant type
|
||||
* or a container like content.
|
||||
*/
|
||||
predicate isRelevantContent(DataFlow::Content c) {
|
||||
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
|
||||
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
|
||||
DataFlowPrivate::containerContent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model for `api` with `input`, `output` and `kind`.
|
||||
*/
|
||||
bindingset[input, output, kind]
|
||||
string asSummaryModel(TargetApi api, string input, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ output + ";" //
|
||||
+ kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asValueModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "value")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asTaintModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "taint")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sink model for `api` with `input` and `kind`.
|
||||
*/
|
||||
bindingset[input, kind]
|
||||
string asSinkModel(TargetApi api, string input, string kind) {
|
||||
result = asPartialModel(api) + input + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source model for `api` with `output` and `kind`.
|
||||
*/
|
||||
bindingset[output, kind]
|
||||
string asSourceModel(TargetApi api, string output, string kind) {
|
||||
result = asPartialModel(api) + output + ";" + kind
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import csharp
|
||||
private import semmle.code.csharp.commons.Util as Util
|
||||
private import semmle.code.csharp.commons.Collections
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
|
||||
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
/**
|
||||
* Holds if it is relevant to generate models for `api`.
|
||||
*/
|
||||
predicate isRelevantForModels(Callable api) {
|
||||
[api.(Modifiable), api.(Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||
not api instanceof Util::MainMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of callables that are relevant generating summary, source and sinks models for.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it the callables that can be called
|
||||
* from outside the library itself.
|
||||
*/
|
||||
class TargetApi extends DataFlowCallable {
|
||||
TargetApi() {
|
||||
this.fromSource() and
|
||||
isRelevantForModels(this)
|
||||
}
|
||||
}
|
||||
|
||||
predicate asPartialModel = DataFlowPrivate::Csv::asPartialModel/1;
|
||||
|
||||
/**
|
||||
* Holds for type `t` for fields that are relevant as an intermediate
|
||||
* read or write step in the data flow analysis.
|
||||
*/
|
||||
predicate isRelevantType(Type t) { not t instanceof Enum }
|
||||
|
||||
private string parameterAccess(Parameter p) {
|
||||
if isCollectionType(p.getType())
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
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 = "Argument[Qualifier]" and p instanceof DataFlowPrivate::InstanceParameterNode
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Parameter getParameter(ReturnNodeExt node, ParameterPosition pos) {
|
||||
result = node.getEnclosingCallable().getParameter(pos.getPosition())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSV string represention of the the return node `node`.
|
||||
*/
|
||||
string returnNodeAsOutput(ReturnNodeExt node) {
|
||||
if node.getKind() instanceof ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(ParameterPosition pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
|
||||
result = parameterAccess(getParameter(node, pos))
|
||||
or
|
||||
pos.isThisParameter() and
|
||||
result = "Argument[Qualifier]"
|
||||
)
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id java/utils/model-generator/sink-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
from TargetApi api, string sink
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id java/utils/model-generator/sink-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
from TargetApi api, string source
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
* @id java/utils/model-generator/summary-models
|
||||
*/
|
||||
|
||||
private import internal.ModelGeneratorUtils
|
||||
private import internal.CaptureModels
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,9 +3,82 @@
|
||||
* and sink models of the Standard or a 3rd party library.
|
||||
*/
|
||||
|
||||
private import ModelGeneratorUtils
|
||||
private import CaptureModelsSpecific
|
||||
|
||||
class TargetApi = TargetApiSpecific;
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
|
||||
*/
|
||||
private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::Content f |
|
||||
DataFlowPrivate::readStep(node1, f, node2) and
|
||||
if f instanceof DataFlow::FieldContent
|
||||
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
|
||||
else
|
||||
if f instanceof DataFlow::SyntheticFieldContent
|
||||
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
|
||||
else any()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
|
||||
DataFlowPrivate::containerContent(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if content `c` is either a field or synthetic field of a relevant type
|
||||
* or a container like content.
|
||||
*/
|
||||
private predicate isRelevantContent(DataFlow::Content c) {
|
||||
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
|
||||
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
|
||||
DataFlowPrivate::containerContent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model for `api` with `input`, `output` and `kind`.
|
||||
*/
|
||||
bindingset[input, output, kind]
|
||||
private string asSummaryModel(TargetApi api, string input, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ output + ";" //
|
||||
+ kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
private string asValueModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "value")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
private string asTaintModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "taint")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sink model for `api` with `input` and `kind`.
|
||||
*/
|
||||
bindingset[input, kind]
|
||||
private string asSinkModel(TargetApi api, string input, string kind) {
|
||||
result = asPartialModel(api) + input + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source model for `api` with `output` and `kind`.
|
||||
*/
|
||||
bindingset[output, kind]
|
||||
private string asSourceModel(TargetApi api, string output, string kind) {
|
||||
result = asPartialModel(api) + output + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*/
|
||||
|
||||
@@ -3,13 +3,171 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.internal.DataFlowNodes
|
||||
private import semmle.code.java.dataflow.internal.DataFlowPrivate
|
||||
private import semmle.code.java.dataflow.InstanceAccess
|
||||
private import ModelGeneratorUtils
|
||||
private import semmle.code.java.dataflow.internal.ContainerFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
|
||||
import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
private Method superImpl(Method m) {
|
||||
result = m.getAnOverride() and
|
||||
not exists(result.getAnOverride()) and
|
||||
not m instanceof ToStringMethod
|
||||
}
|
||||
|
||||
private predicate isInTestFile(File file) {
|
||||
file.getAbsolutePath().matches("%src/test/%") or
|
||||
file.getAbsolutePath().matches("%/guava-tests/%") or
|
||||
file.getAbsolutePath().matches("%/guava-testlib/%")
|
||||
}
|
||||
|
||||
private predicate isJdkInternal(CompilationUnit cu) {
|
||||
cu.getPackage().getName().matches("org.graalvm%") or
|
||||
cu.getPackage().getName().matches("com.sun%") or
|
||||
cu.getPackage().getName().matches("javax.swing%") or
|
||||
cu.getPackage().getName().matches("java.awt%") or
|
||||
cu.getPackage().getName().matches("sun%") or
|
||||
cu.getPackage().getName().matches("jdk.%") or
|
||||
cu.getPackage().getName().matches("java2d.%") or
|
||||
cu.getPackage().getName().matches("build.tools.%") or
|
||||
cu.getPackage().getName().matches("propertiesparser.%") or
|
||||
cu.getPackage().getName().matches("org.jcp.%") or
|
||||
cu.getPackage().getName().matches("org.w3c.%") or
|
||||
cu.getPackage().getName().matches("org.ietf.jgss.%") or
|
||||
cu.getPackage().getName().matches("org.xml.sax%") or
|
||||
cu.getPackage().getName() = "compileproperties" or
|
||||
cu.getPackage().getName() = "netscape.javascript" or
|
||||
cu.getPackage().getName() = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is relevant to generate models for `api`.
|
||||
*/
|
||||
private predicate isRelevantForModels(Callable api) {
|
||||
not isInTestFile(api.getCompilationUnit().getFile()) and
|
||||
not isJdkInternal(api.getCompilationUnit()) and
|
||||
not api instanceof MainMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of Callables that are relevant for generating summary, source and sinks models for.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it the Callables that can be called
|
||||
* from outside the library itself.
|
||||
*/
|
||||
class TargetApiSpecific extends Callable {
|
||||
TargetApiSpecific() {
|
||||
this.isPublic() and
|
||||
this.fromSource() and
|
||||
(
|
||||
this.getDeclaringType().isPublic() or
|
||||
superImpl(this).getDeclaringType().isPublic()
|
||||
) and
|
||||
isRelevantForModels(this)
|
||||
}
|
||||
}
|
||||
|
||||
private string isExtensible(RefType ref) {
|
||||
if ref.isFinal() then result = "false" else result = "true"
|
||||
}
|
||||
|
||||
private string typeAsModel(RefType type) {
|
||||
result = type.getCompilationUnit().getPackage().getName() + ";" + type.nestedName()
|
||||
}
|
||||
|
||||
private RefType bestTypeForModel(TargetApiSpecific api) {
|
||||
if exists(superImpl(api))
|
||||
then superImpl(api).fromSource() and result = superImpl(api).getDeclaringType()
|
||||
else result = api.getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate type name for the model. Either the type
|
||||
* declaring the method or the supertype introducing the method.
|
||||
*/
|
||||
private string typeAsSummaryModel(TargetApiSpecific api) {
|
||||
result = typeAsModel(bestTypeForModel(api))
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the first 6 columns for CSV rows.
|
||||
*/
|
||||
string asPartialModel(TargetApiSpecific api) {
|
||||
result =
|
||||
typeAsSummaryModel(api) + ";" //
|
||||
+ isExtensible(bestTypeForModel(api)) + ";" //
|
||||
+ api.getName() + ";" //
|
||||
+ ExternalFlow::paramsString(api) + ";" //
|
||||
+ /* ext + */ ";" //
|
||||
}
|
||||
|
||||
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
|
||||
t.getName().regexpMatch("byte|char|Byte|Character")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for type `t` for fields that are relevant as an intermediate
|
||||
* read or write step in the data flow analysis.
|
||||
*/
|
||||
predicate isRelevantType(Type t) {
|
||||
not t instanceof TypeClass and
|
||||
not t instanceof EnumType and
|
||||
not t instanceof PrimitiveType and
|
||||
not t instanceof BoxedType and
|
||||
not t.(RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and
|
||||
not t.(RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and
|
||||
(
|
||||
not t.(Array).getElementType() instanceof PrimitiveType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
|
||||
) and
|
||||
(
|
||||
not t.(Array).getElementType() instanceof BoxedType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
|
||||
) and
|
||||
(
|
||||
not t.(CollectionType).getElementType() instanceof BoxedType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(CollectionType).getElementType())
|
||||
)
|
||||
}
|
||||
|
||||
private string parameterAccess(Parameter p) {
|
||||
if
|
||||
p.getType() instanceof Array and
|
||||
not isPrimitiveTypeUsedForBulkData(p.getType().(Array).getElementType())
|
||||
then result = "Argument[" + p.getPosition() + "].ArrayElement"
|
||||
else
|
||||
if p.getType() instanceof ContainerType
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
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 = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSV string represention of the the return node `node`.
|
||||
*/
|
||||
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
|
||||
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(int pos |
|
||||
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
|
||||
|
|
||||
result = parameterAccess(node.getEnclosingCallable().getParameter(pos))
|
||||
or
|
||||
result = "Argument[-1]" and pos = -1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import ModelGeneratorUtilsSpecific
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`.
|
||||
*/
|
||||
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(DataFlow::Content f |
|
||||
DataFlowPrivate::readStep(node1, f, node2) and
|
||||
if f instanceof DataFlow::FieldContent
|
||||
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
|
||||
else
|
||||
if f instanceof DataFlow::SyntheticFieldContent
|
||||
then isRelevantType(f.(DataFlow::SyntheticFieldContent).getField().getType())
|
||||
else any()
|
||||
)
|
||||
or
|
||||
exists(DataFlow::Content f | DataFlowPrivate::storeStep(node1, f, node2) |
|
||||
DataFlowPrivate::containerContent(f)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if content `c` is either a field or synthetic field of a relevant type
|
||||
* or a container like content.
|
||||
*/
|
||||
predicate isRelevantContent(DataFlow::Content c) {
|
||||
isRelevantType(c.(DataFlow::FieldContent).getField().getType()) or
|
||||
isRelevantType(c.(DataFlow::SyntheticFieldContent).getField().getType()) or
|
||||
DataFlowPrivate::containerContent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model for `api` with `input`, `output` and `kind`.
|
||||
*/
|
||||
bindingset[input, output, kind]
|
||||
string asSummaryModel(TargetApi api, string input, string output, string kind) {
|
||||
result =
|
||||
asPartialModel(api) + input + ";" //
|
||||
+ output + ";" //
|
||||
+ kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asValueModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "value")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asTaintModel(TargetApi api, string input, string output) {
|
||||
result = asSummaryModel(api, input, output, "taint")
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sink model for `api` with `input` and `kind`.
|
||||
*/
|
||||
bindingset[input, kind]
|
||||
string asSinkModel(TargetApi api, string input, string kind) {
|
||||
result = asPartialModel(api) + input + ";" + kind
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source model for `api` with `output` and `kind`.
|
||||
*/
|
||||
bindingset[output, kind]
|
||||
string asSourceModel(TargetApi api, string output, string kind) {
|
||||
result = asPartialModel(api) + output + ";" + kind
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.internal.ContainerFlow
|
||||
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
|
||||
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||
|
||||
private Method superImpl(Method m) {
|
||||
result = m.getAnOverride() and
|
||||
not exists(result.getAnOverride()) and
|
||||
not m instanceof ToStringMethod
|
||||
}
|
||||
|
||||
private predicate isInTestFile(File file) {
|
||||
file.getAbsolutePath().matches("%src/test/%") or
|
||||
file.getAbsolutePath().matches("%/guava-tests/%") or
|
||||
file.getAbsolutePath().matches("%/guava-testlib/%")
|
||||
}
|
||||
|
||||
private predicate isJdkInternal(CompilationUnit cu) {
|
||||
cu.getPackage().getName().matches("org.graalvm%") or
|
||||
cu.getPackage().getName().matches("com.sun%") or
|
||||
cu.getPackage().getName().matches("javax.swing%") or
|
||||
cu.getPackage().getName().matches("java.awt%") or
|
||||
cu.getPackage().getName().matches("sun%") or
|
||||
cu.getPackage().getName().matches("jdk.%") or
|
||||
cu.getPackage().getName().matches("java2d.%") or
|
||||
cu.getPackage().getName().matches("build.tools.%") or
|
||||
cu.getPackage().getName().matches("propertiesparser.%") or
|
||||
cu.getPackage().getName().matches("org.jcp.%") or
|
||||
cu.getPackage().getName().matches("org.w3c.%") or
|
||||
cu.getPackage().getName().matches("org.ietf.jgss.%") or
|
||||
cu.getPackage().getName().matches("org.xml.sax%") or
|
||||
cu.getPackage().getName() = "compileproperties" or
|
||||
cu.getPackage().getName() = "netscape.javascript" or
|
||||
cu.getPackage().getName() = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if it is relevant to generate models for `api`.
|
||||
*/
|
||||
predicate isRelevantForModels(Callable api) {
|
||||
not isInTestFile(api.getCompilationUnit().getFile()) and
|
||||
not isJdkInternal(api.getCompilationUnit()) and
|
||||
not api instanceof MainMethod
|
||||
}
|
||||
|
||||
/**
|
||||
* A class of Callables that are relevant for generating summary, source and sinks models for.
|
||||
*
|
||||
* In the Standard library and 3rd party libraries it the Callables that can be called
|
||||
* from outside the library itself.
|
||||
*/
|
||||
class TargetApi extends Callable {
|
||||
TargetApi() {
|
||||
this.isPublic() and
|
||||
this.fromSource() and
|
||||
(
|
||||
this.getDeclaringType().isPublic() or
|
||||
superImpl(this).getDeclaringType().isPublic()
|
||||
) and
|
||||
isRelevantForModels(this)
|
||||
}
|
||||
}
|
||||
|
||||
private string isExtensible(RefType ref) {
|
||||
if ref.isFinal() then result = "false" else result = "true"
|
||||
}
|
||||
|
||||
private string typeAsModel(RefType type) {
|
||||
result = type.getCompilationUnit().getPackage().getName() + ";" + type.nestedName()
|
||||
}
|
||||
|
||||
private RefType bestTypeForModel(TargetApi api) {
|
||||
if exists(superImpl(api))
|
||||
then superImpl(api).fromSource() and result = superImpl(api).getDeclaringType()
|
||||
else result = api.getDeclaringType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appropriate type name for the model. Either the type
|
||||
* declaring the method or the supertype introducing the method.
|
||||
*/
|
||||
private string typeAsSummaryModel(TargetApi api) { result = typeAsModel(bestTypeForModel(api)) }
|
||||
|
||||
/**
|
||||
* Computes the first 6 columns for CSV rows.
|
||||
*/
|
||||
string asPartialModel(TargetApi api) {
|
||||
result =
|
||||
typeAsSummaryModel(api) + ";" //
|
||||
+ isExtensible(bestTypeForModel(api)) + ";" //
|
||||
+ api.getName() + ";" //
|
||||
+ paramsString(api) + ";" //
|
||||
+ /* ext + */ ";" //
|
||||
}
|
||||
|
||||
private predicate isPrimitiveTypeUsedForBulkData(Type t) {
|
||||
t.getName().regexpMatch("byte|char|Byte|Character")
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for type `t` for fields that are relevant as an intermediate
|
||||
* read or write step in the data flow analysis.
|
||||
*/
|
||||
predicate isRelevantType(Type t) {
|
||||
not t instanceof TypeClass and
|
||||
not t instanceof EnumType and
|
||||
not t instanceof PrimitiveType and
|
||||
not t instanceof BoxedType and
|
||||
not t.(RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and
|
||||
not t.(RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and
|
||||
(
|
||||
not t.(Array).getElementType() instanceof PrimitiveType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
|
||||
) and
|
||||
(
|
||||
not t.(Array).getElementType() instanceof BoxedType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
|
||||
) and
|
||||
(
|
||||
not t.(CollectionType).getElementType() instanceof BoxedType or
|
||||
isPrimitiveTypeUsedForBulkData(t.(CollectionType).getElementType())
|
||||
)
|
||||
}
|
||||
|
||||
private string parameterAccess(Parameter p) {
|
||||
if
|
||||
p.getType() instanceof Array and
|
||||
not isPrimitiveTypeUsedForBulkData(p.getType().(Array).getElementType())
|
||||
then result = "Argument[" + p.getPosition() + "].ArrayElement"
|
||||
else
|
||||
if p.getType() instanceof ContainerType
|
||||
then result = "Argument[" + p.getPosition() + "].Element"
|
||||
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 = "Argument[-1]" and p instanceof DataFlow::InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the CSV string represention of the the return node `node`.
|
||||
*/
|
||||
string returnNodeAsOutput(ReturnNodeExt node) {
|
||||
if node.getKind() instanceof ValueReturnKind
|
||||
then result = "ReturnValue"
|
||||
else
|
||||
exists(int pos | pos = node.getKind().(ParamUpdateReturnKind).getPosition() |
|
||||
result = parameterAccess(node.getEnclosingCallable().getParameter(pos))
|
||||
or
|
||||
result = "Argument[-1]" and pos = -1
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user