Java: share getCallable interface between automodel extraction modes

This commit is contained in:
Stephan Brandauer
2023-06-07 14:38:52 +02:00
parent 92ad02a752
commit a8799fe981
3 changed files with 59 additions and 22 deletions

View File

@@ -16,6 +16,7 @@ private import semmle.code.java.security.RequestForgery
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
private import AutomodelSharedUtil as AutomodelSharedUtil private import AutomodelSharedUtil as AutomodelSharedUtil
private import semmle.code.java.security.PathSanitizer as PathSanitizer private import semmle.code.java.security.PathSanitizer as PathSanitizer
private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
import AutomodelSharedCharacteristics as SharedCharacteristics import AutomodelSharedCharacteristics as SharedCharacteristics
import AutomodelEndpointTypes as AutomodelEndpointTypes import AutomodelEndpointTypes as AutomodelEndpointTypes
@@ -85,8 +86,8 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
additional predicate sinkSpec( additional predicate sinkSpec(
Endpoint e, string package, string type, string name, string signature, string ext, string input Endpoint e, string package, string type, string name, string signature, string ext, string input
) { ) {
ApplicationCandidatesImpl::getCallable(e).hasQualifiedName(package, type, name) and ApplicationModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(getCallable(e)) and signature = ExternalFlow::paramsString(ApplicationModeGetCallable::getCallable(e)) and
ext = "" and ext = "" and
( (
exists(Call c, int argIdx | exists(Call c, int argIdx |
@@ -110,13 +111,19 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
type = CallContext() and type = CallContext() and
result = any(Call c | e.asExpr() = [c.getAnArgument(), c.getQualifier()]) result = any(Call c | e.asExpr() = [c.getAnArgument(), c.getQualifier()])
} }
}
private class JavaCallable = Callable;
private module ApplicationModeGetCallable implements AutomodelSharedGetCallable::GetCallableSig {
class Callable = JavaCallable;
class Endpoint = ApplicationCandidatesImpl::Endpoint;
/** /**
* Returns the API callable being modeled. * Returns the API callable being modeled.
*
* Each Java mode should implement this predicate.
*/ */
additional Callable getCallable(Endpoint e) { Callable getCallable(Endpoint e) {
exists(Call c | exists(Call c |
e.asExpr() = [c.getAnArgument(), c.getQualifier()] and e.asExpr() = [c.getAnArgument(), c.getQualifier()] and
result = c.getCallee() result = c.getCallee()
@@ -209,8 +216,8 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::isSink(e, _) and not ApplicationCandidatesImpl::isSink(e, _) and
ApplicationCandidatesImpl::getCallable(e).getName().matches("is%") and ApplicationModeGetCallable::getCallable(e).getName().matches("is%") and
ApplicationCandidatesImpl::getCallable(e).getReturnType() instanceof BooleanType ApplicationModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
} }
} }
@@ -228,7 +235,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::isSink(e, _) and not ApplicationCandidatesImpl::isSink(e, _) and
exists(Callable callable | exists(Callable callable |
callable = ApplicationCandidatesImpl::getCallable(e) and callable = ApplicationModeGetCallable::getCallable(e) and
callable.getName().toLowerCase() = ["exists", "notexists"] and callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType callable.getReturnType() instanceof BooleanType
) )
@@ -242,7 +249,7 @@ private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkChara
ExceptionCharacteristic() { this = "exception" } ExceptionCharacteristic() { this = "exception" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
ApplicationCandidatesImpl::getCallable(e).getDeclaringType().getASupertype*() instanceof ApplicationModeGetCallable::getCallable(e).getDeclaringType().getASupertype*() instanceof
TypeThrowable TypeThrowable
} }
} }
@@ -291,7 +298,7 @@ private class ArgumentToLocalCall extends CharacteristicsImpl::UninterestingToMo
ArgumentToLocalCall() { this = "argument to local call" } ArgumentToLocalCall() { this = "argument to local call" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
ApplicationCandidatesImpl::getCallable(e).fromSource() ApplicationModeGetCallable::getCallable(e).fromSource()
} }
} }
@@ -302,7 +309,7 @@ private class ExcludedFromModeling extends CharacteristicsImpl::UninterestingToM
ExcludedFromModeling() { this = "excluded from modeling" } ExcludedFromModeling() { this = "excluded from modeling" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
ModelExclusions::isUninterestingForModels(ApplicationCandidatesImpl::getCallable(e)) or ModelExclusions::isUninterestingForModels(ApplicationModeGetCallable::getCallable(e)) or
ModelExclusions::isUninterestingForModels(e.getEnclosingCallable()) ModelExclusions::isUninterestingForModels(e.getEnclosingCallable())
} }
} }
@@ -316,7 +323,7 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
NonPublicMethodCharacteristic() { this = "non-public method" } NonPublicMethodCharacteristic() { this = "non-public method" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::getCallable(e).isPublic() not ApplicationModeGetCallable::getCallable(e).isPublic()
} }
} }

View File

@@ -15,6 +15,7 @@ private import semmle.code.java.security.QueryInjection
private import semmle.code.java.security.RequestForgery private import semmle.code.java.security.RequestForgery
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
private import AutomodelSharedUtil as AutomodelSharedUtil private import AutomodelSharedUtil as AutomodelSharedUtil
private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
import AutomodelSharedCharacteristics as SharedCharacteristics import AutomodelSharedCharacteristics as SharedCharacteristics
import AutomodelEndpointTypes as AutomodelEndpointTypes import AutomodelEndpointTypes as AutomodelEndpointTypes
@@ -66,8 +67,8 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
additional predicate sinkSpec( additional predicate sinkSpec(
Endpoint e, string package, string type, string name, string signature, string ext, string input Endpoint e, string package, string type, string name, string signature, string ext, string input
) { ) {
FrameworkCandidatesImpl::getCallable(e).hasQualifiedName(package, type, name) and FrameworkModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(getCallable(e)) and signature = ExternalFlow::paramsString(FrameworkModeGetCallable::getCallable(e)) and
ext = "" and ext = "" and
exists(int paramIdx | e.isParameterOf(_, paramIdx) | exists(int paramIdx | e.isParameterOf(_, paramIdx) |
input = AutomodelSharedUtil::getArgumentForIndex(paramIdx) input = AutomodelSharedUtil::getArgumentForIndex(paramIdx)
@@ -81,18 +82,26 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
*/ */
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) { RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
type = MethodDoc() and type = MethodDoc() and
result = FrameworkCandidatesImpl::getCallable(e).(Documentable).getJavadoc() result = FrameworkModeGetCallable::getCallable(e).(Documentable).getJavadoc()
or or
type = ClassDoc() and type = ClassDoc() and
result = FrameworkCandidatesImpl::getCallable(e).getDeclaringType().(Documentable).getJavadoc() result = FrameworkModeGetCallable::getCallable(e).getDeclaringType().(Documentable).getJavadoc()
} }
}
private class JavaCallable = Callable;
private module FrameworkModeGetCallable implements AutomodelSharedGetCallable::GetCallableSig {
class Callable = JavaCallable;
class Endpoint = FrameworkCandidatesImpl::Endpoint;
/** /**
* Returns the callable that contains the given endpoint. * Returns the callable that contains the given endpoint.
* *
* Each Java mode should implement this predicate. * Each Java mode should implement this predicate.
*/ */
additional Callable getCallable(Endpoint e) { result = e.getEnclosingCallable() } Callable getCallable(Endpoint e) { result = e.getEnclosingCallable() }
} }
module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics<FrameworkCandidatesImpl>; module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics<FrameworkCandidatesImpl>;
@@ -163,8 +172,8 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _) and not FrameworkCandidatesImpl::isSink(e, _) and
FrameworkCandidatesImpl::getCallable(e).getName().matches("is%") and FrameworkModeGetCallable::getCallable(e).getName().matches("is%") and
FrameworkCandidatesImpl::getCallable(e).getReturnType() instanceof BooleanType FrameworkModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
} }
} }
@@ -182,7 +191,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _) and not FrameworkCandidatesImpl::isSink(e, _) and
exists(Callable callable | exists(Callable callable |
callable = FrameworkCandidatesImpl::getCallable(e) and callable = FrameworkModeGetCallable::getCallable(e) and
callable.getName().toLowerCase() = ["exists", "notexists"] and callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType callable.getReturnType() instanceof BooleanType
) )
@@ -196,7 +205,7 @@ private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkChara
ExceptionCharacteristic() { this = "exception" } ExceptionCharacteristic() { this = "exception" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
FrameworkCandidatesImpl::getCallable(e).getDeclaringType().getASupertype*() instanceof FrameworkModeGetCallable::getCallable(e).getDeclaringType().getASupertype*() instanceof
TypeThrowable TypeThrowable
} }
} }
@@ -222,7 +231,7 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
NonPublicMethodCharacteristic() { this = "non-public method" } NonPublicMethodCharacteristic() { this = "non-public method" }
override predicate appliesToEndpoint(Endpoint e) { override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::getCallable(e).isPublic() not FrameworkModeGetCallable::getCallable(e).isPublic()
} }
} }

View File

@@ -0,0 +1,21 @@
/**
* An automodel extraction mode instantiates this interface to define how to access
* the callable that's associated with an endpoint.
*/
signature module GetCallableSig {
/**
* A callable is the definition of a method, function, etc. - something that can be called.
*/
class Callable;
/**
* An endpoint is a potential candidate for modeling. This will typically be bound to the language's
* DataFlow node class, or a subtype thereof.
*/
class Endpoint;
/**
* Gets the callable that's associated with the given endpoint.
*/
Callable getCallable(Endpoint endpoint);
}