Java: Automodel application mode: include candidates that are useful for regression testing

This commit is contained in:
Stephan Brandauer
2023-08-14 11:46:40 +02:00
parent 1a95a34441
commit 551b34e3be
5 changed files with 27 additions and 18 deletions

View File

@@ -55,7 +55,7 @@ private Endpoint getSampleForSignature(
from
Endpoint endpoint, string message, ApplicationModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString isVarargsArray
DollarAtString input, DollarAtString isVarargsArray, DollarAtString alreadyAiModeled
where
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
@@ -67,20 +67,25 @@ where
// 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
// 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 alreadyAiModeled = "false"
or
CharacteristicsImpl::isSink(endpoint, _, any(string s | s.matches("%ai-%"))) and
alreadyAiModeled = "true"
) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) 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
// a non-sink, and we surface only endpoints that have at least one such sink type.
message =
strictconcat(AutomodelEndpointTypes::SinkType sinkType |
not CharacteristicsImpl::isKnownSink(endpoint, sinkType) and
not CharacteristicsImpl::isKnownSink(endpoint, sinkType, _) and
CharacteristicsImpl::isSinkCandidate(endpoint, sinkType)
|
sinkType, ", "
)
select endpoint.asNode(),
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
package, "package", //
type, "type", //
@@ -88,4 +93,5 @@ select endpoint.asNode(),
name, "name", // method name
signature, "signature", //
input, "input", //
isVarargsArray, "isVarargsArray"
isVarargsArray, "isVarargsArray", //
alreadyAiModeled, "alreadyAiModeled"

View File

@@ -22,7 +22,7 @@ where
not erroneousEndpoints(endpoint, _, _, _, _, false) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
// Extract positive examples of sinks belonging to the existing ATM query configurations.
CharacteristicsImpl::isKnownSink(endpoint, sinkType) and
CharacteristicsImpl::isKnownSink(endpoint, sinkType, _) and
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
select endpoint.asNode(),
sinkType + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //

View File

@@ -94,14 +94,15 @@ module SharedCharacteristics<CandidateSig Candidate> {
/**
* Holds if `sink` is a known sink of type `endpointType`.
*/
predicate isKnownSink(Candidate::Endpoint sink, Candidate::EndpointType endpointType) {
predicate isKnownSink(
Candidate::Endpoint sink, Candidate::EndpointType endpointType,
EndpointCharacteristic characteristic
) {
// If the list of characteristics includes positive indicators with maximal confidence for this class, then it's a
// known sink for the class.
not endpointType instanceof Candidate::NegativeEndpointType and
exists(EndpointCharacteristic characteristic |
characteristic.appliesToEndpoint(sink) and
characteristic.hasImplications(endpointType, true, maximalConfidence())
)
characteristic.appliesToEndpoint(sink) and
characteristic.hasImplications(endpointType, true, maximalConfidence())
}
/**
@@ -275,15 +276,17 @@ module SharedCharacteristics<CandidateSig Candidate> {
private class KnownSinkCharacteristic extends SinkCharacteristic {
string madKind;
Candidate::EndpointType endpointType;
string provenance;
KnownSinkCharacteristic() {
Candidate::isKnownKind(madKind, endpointType) and
// bind "this" to a unique string differing from that of the SinkType classes
this = madKind + "-characteristic"
this = madKind + "_" + provenance + "_characteristic" and
Candidate::isSink(_, madKind, provenance)
}
override predicate appliesToEndpoint(Candidate::Endpoint e) {
Candidate::isSink(e, madKind, _)
Candidate::isSink(e, madKind, provenance)
}
override Candidate::EndpointType getSinkType() { result = endpointType }

View File

@@ -1,3 +1,4 @@
| 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 | 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 |
| 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 | file://false:1:1:1:1 | false | alreadyAiModeled |
| 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 | file://false:1:1:1:1 | false | alreadyAiModeled |
| Test.java:34:4:34:11 | openPath | command-injection, request-forgery, sql-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 | file://true:1:1:1:1 | true | alreadyAiModeled |
| 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 | file://false:1:1:1:1 | false | alreadyAiModeled |

View File

@@ -31,7 +31,7 @@ class Test {
public static InputStream getInputStream(Path openPath) throws Exception {
return Files.newInputStream(
openPath // positive example (known sink)
openPath // positive example (known sink), candidate ("only" ai-modeled, and useful as a candidate in regression testing)
);
}
@@ -56,4 +56,3 @@ class Test {
);
}
}