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:
Stephan Brandauer 2023-08-16 08:49:01 +02:00 коммит произвёл GitHub
Родитель b8372c2f95 1a95a34441
Коммит 20254c3d0a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
8 изменённых файлов: 162 добавлений и 99 удалений

Просмотреть файл

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