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:
Michael Nebel
2025-05-02 09:38:24 +02:00
committed by GitHub
53 changed files with 1566 additions and 1459 deletions

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

@@ -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, _)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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`.
*/ */