mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #19382 from michaelnebel/shared/modelgenrefactor
Shared: Re-factor summary, source and sink model generators into separate modules.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = ContentSensitive::captureFlow(api, _)
|
where flow = ContentSensitive::captureFlow(api, _)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string noflow
|
from DataFlowSummaryTargetApi api, string noflow
|
||||||
where noflow = captureNeutral(api)
|
where noflow = captureNeutral(api)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
import Heuristic
|
import SinkModels
|
||||||
|
|
||||||
from DataFlowSinkTargetApi api, string sink
|
from DataFlowSinkTargetApi api, string sink
|
||||||
where sink = captureSink(api)
|
where sink = Heuristic::captureSink(api)
|
||||||
select sink order by sink
|
select sink order by sink
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
import Heuristic
|
import SourceModels
|
||||||
|
|
||||||
from DataFlowSourceTargetApi api, string source
|
from DataFlowSourceTargetApi api, string source
|
||||||
where source = captureSource(api)
|
where source = Heuristic::captureSource(api)
|
||||||
select source order by source
|
select source order by source
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = captureFlow(api, _)
|
where flow = captureFlow(api, _)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* Provides predicates related to capturing summary models of the Standard or a 3rd party library.
|
* Provides predicates related to capturing summary models of the Standard or a 3rd party library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import cpp
|
private import cpp as Cpp
|
||||||
private import semmle.code.cpp.ir.IR
|
private import semmle.code.cpp.ir.IR
|
||||||
private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
|
private import semmle.code.cpp.dataflow.ExternalFlow as ExternalFlow
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||||
@@ -10,113 +10,67 @@ private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific
|
|||||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||||
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||||
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
private import semmle.code.cpp.ir.dataflow.internal.TaintTrackingImplSpecific
|
||||||
private import semmle.code.cpp.dataflow.new.TaintTracking
|
private import semmle.code.cpp.dataflow.new.TaintTracking as Tt
|
||||||
|
private import semmle.code.cpp.dataflow.new.DataFlow as Df
|
||||||
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
||||||
|
|
||||||
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFlow> {
|
/**
|
||||||
|
* Holds if `f` is a "private" function.
|
||||||
|
*
|
||||||
|
* A "private" function does not contribute any models as it is assumed
|
||||||
|
* to be an implementation detail of some other "public" function for which
|
||||||
|
* we will generate a summary.
|
||||||
|
*/
|
||||||
|
private predicate isPrivateOrProtected(Cpp::Function f) {
|
||||||
|
f.getNamespace().getParentNamespace*().isAnonymous()
|
||||||
|
or
|
||||||
|
exists(Cpp::MemberFunction mf | mf = f |
|
||||||
|
mf.isPrivate()
|
||||||
|
or
|
||||||
|
mf.isProtected()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
f.isStatic()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isUninterestingForModels(Callable api) {
|
||||||
|
// Note: This also makes all global/static-local variables
|
||||||
|
// not relevant (which is good!)
|
||||||
|
not api.(Cpp::Function).hasDefinition()
|
||||||
|
or
|
||||||
|
isPrivateOrProtected(api)
|
||||||
|
or
|
||||||
|
api instanceof Cpp::Destructor
|
||||||
|
or
|
||||||
|
api = any(Cpp::LambdaExpression lambda).getLambdaFunction()
|
||||||
|
or
|
||||||
|
api.isFromUninstantiatedTemplate(_)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate relevant(Callable api) {
|
||||||
|
api.fromSource() and
|
||||||
|
not isUninterestingForModels(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Cpp::Location, CppDataFlow>
|
||||||
|
{
|
||||||
|
private module DataFlow = Df::DataFlow;
|
||||||
|
|
||||||
class Type = DataFlowPrivate::DataFlowType;
|
class Type = DataFlowPrivate::DataFlowType;
|
||||||
|
|
||||||
// Note: This also includes `this`
|
// Note: This also includes `this`
|
||||||
class Parameter = DataFlow::ParameterNode;
|
class Parameter = DataFlow::ParameterNode;
|
||||||
|
|
||||||
class Callable = Declaration;
|
class Callable = Cpp::Declaration;
|
||||||
|
|
||||||
class NodeExtended extends DataFlow::Node {
|
class NodeExtended extends DataFlow::Node {
|
||||||
Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingDeclaration() }
|
Callable getAsExprEnclosingCallable() { result = this.asExpr().getEnclosingDeclaration() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter asParameter(NodeExtended n) { result = n }
|
|
||||||
|
|
||||||
Callable getEnclosingCallable(NodeExtended n) {
|
Callable getEnclosingCallable(NodeExtended n) {
|
||||||
result = n.getEnclosingCallable().asSourceCallable()
|
result = n.getEnclosingCallable().asSourceCallable()
|
||||||
}
|
}
|
||||||
|
|
||||||
Callable getAsExprEnclosingCallable(NodeExtended n) {
|
|
||||||
result = n.asExpr().getEnclosingDeclaration()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets `api` if it is relevant. */
|
|
||||||
private Callable liftedImpl(Callable api) { result = api and relevant(api) }
|
|
||||||
|
|
||||||
private predicate hasManualSummaryModel(Callable api) {
|
|
||||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSourceModel(Callable api) {
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSinkModel(Callable api) {
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `f` is a "private" function.
|
|
||||||
*
|
|
||||||
* A "private" function does not contribute any models as it is assumed
|
|
||||||
* to be an implementation detail of some other "public" function for which
|
|
||||||
* we will generate a summary.
|
|
||||||
*/
|
|
||||||
private predicate isPrivateOrProtected(Function f) {
|
|
||||||
f.getNamespace().getParentNamespace*().isAnonymous()
|
|
||||||
or
|
|
||||||
exists(MemberFunction mf | mf = f |
|
|
||||||
mf.isPrivate()
|
|
||||||
or
|
|
||||||
mf.isProtected()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
f.isStatic()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate isUninterestingForModels(Callable api) {
|
|
||||||
// Note: This also makes all global/static-local variables
|
|
||||||
// not relevant (which is good!)
|
|
||||||
not api.(Function).hasDefinition()
|
|
||||||
or
|
|
||||||
isPrivateOrProtected(api)
|
|
||||||
or
|
|
||||||
api instanceof Destructor
|
|
||||||
or
|
|
||||||
api = any(LambdaExpression lambda).getLambdaFunction()
|
|
||||||
or
|
|
||||||
api.isFromUninstantiatedTemplate(_)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate relevant(Callable api) {
|
|
||||||
api.fromSource() and
|
|
||||||
not isUninterestingForModels(api)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SummaryTargetApi extends Callable {
|
|
||||||
private Callable lift;
|
|
||||||
|
|
||||||
SummaryTargetApi() {
|
|
||||||
lift = liftedImpl(this) and
|
|
||||||
not hasManualSummaryModel(lift)
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable lift() { result = lift }
|
|
||||||
|
|
||||||
predicate isRelevant() {
|
|
||||||
relevant(this) and
|
|
||||||
not hasManualSummaryModel(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SourceOrSinkTargetApi extends Callable {
|
|
||||||
SourceOrSinkTargetApi() { relevant(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SourceTargetApi() { not hasManualSourceModel(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class InstanceParameterNode extends DataFlow::ParameterNode {
|
class InstanceParameterNode extends DataFlow::ParameterNode {
|
||||||
InstanceParameterNode() {
|
InstanceParameterNode() {
|
||||||
DataFlowPrivate::nodeHasInstruction(this,
|
DataFlowPrivate::nodeHasInstruction(this,
|
||||||
@@ -124,7 +78,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate isFinalMemberFunction(MemberFunction mf) {
|
private predicate isFinalMemberFunction(Cpp::MemberFunction mf) {
|
||||||
mf.isFinal()
|
mf.isFinal()
|
||||||
or
|
or
|
||||||
mf.getDeclaringType().isFinal()
|
mf.getDeclaringType().isFinal()
|
||||||
@@ -146,12 +100,12 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
* - An uninstantiated template, or
|
* - An uninstantiated template, or
|
||||||
* - A declaration that is not from a template instantiation.
|
* - A declaration that is not from a template instantiation.
|
||||||
*/
|
*/
|
||||||
private string templateParams(Declaration template) {
|
private string templateParams(Cpp::Declaration template) {
|
||||||
exists(string params |
|
exists(string params |
|
||||||
params =
|
params =
|
||||||
concat(int i |
|
concat(int i |
|
||||||
|
|
|
|
||||||
template.getTemplateArgument(i).(TypeTemplateParameter).getName(), "," order by i
|
template.getTemplateArgument(i).(Cpp::TypeTemplateParameter).getName(), "," order by i
|
||||||
)
|
)
|
||||||
|
|
|
|
||||||
if params = "" then result = "" else result = "<" + params + ">"
|
if params = "" then result = "" else result = "<" + params + ">"
|
||||||
@@ -166,7 +120,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
* - An uninstantiated template, or
|
* - An uninstantiated template, or
|
||||||
* - A declaration that is not from a template instantiation.
|
* - A declaration that is not from a template instantiation.
|
||||||
*/
|
*/
|
||||||
private string params(Function functionTemplate) {
|
private string params(Cpp::Function functionTemplate) {
|
||||||
exists(string params |
|
exists(string params |
|
||||||
params =
|
params =
|
||||||
concat(int i |
|
concat(int i |
|
||||||
@@ -193,7 +147,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
Callable callable, string namespace, string type, string name, string params
|
Callable callable, string namespace, string type, string name, string params
|
||||||
) {
|
) {
|
||||||
exists(
|
exists(
|
||||||
Function functionTemplate, string typeWithoutTemplateArgs, string nameWithoutTemplateArgs
|
Cpp::Function functionTemplate, string typeWithoutTemplateArgs, string nameWithoutTemplateArgs
|
||||||
|
|
|
|
||||||
functionTemplate = ExternalFlow::getFullyTemplatedFunction(callable) and
|
functionTemplate = ExternalFlow::getFullyTemplatedFunction(callable) and
|
||||||
functionTemplate.hasQualifiedName(namespace, typeWithoutTemplateArgs, nameWithoutTemplateArgs) and
|
functionTemplate.hasQualifiedName(namespace, typeWithoutTemplateArgs, nameWithoutTemplateArgs) and
|
||||||
@@ -201,7 +155,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
name = nameWithoutTemplateArgs + templateParams(functionTemplate) and
|
name = nameWithoutTemplateArgs + templateParams(functionTemplate) and
|
||||||
params = params(functionTemplate)
|
params = params(functionTemplate)
|
||||||
|
|
|
|
||||||
exists(Class classTemplate |
|
exists(Cpp::Class classTemplate |
|
||||||
classTemplate = functionTemplate.getDeclaringType() and
|
classTemplate = functionTemplate.getDeclaringType() and
|
||||||
type = typeWithoutTemplateArgs + templateParams(classTemplate)
|
type = typeWithoutTemplateArgs + templateParams(classTemplate)
|
||||||
)
|
)
|
||||||
@@ -263,10 +217,10 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
|
|
||||||
/** Holds if this instance access is to an enclosing instance of type `t`. */
|
/** Holds if this instance access is to an enclosing instance of type `t`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate isEnclosingInstanceAccess(DataFlowPrivate::ReturnNode n, Class t) {
|
private predicate isEnclosingInstanceAccess(DataFlowPrivate::ReturnNode n, Cpp::Class t) {
|
||||||
n.getKind().isIndirectReturn(-1) and
|
n.getKind().isIndirectReturn(-1) and
|
||||||
t = n.getType().stripType() and
|
t = n.getType().stripType() and
|
||||||
t != n.getEnclosingCallable().asSourceCallable().(Function).getDeclaringType()
|
t != n.getEnclosingCallable().asSourceCallable().(Cpp::Function).getDeclaringType()
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -275,26 +229,6 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
not isEnclosingInstanceAccess(node, _)
|
not isEnclosingInstanceAccess(node, _)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
predicate apiSource(DataFlow::Node source) {
|
|
||||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
|
|
||||||
or
|
|
||||||
source instanceof DataFlow::ParameterNode
|
|
||||||
}
|
|
||||||
|
|
||||||
string getInputArgument(DataFlow::Node source) {
|
|
||||||
exists(DataFlowPrivate::Position pos, int argumentIndex, int indirectionIndex |
|
|
||||||
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
|
|
||||||
argumentIndex = pos.getArgumentIndex() and
|
|
||||||
indirectionIndex = pos.getIndirectionIndex() and
|
|
||||||
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
|
|
||||||
)
|
|
||||||
or
|
|
||||||
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
|
|
||||||
result = qualifierString()
|
|
||||||
}
|
|
||||||
|
|
||||||
DataFlowPrivate::ParameterPosition getReturnKindParamPosition(DataFlowPrivate::ReturnKind k) {
|
DataFlowPrivate::ParameterPosition getReturnKindParamPosition(DataFlowPrivate::ReturnKind k) {
|
||||||
exists(int argumentIndex, int indirectionIndex |
|
exists(int argumentIndex, int indirectionIndex |
|
||||||
k.isIndirectReturn(argumentIndex) and
|
k.isIndirectReturn(argumentIndex) and
|
||||||
@@ -314,18 +248,71 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() }
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSourceKind(string kind) { any() }
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSinkKind(string kind) { any() }
|
|
||||||
|
|
||||||
predicate containerContent(DataFlow::ContentSet cs) { cs instanceof DataFlow::ElementContent }
|
predicate containerContent(DataFlow::ContentSet cs) { cs instanceof DataFlow::ElementContent }
|
||||||
|
|
||||||
|
string partialModelRow(Callable api, int i) {
|
||||||
|
i = 0 and qualifiedName(api, result, _, _, _) // namespace
|
||||||
|
or
|
||||||
|
i = 1 and qualifiedName(api, _, result, _, _) // type
|
||||||
|
or
|
||||||
|
i = 2 and result = isExtensible(api) // extensible
|
||||||
|
or
|
||||||
|
i = 3 and qualifiedName(api, _, _, result, _) // name
|
||||||
|
or
|
||||||
|
i = 4 and qualifiedName(api, _, _, _, result) // parameters
|
||||||
|
or
|
||||||
|
i = 5 and result = "" and exists(api) // ext
|
||||||
|
}
|
||||||
|
|
||||||
|
string partialNeutralModelRow(Callable api, int i) {
|
||||||
|
i = 0 and qualifiedName(api, result, _, _, _) // namespace
|
||||||
|
or
|
||||||
|
i = 1 and qualifiedName(api, _, result, _, _) // type
|
||||||
|
or
|
||||||
|
i = 2 and qualifiedName(api, _, _, result, _) // name
|
||||||
|
or
|
||||||
|
i = 3 and qualifiedName(api, _, _, _, result) // parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private import ModelGeneratorCommonInput
|
||||||
|
private import MakeModelGeneratorFactory<Cpp::Location, CppDataFlow, CppTaintTracking, ModelGeneratorCommonInput>
|
||||||
|
|
||||||
|
private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
|
||||||
|
private module DataFlow = Df::DataFlow;
|
||||||
|
|
||||||
|
Parameter asParameter(NodeExtended n) { result = n }
|
||||||
|
|
||||||
|
Callable getAsExprEnclosingCallable(NodeExtended n) {
|
||||||
|
result = n.asExpr().getEnclosingDeclaration()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasManualSummaryModel(Callable api) {
|
||||||
|
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets `api` if it is relevant. */
|
||||||
|
private Callable liftedImpl(Callable api) { result = api and relevant(api) }
|
||||||
|
|
||||||
|
class SummaryTargetApi extends Callable {
|
||||||
|
private Callable lift;
|
||||||
|
|
||||||
|
SummaryTargetApi() {
|
||||||
|
lift = liftedImpl(this) and
|
||||||
|
not hasManualSummaryModel(lift)
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable lift() { result = lift }
|
||||||
|
|
||||||
|
predicate isRelevant() {
|
||||||
|
relevant(this) and
|
||||||
|
not hasManualSummaryModel(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
|
Tt::TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
|
||||||
not exists(DataFlow::Content f |
|
not exists(DataFlow::Content f |
|
||||||
DataFlowPrivate::readStep(node1, f, node2) and containerContent(f)
|
DataFlowPrivate::readStep(node1, f, node2) and containerContent(f)
|
||||||
)
|
)
|
||||||
@@ -341,7 +328,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
predicate isCallback(DataFlow::ContentSet c) { none() }
|
predicate isCallback(DataFlow::ContentSet c) { none() }
|
||||||
|
|
||||||
string getSyntheticName(DataFlow::ContentSet c) {
|
string getSyntheticName(DataFlow::ContentSet c) {
|
||||||
exists(Field f |
|
exists(Cpp::Field f |
|
||||||
not f.isPublic() and
|
not f.isPublic() and
|
||||||
f = c.(DataFlow::FieldContent).getField() and
|
f = c.(DataFlow::FieldContent).getField() and
|
||||||
result = f.getName()
|
result = f.getName()
|
||||||
@@ -373,40 +360,52 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CppDataFl
|
|||||||
result = "Element[" + ec.getIndirectionIndex() + "]"
|
result = "Element[" + ec.getIndirectionIndex() + "]"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
predicate isUninterestingForDataFlowModels(Callable api) { none() }
|
private module SourceModelGeneratorInput implements SourceModelGeneratorInputSig {
|
||||||
|
private predicate hasManualSourceModel(Callable api) {
|
||||||
predicate isUninterestingForHeuristicDataFlowModels(Callable api) {
|
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
||||||
isUninterestingForDataFlowModels(api)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string partialModelRow(Callable api, int i) {
|
class SourceTargetApi extends Callable {
|
||||||
i = 0 and qualifiedName(api, result, _, _, _) // namespace
|
SourceTargetApi() { relevant(this) and not hasManualSourceModel(this) }
|
||||||
or
|
|
||||||
i = 1 and qualifiedName(api, _, result, _, _) // type
|
|
||||||
or
|
|
||||||
i = 2 and result = isExtensible(api) // extensible
|
|
||||||
or
|
|
||||||
i = 3 and qualifiedName(api, _, _, result, _) // name
|
|
||||||
or
|
|
||||||
i = 4 and qualifiedName(api, _, _, _, result) // parameters
|
|
||||||
or
|
|
||||||
i = 5 and result = "" and exists(api) // ext
|
|
||||||
}
|
|
||||||
|
|
||||||
string partialNeutralModelRow(Callable api, int i) {
|
|
||||||
i = 0 and qualifiedName(api, result, _, _, _) // namespace
|
|
||||||
or
|
|
||||||
i = 1 and qualifiedName(api, _, result, _, _) // type
|
|
||||||
or
|
|
||||||
i = 2 and qualifiedName(api, _, _, result, _) // name
|
|
||||||
or
|
|
||||||
i = 3 and qualifiedName(api, _, _, _, result) // parameters
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate sourceNode = ExternalFlow::sourceNode/2;
|
predicate sourceNode = ExternalFlow::sourceNode/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||||
|
private module DataFlow = Df::DataFlow;
|
||||||
|
|
||||||
|
private predicate hasManualSinkModel(Callable api) {
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
||||||
|
}
|
||||||
|
|
||||||
|
class SinkTargetApi extends Callable {
|
||||||
|
SinkTargetApi() { relevant(this) and not hasManualSinkModel(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate apiSource(DataFlow::Node source) {
|
||||||
|
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1)
|
||||||
|
or
|
||||||
|
source instanceof DataFlow::ParameterNode
|
||||||
|
}
|
||||||
|
|
||||||
|
string getInputArgument(DataFlow::Node source) {
|
||||||
|
exists(DataFlowPrivate::Position pos, int argumentIndex, int indirectionIndex |
|
||||||
|
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
|
||||||
|
argumentIndex = pos.getArgumentIndex() and
|
||||||
|
indirectionIndex = pos.getIndirectionIndex() and
|
||||||
|
result = "Argument[" + DataFlow::repeatStars(indirectionIndex) + argumentIndex + "]"
|
||||||
|
)
|
||||||
|
or
|
||||||
|
DataFlowPrivate::nodeHasOperand(source, any(DataFlow::FieldAddress fa), 1) and
|
||||||
|
result = qualifierString()
|
||||||
|
}
|
||||||
|
|
||||||
predicate sinkNode = ExternalFlow::sinkNode/2;
|
predicate sinkNode = ExternalFlow::sinkNode/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
import MakeModelGenerator<Location, CppDataFlow, CppTaintTracking, ModelGeneratorInput>
|
import MakeSummaryModelGenerator<SummaryModelGeneratorInput> as SummaryModels
|
||||||
|
import MakeSourceModelGenerator<SourceModelGeneratorInput> as SourceModels
|
||||||
|
import MakeSinkModelGenerator<SinkModelGeneratorInput> as SinkModels
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
private import cpp as Cpp
|
private import cpp as Cpp
|
||||||
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
|
||||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||||
class Callable = Cpp::Declaration;
|
class Callable = Cpp::Declaration;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import InlineModelsAsDataTest
|
import InlineModelsAsDataTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import cpp
|
import cpp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import InlineModelsAsDataTest
|
import InlineModelsAsDataTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = ContentSensitive::captureFlow(api, _)
|
where flow = ContentSensitive::captureFlow(api, _)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string noflow
|
from DataFlowSummaryTargetApi api, string noflow
|
||||||
where noflow = captureNeutral(api)
|
where noflow = captureNeutral(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
|
|
||||||
from DataFlowSinkTargetApi api, string sink
|
from DataFlowSinkTargetApi api, string sink
|
||||||
where sink = Heuristic::captureSink(api)
|
where sink = Heuristic::captureSink(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
|
|
||||||
from DataFlowSourceTargetApi api, string source
|
from DataFlowSourceTargetApi api, string source
|
||||||
where source = Heuristic::captureSource(api)
|
where source = Heuristic::captureSource(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = captureFlow(api, _)
|
where flow = captureFlow(api, _)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import PartialFlow::PartialPathGraph
|
import PartialFlow::PartialPathGraph
|
||||||
|
|
||||||
int explorationLimit() { result = 3 }
|
int explorationLimit() { result = 3 }
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import Heuristic
|
import Heuristic
|
||||||
import PropagateFlow::PathGraph
|
import PropagateFlow::PathGraph
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,41 @@ private import semmle.code.csharp.frameworks.System
|
|||||||
private import semmle.code.csharp.Location
|
private import semmle.code.csharp.Location
|
||||||
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
||||||
|
|
||||||
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDataFlow> {
|
private predicate irrelevantAccessor(CS::Accessor a) {
|
||||||
|
a.getDeclaration().(CS::Property).isReadWrite()
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isUninterestingForModels(Callable api) {
|
||||||
|
api.getDeclaringType().getNamespace().getFullName() = ""
|
||||||
|
or
|
||||||
|
api instanceof CS::ConversionOperator
|
||||||
|
or
|
||||||
|
api instanceof Util::MainMethod
|
||||||
|
or
|
||||||
|
api instanceof CS::Destructor
|
||||||
|
or
|
||||||
|
api instanceof CS::AnonymousFunctionExpr
|
||||||
|
or
|
||||||
|
api.(CS::Constructor).isParameterless()
|
||||||
|
or
|
||||||
|
exists(Type decl | decl = api.getDeclaringType() |
|
||||||
|
decl instanceof SystemObjectClass or
|
||||||
|
decl instanceof SystemValueTypeClass
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Disregard properties that have both a get and a set accessor,
|
||||||
|
// which implicitly means auto implemented properties.
|
||||||
|
irrelevantAccessor(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate relevant(Callable api) {
|
||||||
|
[api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||||
|
api.fromSource() and
|
||||||
|
api.isUnboundDeclaration() and
|
||||||
|
not isUninterestingForModels(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Location, CsharpDataFlow> {
|
||||||
class Type = CS::Type;
|
class Type = CS::Type;
|
||||||
|
|
||||||
class Parameter = CS::Parameter;
|
class Parameter = CS::Parameter;
|
||||||
@@ -24,127 +58,8 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
|
|||||||
|
|
||||||
class NodeExtended = CS::DataFlow::Node;
|
class NodeExtended = CS::DataFlow::Node;
|
||||||
|
|
||||||
Callable getAsExprEnclosingCallable(NodeExtended node) {
|
|
||||||
result = node.asExpr().getEnclosingCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable getEnclosingCallable(NodeExtended node) { result = node.getEnclosingCallable() }
|
Callable getEnclosingCallable(NodeExtended node) { result = node.getEnclosingCallable() }
|
||||||
|
|
||||||
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if any of the parameters of `api` are `System.Func<>`.
|
|
||||||
*/
|
|
||||||
private predicate isHigherOrder(Callable api) {
|
|
||||||
exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() |
|
|
||||||
t instanceof SystemLinqExpressions::DelegateExtType
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate irrelevantAccessor(CS::Accessor a) {
|
|
||||||
a.getDeclaration().(CS::Property).isReadWrite()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate isUninterestingForModels(Callable api) {
|
|
||||||
api.getDeclaringType().getNamespace().getFullName() = ""
|
|
||||||
or
|
|
||||||
api instanceof CS::ConversionOperator
|
|
||||||
or
|
|
||||||
api instanceof Util::MainMethod
|
|
||||||
or
|
|
||||||
api instanceof CS::Destructor
|
|
||||||
or
|
|
||||||
api instanceof CS::AnonymousFunctionExpr
|
|
||||||
or
|
|
||||||
api.(CS::Constructor).isParameterless()
|
|
||||||
or
|
|
||||||
exists(Type decl | decl = api.getDeclaringType() |
|
|
||||||
decl instanceof SystemObjectClass or
|
|
||||||
decl instanceof SystemValueTypeClass
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// Disregard properties that have both a get and a set accessor,
|
|
||||||
// which implicitly means auto implemented properties.
|
|
||||||
irrelevantAccessor(api)
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate relevant(Callable api) {
|
|
||||||
[api.(CS::Modifiable), api.(CS::Accessor).getDeclaration()].isEffectivelyPublic() and
|
|
||||||
api.fromSource() and
|
|
||||||
api.isUnboundDeclaration() and
|
|
||||||
not isUninterestingForModels(api)
|
|
||||||
}
|
|
||||||
|
|
||||||
private Callable getARelevantOverrideeOrImplementee(Overridable m) {
|
|
||||||
m.overridesOrImplements(result) and relevant(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the super implementation of `api` if it is relevant.
|
|
||||||
* If such a super implementation does not exist, returns `api` if it is relevant.
|
|
||||||
*/
|
|
||||||
private Callable liftedImpl(Callable api) {
|
|
||||||
(
|
|
||||||
result = getARelevantOverrideeOrImplementee(api)
|
|
||||||
or
|
|
||||||
result = api and relevant(api)
|
|
||||||
) and
|
|
||||||
not exists(getARelevantOverrideeOrImplementee(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSummaryModel(Callable api) {
|
|
||||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSourceModel(Callable api) {
|
|
||||||
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSinkModel(Callable api) {
|
|
||||||
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isUninterestingForDataFlowModels(Callable api) { none() }
|
|
||||||
|
|
||||||
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { isHigherOrder(api) }
|
|
||||||
|
|
||||||
class SourceOrSinkTargetApi extends Callable {
|
|
||||||
SourceOrSinkTargetApi() { relevant(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SourceTargetApi() {
|
|
||||||
not hasManualSourceModel(this) and
|
|
||||||
// Do not generate source models for overridable callables
|
|
||||||
// as virtual dispatch implies that too many methods
|
|
||||||
// will be considered sources.
|
|
||||||
not this.(Overridable).overridesOrImplements(_)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SummaryTargetApi extends Callable {
|
|
||||||
private Callable lift;
|
|
||||||
|
|
||||||
SummaryTargetApi() {
|
|
||||||
lift = liftedImpl(this) and
|
|
||||||
not hasManualSummaryModel(lift)
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable lift() { result = lift }
|
|
||||||
|
|
||||||
predicate isRelevant() {
|
|
||||||
relevant(this) and
|
|
||||||
not hasManualSummaryModel(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `t` is a type that is generally used for bulk data in collection types.
|
* Holds if `t` is a type that is generally used for bulk data in collection types.
|
||||||
* Eg. char[] is roughly equivalent to string and thus a highly
|
* Eg. char[] is roughly equivalent to string and thus a highly
|
||||||
@@ -205,6 +120,8 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
||||||
|
|
||||||
string qualifierString() { result = "Argument[this]" }
|
string qualifierString() { result = "Argument[this]" }
|
||||||
|
|
||||||
string parameterAccess(CS::Parameter p) {
|
string parameterAccess(CS::Parameter p) {
|
||||||
@@ -215,8 +132,6 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
|
|||||||
|
|
||||||
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
string parameterContentAccess(CS::Parameter p) { result = "Argument[" + p.getPosition() + "]" }
|
||||||
|
|
||||||
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
|
|
||||||
|
|
||||||
private signature string parameterAccessSig(Parameter p);
|
private signature string parameterAccessSig(Parameter p);
|
||||||
|
|
||||||
private module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
|
private module ParamReturnNodeAsOutput<parameterAccessSig/1 getParamAccess> {
|
||||||
@@ -251,63 +166,92 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
|
|||||||
node.asExpr() instanceof CS::ThisAccess
|
node.asExpr() instanceof CS::ThisAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate isRelevantMemberAccess(DataFlow::Node node) {
|
|
||||||
exists(CS::MemberAccess access | access = node.asExpr() |
|
|
||||||
access.hasThisQualifier() and
|
|
||||||
access.getTarget().isEffectivelyPublic() and
|
|
||||||
(
|
|
||||||
access instanceof CS::FieldAccess
|
|
||||||
or
|
|
||||||
access.getTarget().(CS::Property).getSetter().isPublic()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
predicate apiSource(DataFlow::Node source) {
|
|
||||||
isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
|
|
||||||
exists(DataFlowCall call |
|
|
||||||
dc1 = call.getEnclosingCallable() and
|
|
||||||
dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[dc1, dc2]
|
|
||||||
private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) =
|
|
||||||
fastTC(uniquelyCalls/2)(dc1, dc2)
|
|
||||||
|
|
||||||
bindingset[sourceEnclosing, api]
|
|
||||||
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) {
|
|
||||||
not exists(DataFlowCallable dc1, DataFlowCallable dc2 |
|
|
||||||
uniquelyCallsPlus(dc1, dc2) or dc1 = dc2
|
|
||||||
|
|
|
||||||
dc1.getUnderlyingCallable() = api and
|
|
||||||
dc2.getUnderlyingCallable() = sourceEnclosing
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
string getInputArgument(DataFlow::Node source) {
|
|
||||||
exists(int pos |
|
|
||||||
pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and
|
|
||||||
result = "Argument[" + pos + "]"
|
|
||||||
)
|
|
||||||
or
|
|
||||||
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
|
|
||||||
result = qualifierString()
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSinkKind(string kind) { any() }
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSourceKind(string kind) { any() }
|
|
||||||
|
|
||||||
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
|
predicate containerContent(DataFlow::ContentSet c) { c.isElement() }
|
||||||
|
|
||||||
|
string partialModelRow(Callable api, int i) {
|
||||||
|
i = 0 and ExternalFlow::partialModel(api, result, _, _, _, _) // package
|
||||||
|
or
|
||||||
|
i = 1 and ExternalFlow::partialModel(api, _, result, _, _, _) // type
|
||||||
|
or
|
||||||
|
i = 2 and ExternalFlow::partialModel(api, _, _, result, _, _) // extensible
|
||||||
|
or
|
||||||
|
i = 3 and ExternalFlow::partialModel(api, _, _, _, result, _) // name
|
||||||
|
or
|
||||||
|
i = 4 and ExternalFlow::partialModel(api, _, _, _, _, result) // parameters
|
||||||
|
or
|
||||||
|
i = 5 and result = "" and exists(api) // ext
|
||||||
|
}
|
||||||
|
|
||||||
|
string partialNeutralModelRow(Callable api, int i) {
|
||||||
|
i = 0 and result = partialModelRow(api, 0) // package
|
||||||
|
or
|
||||||
|
i = 1 and result = partialModelRow(api, 1) // type
|
||||||
|
or
|
||||||
|
i = 2 and result = partialModelRow(api, 3) // name
|
||||||
|
or
|
||||||
|
i = 3 and result = partialModelRow(api, 4) // parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private import ModelGeneratorCommonInput
|
||||||
|
private import MakeModelGeneratorFactory<Location, CsharpDataFlow, CsharpTaintTracking, ModelGeneratorCommonInput>
|
||||||
|
|
||||||
|
module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
|
||||||
|
Callable getAsExprEnclosingCallable(NodeExtended node) {
|
||||||
|
result = node.asExpr().getEnclosingCallable()
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if any of the parameters of `api` are `System.Func<>`.
|
||||||
|
*/
|
||||||
|
private predicate isHigherOrder(Callable api) {
|
||||||
|
exists(Type t | t = api.getAParameter().getType().getUnboundDeclaration() |
|
||||||
|
t instanceof SystemLinqExpressions::DelegateExtType
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private Callable getARelevantOverrideeOrImplementee(Overridable m) {
|
||||||
|
m.overridesOrImplements(result) and relevant(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the super implementation of `api` if it is relevant.
|
||||||
|
* If such a super implementation does not exist, returns `api` if it is relevant.
|
||||||
|
*/
|
||||||
|
private Callable liftedImpl(Callable api) {
|
||||||
|
(
|
||||||
|
result = getARelevantOverrideeOrImplementee(api)
|
||||||
|
or
|
||||||
|
result = api and relevant(api)
|
||||||
|
) and
|
||||||
|
not exists(getARelevantOverrideeOrImplementee(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasManualSummaryModel(Callable api) {
|
||||||
|
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { isHigherOrder(api) }
|
||||||
|
|
||||||
|
class SummaryTargetApi extends Callable {
|
||||||
|
private Callable lift;
|
||||||
|
|
||||||
|
SummaryTargetApi() {
|
||||||
|
lift = liftedImpl(this) and
|
||||||
|
not hasManualSummaryModel(lift)
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable lift() { result = lift }
|
||||||
|
|
||||||
|
predicate isRelevant() {
|
||||||
|
relevant(this) and
|
||||||
|
not hasManualSummaryModel(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||||
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
|
TaintTrackingPrivate::defaultAdditionalTaintStep(nodeFrom, nodeTo, _) and
|
||||||
not nodeTo.asExpr() instanceof CS::ElementAccess and
|
not nodeTo.asExpr() instanceof CS::ElementAccess and
|
||||||
@@ -370,34 +314,88 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, CsharpDat
|
|||||||
or
|
or
|
||||||
c.isDelegateCallReturn() and result = "ReturnValue"
|
c.isDelegateCallReturn() and result = "ReturnValue"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string partialModelRow(Callable api, int i) {
|
private module SourceModelGeneratorInput implements SourceModelGeneratorInputSig {
|
||||||
i = 0 and ExternalFlow::partialModel(api, result, _, _, _, _) // package
|
private predicate hasManualSourceModel(Callable api) {
|
||||||
or
|
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
||||||
i = 1 and ExternalFlow::partialModel(api, _, result, _, _, _) // type
|
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel())
|
||||||
or
|
|
||||||
i = 2 and ExternalFlow::partialModel(api, _, _, result, _, _) // extensible
|
|
||||||
or
|
|
||||||
i = 3 and ExternalFlow::partialModel(api, _, _, _, result, _) // name
|
|
||||||
or
|
|
||||||
i = 4 and ExternalFlow::partialModel(api, _, _, _, _, result) // parameters
|
|
||||||
or
|
|
||||||
i = 5 and result = "" and exists(api) // ext
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string partialNeutralModelRow(Callable api, int i) {
|
class SourceTargetApi extends Callable {
|
||||||
i = 0 and result = partialModelRow(api, 0) // package
|
SourceTargetApi() {
|
||||||
or
|
relevant(this) and
|
||||||
i = 1 and result = partialModelRow(api, 1) // type
|
not hasManualSourceModel(this) and
|
||||||
or
|
// Do not generate source models for overridable callables
|
||||||
i = 2 and result = partialModelRow(api, 3) // name
|
// as virtual dispatch implies that too many methods
|
||||||
or
|
// will be considered sources.
|
||||||
i = 3 and result = partialModelRow(api, 4) // parameters
|
not this.(Overridable).overridesOrImplements(_)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate uniquelyCalls(DataFlowCallable dc1, DataFlowCallable dc2) {
|
||||||
|
exists(DataFlowCall call |
|
||||||
|
dc1 = call.getEnclosingCallable() and
|
||||||
|
dc2 = unique(DataFlowCallable dc0 | dc0 = viableCallable(call) | dc0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[dc1, dc2]
|
||||||
|
private predicate uniquelyCallsPlus(DataFlowCallable dc1, DataFlowCallable dc2) =
|
||||||
|
fastTC(uniquelyCalls/2)(dc1, dc2)
|
||||||
|
|
||||||
|
bindingset[sourceEnclosing, api]
|
||||||
|
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) {
|
||||||
|
not exists(DataFlowCallable dc1, DataFlowCallable dc2 |
|
||||||
|
uniquelyCallsPlus(dc1, dc2) or dc1 = dc2
|
||||||
|
|
|
||||||
|
dc1.getUnderlyingCallable() = api and
|
||||||
|
dc2.getUnderlyingCallable() = sourceEnclosing
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate sourceNode = ExternalFlow::sourceNode/2;
|
predicate sourceNode = ExternalFlow::sourceNode/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||||
|
private predicate hasManualSinkModel(Callable api) {
|
||||||
|
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel())
|
||||||
|
}
|
||||||
|
|
||||||
|
class SinkTargetApi extends Callable {
|
||||||
|
SinkTargetApi() { relevant(this) and not hasManualSinkModel(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate isRelevantMemberAccess(DataFlow::Node node) {
|
||||||
|
exists(CS::MemberAccess access | access = node.asExpr() |
|
||||||
|
access.hasThisQualifier() and
|
||||||
|
access.getTarget().isEffectivelyPublic() and
|
||||||
|
(
|
||||||
|
access instanceof CS::FieldAccess
|
||||||
|
or
|
||||||
|
access.getTarget().(CS::Property).getSetter().isPublic()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate apiSource(DataFlow::Node source) {
|
||||||
|
isRelevantMemberAccess(source) or source instanceof DataFlow::ParameterNode
|
||||||
|
}
|
||||||
|
|
||||||
|
string getInputArgument(DataFlow::Node source) {
|
||||||
|
exists(int pos |
|
||||||
|
pos = source.(DataFlow::ParameterNode).getParameter().getPosition() and
|
||||||
|
result = "Argument[" + pos + "]"
|
||||||
|
)
|
||||||
|
or
|
||||||
|
source.asExpr() instanceof DataFlowPrivate::FieldOrPropertyAccess and
|
||||||
|
result = qualifierString()
|
||||||
|
}
|
||||||
|
|
||||||
predicate sinkNode = ExternalFlow::sinkNode/2;
|
predicate sinkNode = ExternalFlow::sinkNode/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
import MakeModelGenerator<Location, CsharpDataFlow, CsharpTaintTracking, ModelGeneratorInput>
|
import MakeSummaryModelGenerator<SummaryModelGeneratorInput> as SummaryModels
|
||||||
|
import MakeSourceModelGenerator<SourceModelGeneratorInput> as SourceModels
|
||||||
|
import MakeSinkModelGenerator<SinkModelGeneratorInput> as SinkModels
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
private import csharp as CS
|
private import csharp as CS
|
||||||
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
|
||||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||||
class Callable = CS::Callable;
|
class Callable = CS::Callable;
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ private import csharp
|
|||||||
private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections
|
private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||||
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
private import semmle.code.csharp.frameworks.system.linq.Expressions
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
private import CaptureModels::SummaryModelGeneratorInput as SummaryModelGeneratorInput
|
||||||
private import CaptureModelsPrinting
|
private import CaptureModelsPrinting
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,21 +178,19 @@ private predicate output(Callable callable, TypeParameter tp, string output) {
|
|||||||
delegateSink(callable, tp, output)
|
delegateSink(callable, tp, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
private module ModelPrintingInput implements ModelPrintingSig {
|
private module ModelPrintingInput implements ModelPrintingSummarySig {
|
||||||
class SummaryApi = TypeBasedFlowTargetApi;
|
class SummaryApi = TypeBasedFlowTargetApi;
|
||||||
|
|
||||||
class SourceOrSinkApi = TypeBasedFlowTargetApi;
|
|
||||||
|
|
||||||
string getProvenance() { result = "tb-generated" }
|
string getProvenance() { result = "tb-generated" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Printing = ModelPrinting<ModelPrintingInput>;
|
private module Printing = ModelPrintingSummary<ModelPrintingInput>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class of callables that are relevant generating summaries for based
|
* A class of callables that are relevant generating summaries for based
|
||||||
* on the Theorems for Free approach.
|
* on the Theorems for Free approach.
|
||||||
*/
|
*/
|
||||||
class TypeBasedFlowTargetApi extends ModelGeneratorInput::SummaryTargetApi {
|
class TypeBasedFlowTargetApi extends SummaryModelGeneratorInput::SummaryTargetApi {
|
||||||
/**
|
/**
|
||||||
* Gets the string representation of all type based summaries for `this`
|
* Gets the string representation of all type based summaries for `this`
|
||||||
* inspired by the Theorems for Free approach.
|
* inspired by the Theorems for Free approach.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import csharp
|
import csharp
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = ContentSensitive::captureFlow(api, _)
|
where flow = ContentSensitive::captureFlow(api, _)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string noflow
|
from DataFlowSummaryTargetApi api, string noflow
|
||||||
where noflow = captureNeutral(api)
|
where noflow = captureNeutral(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
|
|
||||||
from DataFlowSinkTargetApi api, string sink
|
from DataFlowSinkTargetApi api, string sink
|
||||||
where sink = Heuristic::captureSink(api)
|
where sink = Heuristic::captureSink(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
|
|
||||||
from DataFlowSourceTargetApi api, string source
|
from DataFlowSourceTargetApi api, string source
|
||||||
where source = Heuristic::captureSource(api)
|
where source = Heuristic::captureSource(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = captureFlow(api, _)
|
where flow = captureFlow(api, _)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import PartialFlow::PartialPathGraph
|
import PartialFlow::PartialPathGraph
|
||||||
|
|
||||||
int explorationLimit() { result = 3 }
|
int explorationLimit() { result = 3 }
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
import java
|
import java
|
||||||
import semmle.code.java.dataflow.DataFlow
|
import semmle.code.java.dataflow.DataFlow
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import Heuristic
|
import Heuristic
|
||||||
import PropagateFlow::PathGraph
|
import PropagateFlow::PathGraph
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,20 @@ predicate isPrimitiveTypeUsedForBulkData(J::Type t) {
|
|||||||
t.hasName(["byte", "char", "Byte", "Character"])
|
t.hasName(["byte", "char", "Byte", "Character"])
|
||||||
}
|
}
|
||||||
|
|
||||||
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, JavaDataFlow> {
|
private predicate isInfrequentlyUsed(J::CompilationUnit cu) {
|
||||||
|
cu.getPackage().getName().matches("javax.swing%") or
|
||||||
|
cu.getPackage().getName().matches("java.awt%")
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate relevant(Callable api) {
|
||||||
|
api.isPublic() and
|
||||||
|
api.getDeclaringType().isPublic() and
|
||||||
|
api.fromSource() and
|
||||||
|
not isUninterestingForModels(api) and
|
||||||
|
not isInfrequentlyUsed(api.getCompilationUnit())
|
||||||
|
}
|
||||||
|
|
||||||
|
module ModelGeneratorCommonInput implements ModelGeneratorCommonInputSig<Location, JavaDataFlow> {
|
||||||
class Type = J::Type;
|
class Type = J::Type;
|
||||||
|
|
||||||
class Parameter = J::Parameter;
|
class Parameter = J::Parameter;
|
||||||
@@ -34,96 +47,8 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, JavaDataF
|
|||||||
|
|
||||||
class NodeExtended = DataFlow::Node;
|
class NodeExtended = DataFlow::Node;
|
||||||
|
|
||||||
Callable getAsExprEnclosingCallable(NodeExtended node) {
|
|
||||||
result = node.asExpr().getEnclosingCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable getEnclosingCallable(NodeExtended node) { result = node.getEnclosingCallable() }
|
Callable getEnclosingCallable(NodeExtended node) { result = node.getEnclosingCallable() }
|
||||||
|
|
||||||
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
|
||||||
|
|
||||||
private predicate isInfrequentlyUsed(J::CompilationUnit cu) {
|
|
||||||
cu.getPackage().getName().matches("javax.swing%") or
|
|
||||||
cu.getPackage().getName().matches("java.awt%")
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate relevant(Callable api) {
|
|
||||||
api.isPublic() and
|
|
||||||
api.getDeclaringType().isPublic() and
|
|
||||||
api.fromSource() and
|
|
||||||
not isUninterestingForModels(api) and
|
|
||||||
not isInfrequentlyUsed(api.getCompilationUnit())
|
|
||||||
}
|
|
||||||
|
|
||||||
private J::Method getARelevantOverride(J::Method m) {
|
|
||||||
result = m.getAnOverride() and
|
|
||||||
relevant(result) and
|
|
||||||
// Other exclusions for overrides.
|
|
||||||
not m instanceof J::ToStringMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the super implementation of `m` if it is relevant.
|
|
||||||
* If such a super implementations does not exist, returns `m` if it is relevant.
|
|
||||||
*/
|
|
||||||
private J::Callable liftedImpl(J::Callable m) {
|
|
||||||
(
|
|
||||||
result = getARelevantOverride(m)
|
|
||||||
or
|
|
||||||
result = m and relevant(m)
|
|
||||||
) and
|
|
||||||
not exists(getARelevantOverride(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSummaryModel(Callable api) {
|
|
||||||
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSourceModel(Callable api) {
|
|
||||||
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()).asCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
private predicate hasManualSinkModel(Callable api) {
|
|
||||||
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
|
||||||
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()).asCallable()
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isUninterestingForDataFlowModels(Callable api) {
|
|
||||||
api.getDeclaringType() instanceof J::Interface and not exists(api.getBody())
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { none() }
|
|
||||||
|
|
||||||
class SourceOrSinkTargetApi extends Callable {
|
|
||||||
SourceOrSinkTargetApi() { relevant(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SinkTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SinkTargetApi() { not hasManualSinkModel(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SourceTargetApi extends SourceOrSinkTargetApi {
|
|
||||||
SourceTargetApi() { not hasManualSourceModel(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class SummaryTargetApi extends Callable {
|
|
||||||
private Callable lift;
|
|
||||||
|
|
||||||
SummaryTargetApi() {
|
|
||||||
lift = liftedImpl(this) and
|
|
||||||
not hasManualSummaryModel(lift)
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable lift() { result = lift }
|
|
||||||
|
|
||||||
predicate isRelevant() {
|
|
||||||
relevant(this) and
|
|
||||||
not hasManualSummaryModel(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string isExtensible(Callable c) {
|
private string isExtensible(Callable c) {
|
||||||
if c.getDeclaringType().isFinal() then result = "false" else result = "true"
|
if c.getDeclaringType().isFinal() then result = "false" else result = "true"
|
||||||
}
|
}
|
||||||
@@ -204,50 +129,88 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, JavaDataF
|
|||||||
node.asExpr().(J::ThisAccess).isOwnInstanceAccess()
|
node.asExpr().(J::ThisAccess).isOwnInstanceAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate sinkModelSanitizer(DataFlow::Node node) {
|
|
||||||
// exclude variable capture jump steps
|
|
||||||
exists(Ssa::SsaImplicitInit closure |
|
|
||||||
closure.captures(_) and
|
|
||||||
node.asExpr() = closure.getAFirstUse()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate apiSource(DataFlow::Node source) {
|
|
||||||
(
|
|
||||||
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
|
|
||||||
source instanceof DataFlow::ParameterNode
|
|
||||||
) and
|
|
||||||
exists(J::RefType t |
|
|
||||||
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
|
|
||||||
not t instanceof J::TypeObject and
|
|
||||||
t.isPublic()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate irrelevantSourceSinkApi(Callable source, SourceTargetApi api) { none() }
|
|
||||||
|
|
||||||
string getInputArgument(DataFlow::Node source) {
|
|
||||||
exists(int pos |
|
|
||||||
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
|
|
||||||
if pos >= 0 then result = "Argument[" + pos + "]" else result = qualifierString()
|
|
||||||
)
|
|
||||||
or
|
|
||||||
source.asExpr() instanceof J::FieldAccess and
|
|
||||||
result = qualifierString()
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSinkKind(string kind) {
|
|
||||||
not kind = "log-injection" and
|
|
||||||
not kind.matches("regex-use%") and
|
|
||||||
not kind = "file-content-store"
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSourceKind(string kind) { any() }
|
|
||||||
|
|
||||||
predicate containerContent = DataFlowPrivate::containerContent/1;
|
predicate containerContent = DataFlowPrivate::containerContent/1;
|
||||||
|
|
||||||
|
string partialModelRow(Callable api, int i) {
|
||||||
|
i = 0 and qualifiedName(api, result, _) // package
|
||||||
|
or
|
||||||
|
i = 1 and qualifiedName(api, _, result) // type
|
||||||
|
or
|
||||||
|
i = 2 and result = isExtensible(api) // extensible
|
||||||
|
or
|
||||||
|
i = 3 and result = api.getName() // name
|
||||||
|
or
|
||||||
|
i = 4 and result = ExternalFlow::paramsString(api) // parameters
|
||||||
|
or
|
||||||
|
i = 5 and result = "" and exists(api) // ext
|
||||||
|
}
|
||||||
|
|
||||||
|
string partialNeutralModelRow(Callable api, int i) {
|
||||||
|
i = 0 and qualifiedName(api, result, _) // package
|
||||||
|
or
|
||||||
|
i = 1 and qualifiedName(api, _, result) // type
|
||||||
|
or
|
||||||
|
i = 2 and result = api.getName() // name
|
||||||
|
or
|
||||||
|
i = 3 and result = ExternalFlow::paramsString(api) // parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private import ModelGeneratorCommonInput
|
||||||
|
private import MakeModelGeneratorFactory<Location, JavaDataFlow, JavaTaintTracking, ModelGeneratorCommonInput>
|
||||||
|
|
||||||
|
module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
|
||||||
|
Callable getAsExprEnclosingCallable(NodeExtended node) {
|
||||||
|
result = node.asExpr().getEnclosingCallable()
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
||||||
|
|
||||||
|
private J::Method getARelevantOverride(J::Method m) {
|
||||||
|
result = m.getAnOverride() and
|
||||||
|
relevant(result) and
|
||||||
|
// Other exclusions for overrides.
|
||||||
|
not m instanceof J::ToStringMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the super implementation of `m` if it is relevant.
|
||||||
|
* If such a super implementations does not exist, returns `m` if it is relevant.
|
||||||
|
*/
|
||||||
|
private J::Callable liftedImpl(J::Callable m) {
|
||||||
|
(
|
||||||
|
result = getARelevantOverride(m)
|
||||||
|
or
|
||||||
|
result = m and relevant(m)
|
||||||
|
) and
|
||||||
|
not exists(getARelevantOverride(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
private predicate hasManualSummaryModel(Callable api) {
|
||||||
|
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()).asCallable() or
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel()).asCallable()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SummaryTargetApi extends Callable {
|
||||||
|
private Callable lift;
|
||||||
|
|
||||||
|
SummaryTargetApi() {
|
||||||
|
lift = liftedImpl(this) and
|
||||||
|
not hasManualSummaryModel(lift)
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable lift() { result = lift }
|
||||||
|
|
||||||
|
predicate isRelevant() {
|
||||||
|
relevant(this) and
|
||||||
|
not hasManualSummaryModel(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isUninterestingForDataFlowModels(Callable api) {
|
||||||
|
api.getDeclaringType() instanceof J::Interface and not exists(api.getBody())
|
||||||
|
}
|
||||||
|
|
||||||
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
predicate isAdditionalContentFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||||
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
|
TaintTracking::defaultAdditionalTaintStep(node1, node2, _) and
|
||||||
not exists(DataFlow::Content f |
|
not exists(DataFlow::Content f |
|
||||||
@@ -287,34 +250,71 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, JavaDataF
|
|||||||
or
|
or
|
||||||
c instanceof DataFlowUtil::MapKeyContent and result = "MapKey"
|
c instanceof DataFlowUtil::MapKeyContent and result = "MapKey"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string partialModelRow(Callable api, int i) {
|
private module SourceModelGeneratorInput implements SourceModelGeneratorInputSig {
|
||||||
i = 0 and qualifiedName(api, result, _) // package
|
private predicate hasManualSourceModel(Callable api) {
|
||||||
or
|
api = any(ExternalFlow::SourceCallable sc | sc.hasManualModel()) or
|
||||||
i = 1 and qualifiedName(api, _, result) // type
|
api = any(FlowSummaryImpl::Public::NeutralSourceCallable sc | sc.hasManualModel()).asCallable()
|
||||||
or
|
|
||||||
i = 2 and result = isExtensible(api) // extensible
|
|
||||||
or
|
|
||||||
i = 3 and result = api.getName() // name
|
|
||||||
or
|
|
||||||
i = 4 and result = ExternalFlow::paramsString(api) // parameters
|
|
||||||
or
|
|
||||||
i = 5 and result = "" and exists(api) // ext
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string partialNeutralModelRow(Callable api, int i) {
|
class SourceTargetApi extends Callable {
|
||||||
i = 0 and qualifiedName(api, result, _) // package
|
SourceTargetApi() { relevant(this) and not hasManualSourceModel(this) }
|
||||||
or
|
|
||||||
i = 1 and qualifiedName(api, _, result) // type
|
|
||||||
or
|
|
||||||
i = 2 and result = api.getName() // name
|
|
||||||
or
|
|
||||||
i = 3 and result = ExternalFlow::paramsString(api) // parameters
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate sourceNode = ExternalFlow::sourceNode/2;
|
predicate sourceNode = ExternalFlow::sourceNode/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||||
|
private predicate hasManualSinkModel(Callable api) {
|
||||||
|
api = any(ExternalFlow::SinkCallable sc | sc.hasManualModel()) or
|
||||||
|
api = any(FlowSummaryImpl::Public::NeutralSinkCallable sc | sc.hasManualModel()).asCallable()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SinkTargetApi extends Callable {
|
||||||
|
SinkTargetApi() { relevant(this) and not hasManualSinkModel(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate sinkModelSanitizer(DataFlow::Node node) {
|
||||||
|
// exclude variable capture jump steps
|
||||||
|
exists(Ssa::SsaImplicitInit closure |
|
||||||
|
closure.captures(_) and
|
||||||
|
node.asExpr() = closure.getAFirstUse()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate apiSource(DataFlow::Node source) {
|
||||||
|
(
|
||||||
|
source.asExpr().(J::FieldAccess).isOwnFieldAccess() or
|
||||||
|
source instanceof DataFlow::ParameterNode
|
||||||
|
) and
|
||||||
|
exists(J::RefType t |
|
||||||
|
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
|
||||||
|
not t instanceof J::TypeObject and
|
||||||
|
t.isPublic()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
string getInputArgument(DataFlow::Node source) {
|
||||||
|
exists(int pos |
|
||||||
|
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
|
||||||
|
if pos >= 0 then result = "Argument[" + pos + "]" else result = qualifierString()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
source.asExpr() instanceof J::FieldAccess and
|
||||||
|
result = qualifierString()
|
||||||
|
}
|
||||||
|
|
||||||
|
bindingset[kind]
|
||||||
|
predicate isRelevantSinkKind(string kind) {
|
||||||
|
not kind = "log-injection" and
|
||||||
|
not kind.matches("regex-use%") and
|
||||||
|
not kind = "file-content-store"
|
||||||
|
}
|
||||||
|
|
||||||
predicate sinkNode = ExternalFlow::sinkNode/2;
|
predicate sinkNode = ExternalFlow::sinkNode/2;
|
||||||
}
|
}
|
||||||
|
|
||||||
import MakeModelGenerator<Location, JavaDataFlow, JavaTaintTracking, ModelGeneratorInput>
|
import MakeSummaryModelGenerator<SummaryModelGeneratorInput> as SummaryModels
|
||||||
|
import MakeSourceModelGenerator<SourceModelGeneratorInput> as SourceModels
|
||||||
|
import MakeSinkModelGenerator<SinkModelGeneratorInput> as SinkModels
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
private import java as J
|
private import java as J
|
||||||
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
|
||||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||||
class Callable = J::Callable;
|
class Callable = J::Callable;
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ private import java
|
|||||||
private import semmle.code.java.Collections
|
private import semmle.code.java.Collections
|
||||||
private import semmle.code.java.dataflow.internal.ContainerFlow
|
private import semmle.code.java.dataflow.internal.ContainerFlow
|
||||||
private import CaptureModels as CaptureModels
|
private import CaptureModels as CaptureModels
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
private import CaptureModels::SummaryModelGeneratorInput as SummaryModelGeneratorInput
|
||||||
private import CaptureModelsPrinting
|
private import CaptureModelsPrinting
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,21 +285,19 @@ private predicate output(Callable callable, TypeVariable tv, string output) {
|
|||||||
functionalSink(callable, tv, output)
|
functionalSink(callable, tv, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
module ModelPrintingInput implements ModelPrintingSig {
|
module ModelPrintingInput implements ModelPrintingSummarySig {
|
||||||
class SummaryApi = TypeBasedFlowTargetApi;
|
class SummaryApi = TypeBasedFlowTargetApi;
|
||||||
|
|
||||||
class SourceOrSinkApi = ModelGeneratorInput::SourceOrSinkTargetApi;
|
|
||||||
|
|
||||||
string getProvenance() { result = "tb-generated" }
|
string getProvenance() { result = "tb-generated" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private module Printing = ModelPrinting<ModelPrintingInput>;
|
private module Printing = ModelPrintingSummary<ModelPrintingInput>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class of callables that are relevant generating summaries for based
|
* A class of callables that are relevant generating summaries for based
|
||||||
* on the Theorems for Free approach.
|
* on the Theorems for Free approach.
|
||||||
*/
|
*/
|
||||||
class TypeBasedFlowTargetApi extends ModelGeneratorInput::SummaryTargetApi {
|
class TypeBasedFlowTargetApi extends SummaryModelGeneratorInput::SummaryTargetApi {
|
||||||
/**
|
/**
|
||||||
* Gets the string representation of all type based summaries for `this`
|
* Gets the string representation of all type based summaries for `this`
|
||||||
* inspired by the Theorems for Free approach.
|
* inspired by the Theorems for Free approach.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import java
|
import java
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import java
|
import java
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import java
|
import java
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import java
|
import java
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import java
|
import java
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = ContentSensitive::captureFlow(api, _)
|
where flow = ContentSensitive::captureFlow(api, _)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string noflow
|
from DataFlowSummaryTargetApi api, string noflow
|
||||||
where noflow = Heuristic::captureNoFlow(api)
|
where noflow = Heuristic::captureNoFlow(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
|
|
||||||
from DataFlowSinkTargetApi api, string sink
|
from DataFlowSinkTargetApi api, string sink
|
||||||
where sink = Heuristic::captureSink(api)
|
where sink = Heuristic::captureSink(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
|
|
||||||
from DataFlowSourceTargetApi api, string source
|
from DataFlowSourceTargetApi api, string source
|
||||||
where source = Heuristic::captureSource(api)
|
where source = Heuristic::captureSource(api)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import internal.CaptureModels
|
import internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
|
|
||||||
from DataFlowSummaryTargetApi api, string flow
|
from DataFlowSummaryTargetApi api, string flow
|
||||||
where flow = captureFlow(api, _)
|
where flow = captureFlow(api, _)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
private import codeql.rust.dataflow.DataFlow
|
private import codeql.rust.dataflow.DataFlow
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import PartialFlow::PartialPathGraph
|
import PartialFlow::PartialPathGraph
|
||||||
|
|
||||||
int explorationLimit() { result = 3 }
|
int explorationLimit() { result = 3 }
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
private import codeql.rust.dataflow.DataFlow
|
private import codeql.rust.dataflow.DataFlow
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import Heuristic
|
import Heuristic
|
||||||
import PropagateFlow::PathGraph
|
import PropagateFlow::PathGraph
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ private import codeql.util.Unit
|
|||||||
private import rust
|
private import rust
|
||||||
private import rust as R
|
private import rust as R
|
||||||
private import codeql.rust.dataflow.DataFlow
|
private import codeql.rust.dataflow.DataFlow
|
||||||
private import codeql.rust.dataflow.internal.DataFlowImpl
|
private import codeql.rust.dataflow.internal.DataFlowImpl as DataFlowImpl
|
||||||
private import codeql.rust.dataflow.internal.Node as Node
|
private import codeql.rust.dataflow.internal.Node as Node
|
||||||
private import codeql.rust.dataflow.internal.Content
|
private import codeql.rust.dataflow.internal.Content
|
||||||
private import codeql.rust.dataflow.FlowSource as FlowSource
|
private import codeql.rust.dataflow.FlowSource as FlowSource
|
||||||
@@ -11,7 +11,25 @@ private import codeql.rust.dataflow.internal.TaintTrackingImpl
|
|||||||
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
|
||||||
private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary
|
private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary
|
||||||
|
|
||||||
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataFlow> {
|
private predicate relevant(Function api) {
|
||||||
|
// Only include functions that have a resolved path.
|
||||||
|
api.hasCrateOrigin() and
|
||||||
|
api.hasExtendedCanonicalPath() and
|
||||||
|
(
|
||||||
|
// This excludes closures (these are not exported API endpoints) and
|
||||||
|
// functions without a `pub` visiblity. A function can be `pub` without
|
||||||
|
// ultimately being exported by a crate, so this is an overapproximation.
|
||||||
|
api.hasVisibility()
|
||||||
|
or
|
||||||
|
// If a method implements a public trait it is exposed through the trait.
|
||||||
|
// We overapproximate this by including all trait method implementations.
|
||||||
|
exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module ModelGeneratorCommonInput implements
|
||||||
|
ModelGeneratorCommonInputSig<Location, DataFlowImpl::RustDataFlow>
|
||||||
|
{
|
||||||
// NOTE: We are not using type information for now.
|
// NOTE: We are not using type information for now.
|
||||||
class Type = Unit;
|
class Type = Unit;
|
||||||
|
|
||||||
@@ -23,42 +41,71 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
|
|||||||
Type getType() { any() }
|
Type getType() { any() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Callable getAsExprEnclosingCallable(NodeExtended node) { result = node.asExpr().getScope() }
|
|
||||||
|
|
||||||
Callable getEnclosingCallable(NodeExtended node) {
|
Callable getEnclosingCallable(NodeExtended node) {
|
||||||
result = node.(Node::Node).getEnclosingCallable().asCfgScope()
|
result = node.(Node::Node).getEnclosingCallable().asCfgScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
predicate isRelevantType(Type t) { any() }
|
||||||
|
|
||||||
private predicate relevant(Function api) {
|
/**
|
||||||
// Only include functions that have a resolved path.
|
* Gets the underlying type of the content `c`.
|
||||||
api.hasCrateOrigin() and
|
*/
|
||||||
api.hasExtendedCanonicalPath() and
|
Type getUnderlyingContentType(DataFlow::ContentSet c) { result = any(Type t) and exists(c) }
|
||||||
(
|
|
||||||
// This excludes closures (these are not exported API endpoints) and
|
string qualifierString() { result = "Argument[self]" }
|
||||||
// functions without a `pub` visiblity. A function can be `pub` without
|
|
||||||
// ultimately being exported by a crate, so this is an overapproximation.
|
string parameterAccess(R::ParamBase p) {
|
||||||
api.hasVisibility()
|
result =
|
||||||
or
|
"Argument[" + any(DataFlowImpl::ParameterPosition pos | p = pos.getParameterIn(_)).toString() +
|
||||||
// If a method implements a public trait it is exposed through the trait.
|
"]"
|
||||||
// We overapproximate this by including all trait method implementations.
|
|
||||||
exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isUninterestingForDataFlowModels(Callable api) { none() }
|
string parameterContentAccess(R::ParamBase p) { result = parameterAccess(p) }
|
||||||
|
|
||||||
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { none() }
|
class InstanceParameterNode extends DataFlow::ParameterNode {
|
||||||
|
InstanceParameterNode() { this.asParameter() instanceof SelfParam }
|
||||||
class SourceOrSinkTargetApi extends Callable {
|
|
||||||
SourceOrSinkTargetApi() { relevant(this) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SinkTargetApi extends SourceOrSinkTargetApi { }
|
bindingset[c]
|
||||||
|
string paramReturnNodeAsOutput(Callable c, DataFlowImpl::ParameterPosition pos) {
|
||||||
|
result = paramReturnNodeAsContentOutput(c, pos)
|
||||||
|
}
|
||||||
|
|
||||||
class SourceTargetApi extends SourceOrSinkTargetApi { }
|
bindingset[c]
|
||||||
|
string paramReturnNodeAsContentOutput(Callable c, DataFlowImpl::ParameterPosition pos) {
|
||||||
|
result = parameterContentAccess(c.getParamList().getParam(pos.getPosition()))
|
||||||
|
or
|
||||||
|
pos.isSelf() and result = qualifierString()
|
||||||
|
}
|
||||||
|
|
||||||
|
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
||||||
|
result = ret.(Node::Node).getEnclosingCallable().asCfgScope()
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate isOwnInstanceAccessNode(DataFlowImpl::RustDataFlow::ReturnNode node) {
|
||||||
|
// This is probably not relevant to implement for Rust, as we only use
|
||||||
|
// `captureMixedFlow` which doesn't explicitly distinguish between
|
||||||
|
// functions that return `self` and those that don't.
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
|
||||||
|
predicate containerContent(DataFlow::ContentSet c) {
|
||||||
|
c.(SingletonContentSet).getContent() instanceof ElementContent
|
||||||
|
}
|
||||||
|
|
||||||
|
string partialModelRow(Callable api, int i) {
|
||||||
|
i = 0 and result = api.(Function).getCrateOrigin() // crate
|
||||||
|
or
|
||||||
|
i = 1 and result = api.(Function).getExtendedCanonicalPath() // name
|
||||||
|
}
|
||||||
|
|
||||||
|
string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private import ModelGeneratorCommonInput
|
||||||
|
private import MakeModelGeneratorFactory<Location, DataFlowImpl::RustDataFlow, RustTaintTracking, ModelGeneratorCommonInput>
|
||||||
|
|
||||||
|
private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
|
||||||
class SummaryTargetApi extends Callable {
|
class SummaryTargetApi extends Callable {
|
||||||
private Callable lift;
|
private Callable lift;
|
||||||
|
|
||||||
@@ -72,74 +119,9 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
|
|||||||
predicate isRelevant() { relevant(this) }
|
predicate isRelevant() { relevant(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate isRelevantType(Type t) { any() }
|
Callable getAsExprEnclosingCallable(NodeExtended node) { result = node.asExpr().getScope() }
|
||||||
|
|
||||||
/**
|
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
|
||||||
* Gets the underlying type of the content `c`.
|
|
||||||
*/
|
|
||||||
Type getUnderlyingContentType(DataFlow::ContentSet c) { result = any(Type t) and exists(c) }
|
|
||||||
|
|
||||||
string qualifierString() { result = "Argument[self]" }
|
|
||||||
|
|
||||||
string parameterAccess(R::ParamBase p) {
|
|
||||||
result = "Argument[" + any(ParameterPosition pos | p = pos.getParameterIn(_)).toString() + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
string parameterContentAccess(R::ParamBase p) { result = parameterAccess(p) }
|
|
||||||
|
|
||||||
class InstanceParameterNode extends DataFlow::ParameterNode {
|
|
||||||
InstanceParameterNode() { this.asParameter() instanceof SelfParam }
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[c]
|
|
||||||
string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
|
|
||||||
result = paramReturnNodeAsContentOutput(c, pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[c]
|
|
||||||
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
|
|
||||||
result = parameterContentAccess(c.getParamList().getParam(pos.getPosition()))
|
|
||||||
or
|
|
||||||
pos.isSelf() and result = qualifierString()
|
|
||||||
}
|
|
||||||
|
|
||||||
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
|
|
||||||
result = ret.(Node::Node).getEnclosingCallable().asCfgScope()
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isOwnInstanceAccessNode(RustDataFlow::ReturnNode node) {
|
|
||||||
// This is probably not relevant to implement for Rust, as we only use
|
|
||||||
// `captureMixedFlow` which doesn't explicitly distinguish between
|
|
||||||
// functions that return `self` and those that don't.
|
|
||||||
none()
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds if `source` is an API entrypoint, i.e., a source of input where data
|
|
||||||
* can flow in to a library. This is used for creating sink models, as we
|
|
||||||
* only want to mark functions as sinks if input to the function can reach
|
|
||||||
* (from an input source) a known sink.
|
|
||||||
*/
|
|
||||||
predicate apiSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode }
|
|
||||||
|
|
||||||
bindingset[sourceEnclosing, api]
|
|
||||||
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { none() }
|
|
||||||
|
|
||||||
string getInputArgument(DataFlow::Node source) {
|
|
||||||
result = "Argument[" + source.(Node::SourceParameterNode).getPosition().toString() + "]"
|
|
||||||
}
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSinkKind(string kind) { any() }
|
|
||||||
|
|
||||||
bindingset[kind]
|
|
||||||
predicate isRelevantSourceKind(string kind) { any() }
|
|
||||||
|
|
||||||
predicate containerContent(DataFlow::ContentSet c) {
|
|
||||||
c.(SingletonContentSet).getContent() instanceof ElementContent
|
|
||||||
}
|
|
||||||
|
|
||||||
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
|
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
|
||||||
|
|
||||||
@@ -159,7 +141,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
|
|||||||
private string encodeContent(ContentSet cs, string arg) {
|
private string encodeContent(ContentSet cs, string arg) {
|
||||||
result = FlowSummary::Input::encodeContent(cs, arg)
|
result = FlowSummary::Input::encodeContent(cs, arg)
|
||||||
or
|
or
|
||||||
exists(Content c | cs = TSingletonContentSet(c) |
|
exists(Content c | cs = DataFlowImpl::TSingletonContentSet(c) |
|
||||||
exists(int pos |
|
exists(int pos |
|
||||||
pos = c.(FunctionCallArgumentContent).getPosition() and
|
pos = c.(FunctionCallArgumentContent).getPosition() and
|
||||||
result = "Parameter" and
|
result = "Parameter" and
|
||||||
@@ -176,18 +158,36 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
|
|||||||
if arg = "" then result = name else result = name + "[" + arg + "]"
|
if arg = "" then result = name else result = name + "[" + arg + "]"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string partialModelRow(Callable api, int i) {
|
private module SourceModelGeneratorInput implements SourceModelGeneratorInputSig {
|
||||||
i = 0 and result = api.(Function).getCrateOrigin() // crate
|
class SourceTargetApi extends Callable {
|
||||||
or
|
SourceTargetApi() { relevant(this) }
|
||||||
i = 1 and result = api.(Function).getExtendedCanonicalPath() // name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) }
|
|
||||||
|
|
||||||
predicate sourceNode(DataFlow::Node node, string kind) { FlowSource::sourceNode(node, kind) }
|
predicate sourceNode(DataFlow::Node node, string kind) { FlowSource::sourceNode(node, kind) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
|
||||||
|
class SinkTargetApi extends Callable {
|
||||||
|
SinkTargetApi() { relevant(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `source` is an API entrypoint, i.e., a source of input where data
|
||||||
|
* can flow in to a library. This is used for creating sink models, as we
|
||||||
|
* only want to mark functions as sinks if input to the function can reach
|
||||||
|
* (from an input source) a known sink.
|
||||||
|
*/
|
||||||
|
predicate apiSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode }
|
||||||
|
|
||||||
|
string getInputArgument(DataFlow::Node source) {
|
||||||
|
result = "Argument[" + source.(Node::SourceParameterNode).getPosition().toString() + "]"
|
||||||
|
}
|
||||||
|
|
||||||
predicate sinkNode(DataFlow::Node node, string kind) { FlowSink::sinkNode(node, kind) }
|
predicate sinkNode(DataFlow::Node node, string kind) { FlowSink::sinkNode(node, kind) }
|
||||||
}
|
}
|
||||||
|
|
||||||
import MakeModelGenerator<Location, RustDataFlow, RustTaintTracking, ModelGeneratorInput>
|
import MakeSummaryModelGenerator<SummaryModelGeneratorInput> as SummaryModels
|
||||||
|
import MakeSourceModelGenerator<SourceModelGeneratorInput> as SourceModels
|
||||||
|
import MakeSinkModelGenerator<SinkModelGeneratorInput> as SinkModels
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
private import rust as R
|
private import rust as R
|
||||||
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
private import codeql.mad.modelgenerator.internal.ModelPrinting
|
||||||
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
|
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
|
||||||
|
|
||||||
private module ModelPrintingLang implements ModelPrintingLangSig {
|
private module ModelPrintingLang implements ModelPrintingLangSig {
|
||||||
class Callable = R::Callable;
|
class Callable = R::Callable;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import rust
|
import rust
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SinkModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import rust
|
import rust
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SourceModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
import codeql.rust.dataflow.internal.ModelsAsData
|
import codeql.rust.dataflow.internal.ModelsAsData
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import rust
|
import rust
|
||||||
import utils.modelgenerator.internal.CaptureModels
|
import utils.modelgenerator.internal.CaptureModels
|
||||||
|
import SummaryModels
|
||||||
import utils.test.InlineMadTest
|
import utils.test.InlineMadTest
|
||||||
|
|
||||||
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
module InlineMadTestConfig implements InlineMadTestConfigSig {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ signature module ModelPrintingLangSig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
||||||
signature module ModelPrintingSig {
|
signature module ModelPrintingSummarySig {
|
||||||
/**
|
/**
|
||||||
* The class of APIs relevant for model generation.
|
* The class of APIs relevant for model generation.
|
||||||
*/
|
*/
|
||||||
@@ -24,6 +24,16 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
|||||||
Lang::Callable lift();
|
Lang::Callable lift();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the string representation of the provenance of the models.
|
||||||
|
*/
|
||||||
|
string getProvenance();
|
||||||
|
}
|
||||||
|
|
||||||
|
signature module ModelPrintingSourceOrSinkSig {
|
||||||
|
/**
|
||||||
|
* The class of APIs relevant for model generation.
|
||||||
|
*/
|
||||||
class SourceOrSinkApi extends Lang::Callable;
|
class SourceOrSinkApi extends Lang::Callable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,14 +42,14 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
|||||||
string getProvenance();
|
string getProvenance();
|
||||||
}
|
}
|
||||||
|
|
||||||
module ModelPrinting<ModelPrintingSig Printing> {
|
/**
|
||||||
/**
|
* Computes the first columns for MaD rows used for summaries, sources and sinks.
|
||||||
* Computes the first columns for MaD rows used for summaries, sources and sinks.
|
*/
|
||||||
*/
|
private string asPartialModel(Lang::Callable api) {
|
||||||
private string asPartialModel(Lang::Callable api) {
|
result = strictconcat(int i | | Lang::partialModelRow(api, i), ";" order by i) + ";"
|
||||||
result = strictconcat(int i | | Lang::partialModelRow(api, i), ";" order by i) + ";"
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
module ModelPrintingSummary<ModelPrintingSummarySig Printing> {
|
||||||
/**
|
/**
|
||||||
* Computes the first columns for neutral MaD rows.
|
* Computes the first columns for neutral MaD rows.
|
||||||
*/
|
*/
|
||||||
@@ -106,7 +116,9 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
|||||||
preservesValue = false and
|
preservesValue = false and
|
||||||
result = asSummaryModel(api, input, output, "taint", lift)
|
result = asSummaryModel(api, input, output, "taint", lift)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module ModelPrintingSourceOrSink<ModelPrintingSourceOrSinkSig Printing> {
|
||||||
/**
|
/**
|
||||||
* Gets the sink model for `api` with `input` and `kind`.
|
* Gets the sink model for `api` with `input` and `kind`.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user