зеркало из https://github.com/github/codeql.git
Merge pull request #13886 from github/kaeluka/java-automodel-variadic-args
Java: automodel application mode: use endpoint class like in framework mode
This commit is contained in:
Коммит
20254c3d0a
|
@ -21,21 +21,97 @@ import AutomodelEndpointTypes as AutomodelEndpointTypes
|
||||||
|
|
||||||
newtype JavaRelatedLocationType = CallContext()
|
newtype JavaRelatedLocationType = CallContext()
|
||||||
|
|
||||||
|
newtype TApplicationModeEndpoint =
|
||||||
|
TExplicitArgument(Call call, DataFlow::Node arg) {
|
||||||
|
exists(Argument argExpr |
|
||||||
|
arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg()
|
||||||
|
)
|
||||||
|
} or
|
||||||
|
TInstanceArgument(Call call, DataFlow::Node arg) { arg = DataFlow::getInstanceArgument(call) } or
|
||||||
|
TImplicitVarargsArray(Call call, DataFlow::Node arg, int idx) {
|
||||||
|
exists(Argument argExpr |
|
||||||
|
arg.asExpr() = argExpr and
|
||||||
|
call.getArgument(idx) = argExpr and
|
||||||
|
argExpr.isVararg() and
|
||||||
|
not exists(int i | i < idx and call.getArgument(i).(Argument).isVararg())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An endpoint is a node that is a candidate for modeling.
|
||||||
|
*/
|
||||||
|
abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint {
|
||||||
|
abstract predicate isArgOf(Call c, int idx);
|
||||||
|
|
||||||
|
Call getCall() { this.isArgOf(result, _) }
|
||||||
|
|
||||||
|
int getArgIndex() { this.isArgOf(_, result) }
|
||||||
|
|
||||||
|
abstract Top asTop();
|
||||||
|
|
||||||
|
abstract DataFlow::Node asNode();
|
||||||
|
|
||||||
|
abstract string toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class representing nodes that are arguments to calls.
|
* A class representing nodes that are arguments to calls.
|
||||||
*/
|
*/
|
||||||
private class ArgumentNode extends DataFlow::Node {
|
class ExplicitArgument extends ApplicationModeEndpoint, TExplicitArgument {
|
||||||
Call c;
|
Call call;
|
||||||
|
DataFlow::Node arg;
|
||||||
|
|
||||||
ArgumentNode() {
|
ExplicitArgument() { this = TExplicitArgument(call, arg) }
|
||||||
exists(Argument arg | this.asExpr() = arg and not arg.isVararg() and c = arg.getCall())
|
|
||||||
or
|
override predicate isArgOf(Call c, int idx) { c = call and this.asTop() = c.getArgument(idx) }
|
||||||
this.(DataFlow::ImplicitVarargsArray).getCall() = c
|
|
||||||
or
|
override Top asTop() { result = arg.asExpr() }
|
||||||
this = DataFlow::getInstanceArgument(c)
|
|
||||||
|
override DataFlow::Node asNode() { result = arg }
|
||||||
|
|
||||||
|
override string toString() { result = arg.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
|
||||||
|
Call call;
|
||||||
|
DataFlow::Node arg;
|
||||||
|
|
||||||
|
InstanceArgument() { this = TInstanceArgument(call, arg) }
|
||||||
|
|
||||||
|
override predicate isArgOf(Call c, int idx) {
|
||||||
|
c = call and this.asTop() = c.getQualifier() and idx = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
Call getCall() { result = c }
|
override Top asTop() { if exists(arg.asExpr()) then result = arg.asExpr() else result = call }
|
||||||
|
|
||||||
|
override DataFlow::Node asNode() { result = arg }
|
||||||
|
|
||||||
|
override string toString() { result = arg.toString() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An endpoint that represents an implicit varargs array.
|
||||||
|
* We choose to represent the varargs array as a single endpoint, rather than as multiple endpoints.
|
||||||
|
*
|
||||||
|
* This avoids the problem of having to deal with redundant endpoints downstream.
|
||||||
|
*
|
||||||
|
* In order to be able to distinguish between varargs endpoints and regular endpoints, we export the `isVarargsArray`
|
||||||
|
* meta data field in the extraction queries.
|
||||||
|
*/
|
||||||
|
class ImplicitVarargsArray extends ApplicationModeEndpoint, TImplicitVarargsArray {
|
||||||
|
Call call;
|
||||||
|
DataFlow::Node vararg;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
ImplicitVarargsArray() { this = TImplicitVarargsArray(call, vararg, idx) }
|
||||||
|
|
||||||
|
override predicate isArgOf(Call c, int i) { c = call and i = idx }
|
||||||
|
|
||||||
|
override Top asTop() { result = this.getCall() }
|
||||||
|
|
||||||
|
override DataFlow::Node asNode() { result = vararg }
|
||||||
|
|
||||||
|
override string toString() { result = vararg.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +123,7 @@ private class ArgumentNode extends DataFlow::Node {
|
||||||
*/
|
*/
|
||||||
module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
||||||
// for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
|
// for documentation of the implementations here, see the QLDoc in the CandidateSig signature module.
|
||||||
class Endpoint = ArgumentNode;
|
class Endpoint = ApplicationModeEndpoint;
|
||||||
|
|
||||||
class EndpointType = AutomodelEndpointTypes::EndpointType;
|
class EndpointType = AutomodelEndpointTypes::EndpointType;
|
||||||
|
|
||||||
|
@ -61,18 +137,18 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
|
||||||
predicate isSanitizer(Endpoint e, EndpointType t) {
|
predicate isSanitizer(Endpoint e, EndpointType t) {
|
||||||
exists(t) and
|
exists(t) and
|
||||||
(
|
(
|
||||||
e.getType() instanceof BoxedType
|
e.asNode().getType() instanceof BoxedType
|
||||||
or
|
or
|
||||||
e.getType() instanceof PrimitiveType
|
e.asNode().getType() instanceof PrimitiveType
|
||||||
or
|
or
|
||||||
e.getType() instanceof NumberType
|
e.asNode().getType() instanceof NumberType
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
t instanceof AutomodelEndpointTypes::PathInjectionSinkType and
|
t instanceof AutomodelEndpointTypes::PathInjectionSinkType and
|
||||||
e instanceof PathSanitizer::PathInjectionSanitizer
|
e.asNode() instanceof PathSanitizer::PathInjectionSanitizer
|
||||||
}
|
}
|
||||||
|
|
||||||
RelatedLocation asLocation(Endpoint e) { result = e.asExpr() }
|
RelatedLocation asLocation(Endpoint e) { result = e.asTop() }
|
||||||
|
|
||||||
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
|
predicate isKnownKind = AutomodelJavaUtil::isKnownKind/2;
|
||||||
|
|
||||||
|
@ -98,16 +174,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
|
||||||
ApplicationModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
|
ApplicationModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
|
||||||
signature = ExternalFlow::paramsString(ApplicationModeGetCallable::getCallable(e)) and
|
signature = ExternalFlow::paramsString(ApplicationModeGetCallable::getCallable(e)) and
|
||||||
ext = "" and
|
ext = "" and
|
||||||
(
|
input = AutomodelJavaUtil::getArgumentForIndex(e.getArgIndex())
|
||||||
exists(Call c, int argIdx |
|
|
||||||
e.asExpr() = c.getArgument(argIdx) and
|
|
||||||
input = AutomodelJavaUtil::getArgumentForIndex(argIdx)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
exists(Call c |
|
|
||||||
e.asExpr() = c.getQualifier() and input = AutomodelJavaUtil::getArgumentForIndex(-1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,7 +185,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
|
||||||
*/
|
*/
|
||||||
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
|
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
|
||||||
type = CallContext() and
|
type = CallContext() and
|
||||||
result = any(Call c | e.asExpr() = [c.getAnArgument(), c.getQualifier()])
|
result = e.getCall()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,12 +199,7 @@ private module ApplicationModeGetCallable implements AutomodelSharedGetCallable:
|
||||||
/**
|
/**
|
||||||
* Returns the API callable being modeled.
|
* Returns the API callable being modeled.
|
||||||
*/
|
*/
|
||||||
Callable getCallable(Endpoint e) {
|
Callable getCallable(Endpoint e) { result = e.getCall().getCallee() }
|
||||||
exists(Call c |
|
|
||||||
e.asExpr() = [c.getAnArgument(), c.getQualifier()] and
|
|
||||||
result = c.getCallee()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -145,7 +207,7 @@ private module ApplicationModeGetCallable implements AutomodelSharedGetCallable:
|
||||||
* should be empty.
|
* should be empty.
|
||||||
*/
|
*/
|
||||||
private predicate isCustomSink(Endpoint e, string kind) {
|
private predicate isCustomSink(Endpoint e, string kind) {
|
||||||
e instanceof QueryInjectionSink and kind = "sql"
|
e.asNode() instanceof QueryInjectionSink and kind = "sql"
|
||||||
}
|
}
|
||||||
|
|
||||||
module CharacteristicsImpl =
|
module CharacteristicsImpl =
|
||||||
|
@ -167,23 +229,21 @@ class ApplicationModeMetadataExtractor extends string {
|
||||||
|
|
||||||
predicate hasMetadata(
|
predicate hasMetadata(
|
||||||
Endpoint e, string package, string type, string subtypes, string name, string signature,
|
Endpoint e, string package, string type, string subtypes, string name, string signature,
|
||||||
string input
|
string input, string isVarargsArray
|
||||||
) {
|
) {
|
||||||
exists(Call call, Callable callable, int argIdx |
|
exists(Callable callable |
|
||||||
call.getCallee() = callable and
|
e.getCall().getCallee() = callable and
|
||||||
(
|
input = AutomodelJavaUtil::getArgumentForIndex(e.getArgIndex()) and
|
||||||
e.asExpr() = call.getArgument(argIdx)
|
|
||||||
or
|
|
||||||
e.asExpr() = call.getQualifier() and argIdx = -1
|
|
||||||
) and
|
|
||||||
input = AutomodelJavaUtil::getArgumentForIndex(argIdx) and
|
|
||||||
package = callable.getDeclaringType().getPackage().getName() and
|
package = callable.getDeclaringType().getPackage().getName() and
|
||||||
// we're using the erased types because the MaD convention is to not specify type parameters.
|
// we're using the erased types because the MaD convention is to not specify type parameters.
|
||||||
// Whether something is or isn't a sink doesn't usually depend on the type parameters.
|
// Whether something is or isn't a sink doesn't usually depend on the type parameters.
|
||||||
type = callable.getDeclaringType().getErasure().(RefType).nestedName() and
|
type = callable.getDeclaringType().getErasure().(RefType).nestedName() and
|
||||||
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
|
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
|
||||||
name = callable.getName() and
|
name = callable.getName() and
|
||||||
signature = ExternalFlow::paramsString(callable)
|
signature = ExternalFlow::paramsString(callable) and
|
||||||
|
if e instanceof ImplicitVarargsArray
|
||||||
|
then isVarargsArray = "true"
|
||||||
|
else isVarargsArray = "false"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,28 +313,10 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
|
||||||
IsMaDTaintStepCharacteristic() { this = "taint step" }
|
IsMaDTaintStepCharacteristic() { this = "taint step" }
|
||||||
|
|
||||||
override predicate appliesToEndpoint(Endpoint e) {
|
override predicate appliesToEndpoint(Endpoint e) {
|
||||||
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e, _, _) or
|
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _) or
|
||||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e, _, _) or
|
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _) or
|
||||||
FlowSummaryImpl::Private::Steps::summaryGetterStep(e, _, _, _) or
|
FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _) or
|
||||||
FlowSummaryImpl::Private::Steps::summarySetterStep(e, _, _, _)
|
FlowSummaryImpl::Private::Steps::summarySetterStep(e.asNode(), _, _, _)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A negative characteristic that filters out qualifiers that are classes (i.e. static calls). These
|
|
||||||
* are unlikely to have any non-trivial flow going into them.
|
|
||||||
*
|
|
||||||
* Technically, an accessed type _could_ come from outside of the source code, but there's not
|
|
||||||
* much likelihood of that being user-controlled.
|
|
||||||
*/
|
|
||||||
private class ClassQualifierCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
|
|
||||||
ClassQualifierCharacteristic() { this = "class qualifier" }
|
|
||||||
|
|
||||||
override predicate appliesToEndpoint(Endpoint e) {
|
|
||||||
exists(Call c |
|
|
||||||
e.asExpr() = c.getQualifier() and
|
|
||||||
c.getQualifier() instanceof TypeAccess
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +393,7 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
|
||||||
private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
|
private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
|
||||||
FunctionValueCharacteristic() { this = "function value" }
|
FunctionValueCharacteristic() { this = "function value" }
|
||||||
|
|
||||||
override predicate appliesToEndpoint(Endpoint e) { e.asExpr() instanceof FunctionalExpr }
|
override predicate appliesToEndpoint(Endpoint e) { e.asNode().asExpr() instanceof FunctionalExpr }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -371,12 +413,12 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
|
||||||
* Holds if the node `n` is known as the predecessor in a modeled flow step.
|
* Holds if the node `n` is known as the predecessor in a modeled flow step.
|
||||||
*/
|
*/
|
||||||
private predicate isKnownOutNodeForStep(Endpoint e) {
|
private predicate isKnownOutNodeForStep(Endpoint e) {
|
||||||
e.asExpr() instanceof Call or // we just assume flow in that case
|
e.asNode().asExpr() instanceof Call or // we just assume flow in that case
|
||||||
TaintTracking::localTaintStep(_, e) or
|
TaintTracking::localTaintStep(_, e.asNode()) or
|
||||||
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(_, e, _) or
|
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(_, e.asNode(), _) or
|
||||||
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(_, e, _) or
|
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(_, e.asNode(), _) or
|
||||||
FlowSummaryImpl::Private::Steps::summaryGetterStep(_, _, e, _) or
|
FlowSummaryImpl::Private::Steps::summaryGetterStep(_, _, e.asNode(), _) or
|
||||||
FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e, _)
|
FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e.asNode(), _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,16 +25,18 @@ private import AutomodelJavaUtil
|
||||||
bindingset[limit]
|
bindingset[limit]
|
||||||
private Endpoint getSampleForSignature(
|
private Endpoint getSampleForSignature(
|
||||||
int limit, string package, string type, string subtypes, string name, string signature,
|
int limit, string package, string type, string subtypes, string name, string signature,
|
||||||
string input
|
string input, string isVarargs
|
||||||
) {
|
) {
|
||||||
exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
|
exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
|
||||||
num_endpoints =
|
num_endpoints =
|
||||||
count(Endpoint e | meta.hasMetadata(e, package, type, subtypes, name, signature, input))
|
count(Endpoint e |
|
||||||
|
meta.hasMetadata(e, package, type, subtypes, name, signature, input, isVarargs)
|
||||||
|
)
|
||||||
|
|
|
|
||||||
result =
|
result =
|
||||||
rank[n](Endpoint e, Location loc |
|
rank[n](Endpoint e, Location loc |
|
||||||
loc = e.getLocation() and
|
loc = e.asTop().getLocation() and
|
||||||
meta.hasMetadata(e, package, type, subtypes, name, signature, input)
|
meta.hasMetadata(e, package, type, subtypes, name, signature, input, isVarargs)
|
||||||
|
|
|
|
||||||
e
|
e
|
||||||
order by
|
order by
|
||||||
|
@ -53,19 +55,20 @@ private Endpoint getSampleForSignature(
|
||||||
from
|
from
|
||||||
Endpoint endpoint, string message, ApplicationModeMetadataExtractor meta, DollarAtString package,
|
Endpoint endpoint, string message, ApplicationModeMetadataExtractor meta, DollarAtString package,
|
||||||
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
|
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
|
||||||
DollarAtString input
|
DollarAtString input, DollarAtString isVarargsArray
|
||||||
where
|
where
|
||||||
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
|
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
|
||||||
u.appliesToEndpoint(endpoint)
|
u.appliesToEndpoint(endpoint)
|
||||||
) and
|
) and
|
||||||
endpoint = getSampleForSignature(9, package, type, subtypes, name, signature, input) and
|
endpoint =
|
||||||
|
getSampleForSignature(9, package, type, subtypes, name, signature, input, isVarargsArray) and
|
||||||
// If a node is already a known sink for any of our existing ATM queries and is already modeled as a MaD sink, we
|
// If a node is already a known sink for any of our existing ATM queries and is already modeled as a MaD sink, we
|
||||||
// don't include it as a candidate. Otherwise, we might include it as a candidate for query A, but the model will
|
// don't include it as a candidate. Otherwise, we might include it as a candidate for query A, but the model will
|
||||||
// label it as a sink for one of the sink types of query B, for which it's already a known sink. This would result in
|
// label it as a sink for one of the sink types of query B, for which it's already a known sink. This would result in
|
||||||
// overlap between our detected sinks and the pre-existing modeling. We assume that, if a sink has already been
|
// overlap between our detected sinks and the pre-existing modeling. We assume that, if a sink has already been
|
||||||
// modeled in a MaD model, then it doesn't belong to any additional sink types, and we don't need to reexamine it.
|
// modeled in a MaD model, then it doesn't belong to any additional sink types, and we don't need to reexamine it.
|
||||||
not CharacteristicsImpl::isSink(endpoint, _, _) and
|
not CharacteristicsImpl::isSink(endpoint, _, _) and
|
||||||
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input) and
|
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
|
||||||
includeAutomodelCandidate(package, type, name, signature) and
|
includeAutomodelCandidate(package, type, name, signature) and
|
||||||
// The message is the concatenation of all sink types for which this endpoint is known neither to be a sink nor to be
|
// The message is the concatenation of all sink types for which this endpoint is known neither to be a sink nor to be
|
||||||
// a non-sink, and we surface only endpoints that have at least one such sink type.
|
// a non-sink, and we surface only endpoints that have at least one such sink type.
|
||||||
|
@ -76,11 +79,13 @@ where
|
||||||
|
|
|
|
||||||
sinkType, ", "
|
sinkType, ", "
|
||||||
)
|
)
|
||||||
select endpoint, message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@.", //
|
select endpoint.asNode(),
|
||||||
|
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
|
||||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||||
package, "package", //
|
package, "package", //
|
||||||
type, "type", //
|
type, "type", //
|
||||||
subtypes, "subtypes", //
|
subtypes, "subtypes", //
|
||||||
name, "name", // method name
|
name, "name", // method name
|
||||||
signature, "signature", //
|
signature, "signature", //
|
||||||
input, "input" //
|
input, "input", //
|
||||||
|
isVarargsArray, "isVarargsArray"
|
||||||
|
|
|
@ -24,7 +24,7 @@ Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) {
|
||||||
exists(int n, int num_endpoints | num_endpoints = count(Endpoint e | c.appliesToEndpoint(e)) |
|
exists(int n, int num_endpoints | num_endpoints = count(Endpoint e | c.appliesToEndpoint(e)) |
|
||||||
result =
|
result =
|
||||||
rank[n](Endpoint e, Location loc |
|
rank[n](Endpoint e, Location loc |
|
||||||
loc = e.getLocation() and c.appliesToEndpoint(e)
|
loc = e.asTop().getLocation() and c.appliesToEndpoint(e)
|
||||||
|
|
|
|
||||||
e
|
e
|
||||||
order by
|
order by
|
||||||
|
@ -43,7 +43,8 @@ Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) {
|
||||||
from
|
from
|
||||||
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
|
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
|
||||||
ApplicationModeMetadataExtractor meta, DollarAtString package, DollarAtString type,
|
ApplicationModeMetadataExtractor meta, DollarAtString package, DollarAtString type,
|
||||||
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input
|
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
|
||||||
|
DollarAtString isVarargsArray
|
||||||
where
|
where
|
||||||
endpoint = getSampleForCharacteristic(characteristic, 100) and
|
endpoint = getSampleForCharacteristic(characteristic, 100) and
|
||||||
confidence >= SharedCharacteristics::highConfidence() and
|
confidence >= SharedCharacteristics::highConfidence() and
|
||||||
|
@ -51,7 +52,7 @@ where
|
||||||
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
|
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
|
||||||
// certain about in the prompt.
|
// certain about in the prompt.
|
||||||
not erroneousEndpoints(endpoint, _, _, _, _, false) and
|
not erroneousEndpoints(endpoint, _, _, _, _, false) and
|
||||||
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input) and
|
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
|
||||||
// It's valid for a node to satisfy the logic for both `isSink` and `isSanitizer`, but in that case it will be
|
// It's valid for a node to satisfy the logic for both `isSink` and `isSanitizer`, but in that case it will be
|
||||||
// treated by the actual query as a sanitizer, since the final logic is something like
|
// treated by the actual query as a sanitizer, since the final logic is something like
|
||||||
// `isSink(n) and not isSanitizer(n)`. We don't want to include such nodes as negative examples in the prompt, because
|
// `isSink(n) and not isSanitizer(n)`. We don't want to include such nodes as negative examples in the prompt, because
|
||||||
|
@ -63,11 +64,13 @@ where
|
||||||
characteristic2.hasImplications(positiveType, true, confidence2)
|
characteristic2.hasImplications(positiveType, true, confidence2)
|
||||||
) and
|
) and
|
||||||
message = characteristic
|
message = characteristic
|
||||||
select endpoint, message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@.", //
|
select endpoint.asNode(),
|
||||||
|
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
|
||||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||||
package, "package", //
|
package, "package", //
|
||||||
type, "type", //
|
type, "type", //
|
||||||
subtypes, "subtypes", //
|
subtypes, "subtypes", //
|
||||||
name, "name", //
|
name, "name", //
|
||||||
signature, "signature", //
|
signature, "signature", //
|
||||||
input, "input" //
|
input, "input", //
|
||||||
|
isVarargsArray, "isVarargsArray" //
|
||||||
|
|
|
@ -15,19 +15,22 @@ private import AutomodelJavaUtil
|
||||||
from
|
from
|
||||||
Endpoint endpoint, SinkType sinkType, ApplicationModeMetadataExtractor meta,
|
Endpoint endpoint, SinkType sinkType, ApplicationModeMetadataExtractor meta,
|
||||||
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
|
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
|
||||||
DollarAtString signature, DollarAtString input
|
DollarAtString signature, DollarAtString input, DollarAtString isVarargsArray
|
||||||
where
|
where
|
||||||
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
|
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
|
||||||
// certain about in the prompt.
|
// certain about in the prompt.
|
||||||
not erroneousEndpoints(endpoint, _, _, _, _, false) and
|
not erroneousEndpoints(endpoint, _, _, _, _, false) and
|
||||||
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input) and
|
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
|
||||||
// Extract positive examples of sinks belonging to the existing ATM query configurations.
|
// Extract positive examples of sinks belonging to the existing ATM query configurations.
|
||||||
CharacteristicsImpl::isKnownSink(endpoint, sinkType)
|
CharacteristicsImpl::isKnownSink(endpoint, sinkType) and
|
||||||
select endpoint, sinkType + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@.", //
|
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
|
||||||
|
select endpoint.asNode(),
|
||||||
|
sinkType + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
|
||||||
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
|
||||||
package, "package", //
|
package, "package", //
|
||||||
type, "type", //
|
type, "type", //
|
||||||
subtypes, "subtypes", //
|
subtypes, "subtypes", //
|
||||||
name, "name", //
|
name, "name", //
|
||||||
signature, "signature", //
|
signature, "signature", //
|
||||||
input, "input" //
|
input, "input", //
|
||||||
|
isVarargsArray, "isVarargsArray"
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
| Test.java:16:3:16:11 | reference | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:16:3:16:24 | set(...) | CallContext | file://java.util.concurrent.atomic:1:1:1:1 | java.util.concurrent.atomic | package | file://AtomicReference:1:1:1:1 | AtomicReference | type | file://false:1:1:1:1 | false | subtypes | file://set:1:1:1:1 | set | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input |
|
| Test.java:16:3:16:11 | reference | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:16:3:16:24 | set(...) | CallContext | file://java.util.concurrent.atomic:1:1:1:1 | java.util.concurrent.atomic | package | file://AtomicReference:1:1:1:1 | AtomicReference | type | file://false:1:1:1:1 | false | subtypes | file://set:1:1:1:1 | set | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
| Test.java:21:3:21:10 | supplier | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:21:3:21:16 | get(...) | CallContext | file://java.util.function:1:1:1:1 | java.util.function | package | file://Supplier:1:1:1:1 | Supplier | type | file://true:1:1:1:1 | true | subtypes | file://get:1:1:1:1 | get | name | file://():1:1:1:1 | () | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input |
|
| Test.java:21:3:21:10 | supplier | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:21:3:21:16 | get(...) | CallContext | file://java.util.function:1:1:1:1 | java.util.function | package | file://Supplier:1:1:1:1 | Supplier | type | file://true:1:1:1:1 | true | subtypes | file://get:1:1:1:1 | get | name | file://():1:1:1:1 | () | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
|
| Test.java:53:4:53:4 | o | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:51:3:56:3 | walk(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://walk:1:1:1:1 | walk | name | file://(Path,FileVisitOption[]):1:1:1:1 | (Path,FileVisitOption[]) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input | file://true:1:1:1:1 | true | isVarargsArray |
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
| Test.java:40:14:40:21 | openPath | taint step\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:40:4:40:22 | get(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Paths:1:1:1:1 | Paths | type | file://false:1:1:1:1 | false | subtypes | file://get:1:1:1:1 | get | name | file://(String,String[]):1:1:1:1 | (String,String[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
|
| Test.java:46:4:46:5 | f2 | known non-sink\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:45:10:47:3 | compareTo(...) | CallContext | file://java.io:1:1:1:1 | java.io | package | file://File:1:1:1:1 | File | type | file://true:1:1:1:1 | true | subtypes | file://compareTo:1:1:1:1 | compareTo | name | file://(File):1:1:1:1 | (File) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
| Test.java:46:4:46:5 | f2 | known non-sink\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:45:10:47:3 | compareTo(...) | CallContext | file://java.io:1:1:1:1 | java.io | package | file://File:1:1:1:1 | File | type | file://true:1:1:1:1 | true | subtypes | file://compareTo:1:1:1:1 | compareTo | name | file://(File):1:1:1:1 | (File) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
|
| Test.java:52:4:52:4 | p | taint step\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:51:3:56:3 | walk(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://walk:1:1:1:1 | walk | name | file://(Path,FileVisitOption[]):1:1:1:1 | (Path,FileVisitOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
| Test.java:26:4:26:9 | source | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
|
| Test.java:26:4:26:9 | source | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
| Test.java:27:4:27:9 | target | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input |
|
| Test.java:27:4:27:9 | target | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:25:3:29:3 | copy(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://copy:1:1:1:1 | copy | name | file://(Path,Path,CopyOption[]):1:1:1:1 | (Path,Path,CopyOption[]) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
| Test.java:34:4:34:11 | openPath | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@. | Test.java:33:10:35:3 | newInputStream(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://newInputStream:1:1:1:1 | newInputStream | name | file://(Path,OpenOption[]):1:1:1:1 | (Path,OpenOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input |
|
| Test.java:34:4:34:11 | openPath | path-injection\nrelated locations: $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | Test.java:33:10:35:3 | newInputStream(...) | CallContext | file://java.nio.file:1:1:1:1 | java.nio.file | package | file://Files:1:1:1:1 | Files | type | file://false:1:1:1:1 | false | subtypes | file://newInputStream:1:1:1:1 | newInputStream | name | file://(Path,OpenOption[]):1:1:1:1 | (Path,OpenOption[]) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://false:1:1:1:1 | false | isVarargsArray |
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.nio.file.Paths;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.FileVisitOption;
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
@ -46,5 +46,14 @@ class Test {
|
||||||
f2 // negative example (modeled as not a sink)
|
f2 // negative example (modeled as not a sink)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
|
||||||
|
Files.walk(
|
||||||
|
p, // negative example (modeled as a taint step)
|
||||||
|
o, // the implicit varargs array is a candidate
|
||||||
|
o // not a candidate (only the first arg corresponding to a varargs array
|
||||||
|
// is extracted)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче