Merge branch 'main' into henrymercer/rc-3.11-mergeback

This commit is contained in:
Henry Mercer
2023-10-03 16:30:23 +01:00
1450 changed files with 135236 additions and 95589 deletions

View File

@@ -96,7 +96,7 @@ class PotentialSinkModelExpr extends Expr {
or
this = call.getQualifier() and argIdx = -1
) and
input = getArgumentForIndex(argIdx) and
(if argIdx = -1 then input = "Argument[this]" else input = "Argument[" + argIdx + "]") and
package = callable.getDeclaringType().getPackage().getName() and
type = callable.getDeclaringType().getErasure().(RefType).nestedName() and
subtypes = considerSubtypes(callable) and

View File

@@ -19,7 +19,10 @@ private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
import AutomodelSharedCharacteristics as SharedCharacteristics
import AutomodelEndpointTypes as AutomodelEndpointTypes
newtype JavaRelatedLocationType = CallContext()
newtype JavaRelatedLocationType =
CallContext() or
MethodDoc() or
ClassDoc()
newtype TApplicationModeEndpoint =
TExplicitArgument(Call call, DataFlow::Node arg) {
@@ -35,22 +38,54 @@ newtype TApplicationModeEndpoint =
argExpr.isVararg() and
not exists(int i | i < idx and call.getArgument(i).(Argument).isVararg())
)
} or
TMethodReturnValue(Call call) { not call instanceof ConstructorCall } or
TOverriddenParameter(Parameter p, Method overriddenMethod) {
not p.getCallable().callsConstructor(_) and
p.getCallable().(Method).overrides(overriddenMethod)
}
/**
* An endpoint is a node that is a candidate for modeling.
*/
abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint {
abstract predicate isArgOf(Call c, int idx);
/**
* Gets the callable to be modeled that this endpoint represents.
*/
abstract Callable getCallable();
Call getCall() { this.isArgOf(result, _) }
abstract Call getCall();
int getArgIndex() { this.isArgOf(_, result) }
/**
* Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
*
* For endpoints that are source candidates, this will be `none()`.
*/
abstract string getMaDInput();
/**
* Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
*
* For endpoints that are sink candidates, this will be `none()`.
*/
abstract string getMaDOutput();
abstract Top asTop();
/**
* Converts the endpoint to a node that can be used in a data flow graph.
*/
abstract DataFlow::Node asNode();
string getExtensibleType() {
if not exists(this.getMaDInput()) and exists(this.getMaDOutput())
then result = "sourceModel"
else
if exists(this.getMaDInput()) and not exists(this.getMaDOutput())
then result = "sinkModel"
else none() // if both exist, it would be a summaryModel (not yet supported)
}
abstract string toString();
}
@@ -63,7 +98,15 @@ class ExplicitArgument extends ApplicationModeEndpoint, TExplicitArgument {
ExplicitArgument() { this = TExplicitArgument(call, arg) }
override predicate isArgOf(Call c, int idx) { c = call and this.asTop() = c.getArgument(idx) }
override Callable getCallable() { result = call.getCallee() }
override Call getCall() { result = call }
private int getArgIndex() { this.asTop() = call.getArgument(result) }
override string getMaDInput() { result = "Argument[" + this.getArgIndex() + "]" }
override string getMaDOutput() { none() }
override Top asTop() { result = arg.asExpr() }
@@ -78,9 +121,13 @@ class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
InstanceArgument() { this = TInstanceArgument(call, arg) }
override predicate isArgOf(Call c, int idx) {
c = call and this.asTop() = c.getQualifier() and idx = -1
}
override Callable getCallable() { result = call.getCallee() }
override Call getCall() { result = call }
override string getMaDInput() { result = "Argument[this]" }
override string getMaDOutput() { none() }
override Top asTop() { if exists(arg.asExpr()) then result = arg.asExpr() else result = call }
@@ -105,15 +152,78 @@ class ImplicitVarargsArray extends ApplicationModeEndpoint, TImplicitVarargsArra
ImplicitVarargsArray() { this = TImplicitVarargsArray(call, vararg, idx) }
override predicate isArgOf(Call c, int i) { c = call and i = idx }
override Callable getCallable() { result = call.getCallee() }
override Top asTop() { result = this.getCall() }
override Call getCall() { result = call }
override string getMaDInput() { result = "Argument[" + idx + "]" }
override string getMaDOutput() { none() }
override Top asTop() { result = call }
override DataFlow::Node asNode() { result = vararg }
override string toString() { result = vararg.toString() }
}
/**
* An endpoint that represents a method call. The `ReturnValue` of a method call
* may be a source.
*/
class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue {
Call call;
MethodReturnValue() { this = TMethodReturnValue(call) }
override Callable getCallable() { result = call.getCallee() }
override Call getCall() { result = call }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "ReturnValue" }
override Top asTop() { result = call }
override DataFlow::Node asNode() { result.asExpr() = call }
override string toString() { result = call.toString() }
}
/**
* An endpoint that represents a parameter of an overridden method that may be
* a source.
*/
class OverriddenParameter extends ApplicationModeEndpoint, TOverriddenParameter {
Parameter p;
Method overriddenMethod;
OverriddenParameter() { this = TOverriddenParameter(p, overriddenMethod) }
override Callable getCallable() {
// NB: we're returning the overridden callable here. This means that the
// candidate model will be about the overridden method, not the overriding
// method. This is a more general model, that also applies to other
// subclasses of the overridden class.
result = overriddenMethod
}
override Call getCall() { none() }
private int getArgIndex() { p.getCallable().getParameter(result) = p }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "Parameter[" + this.getArgIndex() + "]" }
override Top asTop() { result = p }
override DataFlow::Node asNode() { result.(DataFlow::ParameterNode).asParameter() = p }
override string toString() { result = p.toString() }
}
/**
* A candidates implementation.
*
@@ -161,6 +271,14 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
isCustomSink(e, kind) and provenance = "custom-sink"
}
predicate isSource(Endpoint e, string kind, string provenance) {
exists(string package, string type, string name, string signature, string ext, string output |
sourceSpec(e, package, type, name, signature, ext, output) and
ExternalFlow::sourceModel(package, type, _, name, [signature, ""], ext, output, kind,
provenance)
)
}
predicate isNeutral(Endpoint e) {
exists(string package, string type, string name, string signature |
sinkSpec(e, package, type, name, signature, _, _) and
@@ -168,13 +286,24 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
)
}
// XXX how to extend to support sources?
additional predicate sinkSpec(
Endpoint e, string package, string type, string name, string signature, string ext, string input
) {
ApplicationModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(ApplicationModeGetCallable::getCallable(e)) and
e.getCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getCallable()) and
ext = "" and
input = AutomodelJavaUtil::getArgumentForIndex(e.getArgIndex())
input = e.getMaDInput()
}
additional predicate sourceSpec(
Endpoint e, string package, string type, string name, string signature, string ext,
string output
) {
e.getCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getCallable()) and
ext = "" and
output = e.getMaDOutput()
}
/**
@@ -186,6 +315,12 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
type = CallContext() and
result = e.getCall()
or
type = MethodDoc() and
result = e.getCallable().(Documentable).getJavadoc()
or
type = ClassDoc() and
result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
}
}
@@ -229,11 +364,12 @@ class ApplicationModeMetadataExtractor extends string {
predicate hasMetadata(
Endpoint e, string package, string type, string subtypes, string name, string signature,
string input, string isVarargsArray
string input, string output, string isVarargsArray
) {
exists(Callable callable |
e.getCall().getCallee() = callable and
input = AutomodelJavaUtil::getArgumentForIndex(e.getArgIndex()) and
e.getCallable() = callable and
(if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
(if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
package = callable.getDeclaringType().getPackage().getName() and
// 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.
@@ -266,8 +402,8 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::isSink(e, _, _) and
ApplicationModeGetCallable::getCallable(e).getName().matches("is%") and
ApplicationModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
e.getCallable().getName().matches("is%") and
e.getCallable().getReturnType() instanceof BooleanType
}
}
@@ -313,9 +449,13 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
IsMaDTaintStepCharacteristic() { this = "taint step" }
override predicate appliesToEndpoint(Endpoint e) {
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _) or
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _) or
FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _) or
e.getExtensibleType() = "sinkModel" and
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _)
or
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _)
or
FlowSummaryImpl::Private::Steps::summaryGetterStep(e.asNode(), _, _, _)
or
FlowSummaryImpl::Private::Steps::summarySetterStep(e.asNode(), _, _, _)
}
}
@@ -326,8 +466,8 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
* The reason is that we would expect data/taint flow into the method implementation to uncover
* any sinks that are present there.
*/
private class ArgumentToLocalCall extends CharacteristicsImpl::UninterestingToModelCharacteristic {
ArgumentToLocalCall() { this = "argument to local call" }
private class LocalCall extends CharacteristicsImpl::UninterestingToModelCharacteristic {
LocalCall() { this = "local call" }
override predicate appliesToEndpoint(Endpoint e) {
ApplicationModeGetCallable::getCallable(e).fromSource()
@@ -354,6 +494,7 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
NonPublicMethodCharacteristic() { this = "non-public method" }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
not ApplicationModeGetCallable::getCallable(e).isPublic()
}
}
@@ -376,6 +517,7 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
}
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
not ApplicationCandidatesImpl::isSink(e, _, _) and
exists(Endpoint otherSink |
ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and
@@ -393,7 +535,10 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
FunctionValueCharacteristic() { this = "function value" }
override predicate appliesToEndpoint(Endpoint e) { e.asNode().asExpr() instanceof FunctionalExpr }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
e.asNode().asExpr() instanceof FunctionalExpr
}
}
/**
@@ -407,7 +552,10 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
{
CannotBeTaintedCharacteristic() { this = "cannot be tainted" }
override predicate appliesToEndpoint(Endpoint e) { not this.isKnownOutNodeForStep(e) }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
not this.isKnownOutNodeForStep(e)
}
/**
* Holds if the node `n` is known as the predecessor in a modeled flow step.
@@ -421,72 +569,3 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
FlowSummaryImpl::Private::Steps::summarySetterStep(_, _, e.asNode(), _)
}
}
/**
* Holds if the given endpoint has a self-contradictory combination of characteristics. Detects errors in our endpoint
* characteristics. Lists the problematic characteristics and their implications for all such endpoints, together with
* an error message indicating why this combination is problematic.
*
* Copied from
* javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/ContradictoryEndpointCharacteristics.ql
*/
predicate erroneousEndpoints(
Endpoint endpoint, EndpointCharacteristic characteristic,
AutomodelEndpointTypes::EndpointType endpointType, float confidence, string errorMessage,
boolean ignoreKnownModelingErrors
) {
// An endpoint's characteristics should not include positive indicators with medium/high confidence for more than one
// sink/source type (including the negative type).
exists(
EndpointCharacteristic characteristic2, AutomodelEndpointTypes::EndpointType endpointClass2,
float confidence2
|
endpointType != endpointClass2 and
(
endpointType instanceof AutomodelEndpointTypes::SinkType and
endpointClass2 instanceof AutomodelEndpointTypes::SinkType
or
endpointType instanceof AutomodelEndpointTypes::SourceType and
endpointClass2 instanceof AutomodelEndpointTypes::SourceType
) and
characteristic.appliesToEndpoint(endpoint) and
characteristic2.appliesToEndpoint(endpoint) and
characteristic.hasImplications(endpointType, true, confidence) and
characteristic2.hasImplications(endpointClass2, true, confidence2) and
confidence > SharedCharacteristics::mediumConfidence() and
confidence2 > SharedCharacteristics::mediumConfidence() and
(
ignoreKnownModelingErrors = true and
not knownOverlappingCharacteristics(characteristic, characteristic2)
or
ignoreKnownModelingErrors = false
)
) and
errorMessage = "Endpoint has high-confidence positive indicators for multiple classes"
or
// An endpoint's characteristics should not include positive indicators with medium/high confidence for some class and
// also include negative indicators with medium/high confidence for this same class.
exists(EndpointCharacteristic characteristic2, float confidence2 |
characteristic.appliesToEndpoint(endpoint) and
characteristic2.appliesToEndpoint(endpoint) and
characteristic.hasImplications(endpointType, true, confidence) and
characteristic2.hasImplications(endpointType, false, confidence2) and
confidence > SharedCharacteristics::mediumConfidence() and
confidence2 > SharedCharacteristics::mediumConfidence()
) and
ignoreKnownModelingErrors = false and
errorMessage = "Endpoint has high-confidence positive and negative indicators for the same class"
}
/**
* Holds if `characteristic1` and `characteristic2` are among the pairs of currently known positive characteristics that
* have some overlap in their results. This indicates a problem with the underlying Java modeling. Specifically,
* `PathCreation` is prone to FPs.
*/
private predicate knownOverlappingCharacteristics(
EndpointCharacteristic characteristic1, EndpointCharacteristic characteristic2
) {
characteristic1 != characteristic2 and
characteristic1 = ["mad taint step", "create path", "read file", "known non-sink"] and
characteristic2 = ["mad taint step", "create path", "read file", "known non-sink"]
}

View File

@@ -25,18 +25,20 @@ private import AutomodelJavaUtil
bindingset[limit]
private Endpoint getSampleForSignature(
int limit, string package, string type, string subtypes, string name, string signature,
string input, string isVarargs
string input, string output, string isVarargs, string extensibleType
) {
exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
num_endpoints =
count(Endpoint e |
meta.hasMetadata(e, package, type, subtypes, name, signature, input, isVarargs)
e.getExtensibleType() = extensibleType and
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs)
)
|
result =
rank[n](Endpoint e, Location loc |
loc = e.asTop().getLocation() and
meta.hasMetadata(e, package, type, subtypes, name, signature, input, isVarargs)
e.getExtensibleType() = extensibleType and
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs)
|
e
order by
@@ -53,45 +55,43 @@ private Endpoint getSampleForSignature(
}
from
Endpoint endpoint, string message, ApplicationModeMetadataExtractor meta, DollarAtString package,
Endpoint endpoint, ApplicationModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString isVarargsArray, DollarAtString alreadyAiModeled
DollarAtString input, DollarAtString output, DollarAtString isVarargsArray,
DollarAtString alreadyAiModeled, DollarAtString extensibleType
where
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
) and
CharacteristicsImpl::isSinkCandidate(endpoint, _) 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
// 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
// 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.
getSampleForSignature(9, package, type, subtypes, name, signature, input, output,
isVarargsArray, extensibleType) and
// If a node is already modeled in MaD, we 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 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 alreadyAiModeled = ""
not CharacteristicsImpl::isModeled(endpoint, _, _, _) and alreadyAiModeled = ""
or
alreadyAiModeled.matches("%ai-%") and
CharacteristicsImpl::isSink(endpoint, _, alreadyAiModeled)
CharacteristicsImpl::isModeled(endpoint, _, _, alreadyAiModeled)
) 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
CharacteristicsImpl::isSinkCandidate(endpoint, sinkType)
|
sinkType, ", "
)
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray) and
includeAutomodelCandidate(package, type, name, signature)
select endpoint.asNode(),
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@.", //
"Related locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
type, "type", //
subtypes, "subtypes", //
name, "name", // method name
signature, "signature", //
input, "input", //
output, "output", //
isVarargsArray, "isVarargsArray", //
alreadyAiModeled, "alreadyAiModeled"
alreadyAiModeled, "alreadyAiModeled", //
extensibleType, "extensibleType"

View File

@@ -44,15 +44,13 @@ from
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
ApplicationModeMetadataExtractor meta, DollarAtString package, DollarAtString type,
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
DollarAtString isVarargsArray
DollarAtString output, DollarAtString isVarargsArray, DollarAtString extensibleType
where
endpoint = getSampleForCharacteristic(characteristic, 100) and
extensibleType = endpoint.getExtensibleType() and
confidence >= SharedCharacteristics::highConfidence() and
characteristic.hasImplications(any(NegativeSinkType negative), true, confidence) and
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
// certain about in the prompt.
not erroneousEndpoints(endpoint, _, _, _, _, false) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray) and
// 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
// `isSink(n) and not isSanitizer(n)`. We don't want to include such nodes as negative examples in the prompt, because
@@ -65,12 +63,16 @@ where
) and
message = characteristic
select endpoint.asNode(),
message + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
message + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
type, "type", //
subtypes, "subtypes", //
name, "name", //
signature, "signature", //
input, "input", //
isVarargsArray, "isVarargsArray" //
output, "output", //
isVarargsArray, "isVarargsArray", //
extensibleType, "extensibleType"

View File

@@ -13,24 +13,27 @@ private import AutomodelEndpointTypes
private import AutomodelJavaUtil
from
Endpoint endpoint, SinkType sinkType, ApplicationModeMetadataExtractor meta,
Endpoint endpoint, EndpointType endpointType, ApplicationModeMetadataExtractor meta,
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
DollarAtString signature, DollarAtString input, DollarAtString isVarargsArray
DollarAtString signature, DollarAtString input, DollarAtString output,
DollarAtString isVarargsArray, DollarAtString extensibleType
where
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
// certain about in the prompt.
not erroneousEndpoints(endpoint, _, _, _, _, false) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, isVarargsArray) and
extensibleType = endpoint.getExtensibleType() and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray) and
// Extract positive examples of sinks belonging to the existing ATM query configurations.
CharacteristicsImpl::isKnownSink(endpoint, sinkType, _) and
CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) and
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
select endpoint.asNode(),
sinkType + "\nrelated locations: $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
endpointType + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
type, "type", //
subtypes, "subtypes", //
name, "name", //
signature, "signature", //
input, "input", //
isVarargsArray, "isVarargsArray"
output, "output", //
isVarargsArray, "isVarargsArray", //
extensibleType, "extensibleType"

View File

@@ -28,12 +28,6 @@ abstract class SinkType extends EndpointType {
SinkType() { any() }
}
/** A class for source types that can be predicted by a classifier. */
abstract class SourceType extends EndpointType {
bindingset[this]
SourceType() { any() }
}
/** The `Negative` class for non-sinks. */
class NegativeSinkType extends SinkType {
NegativeSinkType() { this = "non-sink" }
@@ -58,3 +52,14 @@ class RequestForgerySinkType extends SinkType {
class CommandInjectionSinkType extends SinkType {
CommandInjectionSinkType() { this = "command-injection" }
}
/** A class for source types that can be predicted by a classifier. */
abstract class SourceType extends EndpointType {
bindingset[this]
SourceType() { any() }
}
/** A source of remote data. */
class RemoteSourceType extends SourceType {
RemoteSourceType() { this = "remote" }
}

View File

@@ -25,16 +25,39 @@ newtype JavaRelatedLocationType =
newtype TFrameworkModeEndpoint =
TExplicitParameter(Parameter p) or
TQualifier(Callable c)
TQualifier(Callable c) or
TReturnValue(Callable c) or
TOverridableParameter(Method m, Parameter p) {
p.getCallable() = m and
m instanceof ModelExclusions::ModelApi and
not m.getDeclaringType().isFinal() and
not m.isFinal() and
not m.isStatic()
} or
TOverridableQualifier(Method m) {
m instanceof ModelExclusions::ModelApi and
not m.getDeclaringType().isFinal() and
not m.isFinal() and
not m.isStatic()
}
/**
* A framework mode endpoint.
*/
abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
/**
* Returns the parameter index of the endpoint.
* Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
*
* For endpoints that are source candidates, this will be `none()`.
*/
abstract int getIndex();
abstract string getMaDInput();
/**
* Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
*
* For endpoints that are sink candidates, this will be `none()`.
*/
abstract string getMaDOutput();
/**
* Returns the name of the parameter of the endpoint.
@@ -48,6 +71,8 @@ abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
abstract Top asTop();
abstract string getExtensibleType();
string toString() { result = this.asTop().toString() }
Location getLocation() { result = this.asTop().getLocation() }
@@ -58,13 +83,17 @@ class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParamete
ExplicitParameterEndpoint() { this = TExplicitParameter(param) and param.fromSource() }
override int getIndex() { result = param.getPosition() }
override string getMaDInput() { result = "Argument[" + param.getPosition() + "]" }
override string getMaDOutput() { none() }
override string getParamName() { result = param.getName() }
override Callable getEnclosingCallable() { result = param.getCallable() }
override Top asTop() { result = param }
override string getExtensibleType() { result = "sinkModel" }
}
class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
@@ -74,13 +103,72 @@ class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
this = TQualifier(callable) and not callable.isStatic() and callable.fromSource()
}
override int getIndex() { result = -1 }
override string getMaDInput() { result = "Argument[this]" }
override string getMaDOutput() { none() }
override string getParamName() { result = "this" }
override Callable getEnclosingCallable() { result = callable }
override Top asTop() { result = callable }
override string getExtensibleType() { result = "sinkModel" }
}
class ReturnValue extends FrameworkModeEndpoint, TReturnValue {
Callable callable;
ReturnValue() { this = TReturnValue(callable) and callable.fromSource() }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "ReturnValue" }
override string getParamName() { none() }
override Callable getEnclosingCallable() { result = callable }
override Top asTop() { result = callable }
override string getExtensibleType() { result = "sourceModel" }
}
class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter {
Method method;
Parameter param;
OverridableParameter() { this = TOverridableParameter(method, param) }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "Parameter[" + param.getPosition() + "]" }
override string getParamName() { result = param.getName() }
override Callable getEnclosingCallable() { result = method }
override Top asTop() { result = param }
override string getExtensibleType() { result = "sourceModel" }
}
class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier {
Method m;
OverridableQualifier() { this = TOverridableQualifier(m) }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "Parameter[this]" }
override string getParamName() { result = "this" }
override Callable getEnclosingCallable() { result = m }
override Top asTop() { result = m }
override string getExtensibleType() { result = "sourceModel" }
}
/**
@@ -117,9 +205,21 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
)
}
predicate isSource(Endpoint e, string kind, string provenance) {
exists(string package, string type, string name, string signature, string ext, string output |
sourceSpec(e, package, type, name, signature, ext, output) and
ExternalFlow::sourceModel(package, type, _, name, [signature, ""], ext, output, kind,
provenance)
)
}
predicate isNeutral(Endpoint e) {
exists(string package, string type, string name, string signature |
sinkSpec(e, package, type, name, signature, _, _) and
(
sinkSpec(e, package, type, name, signature, _, _)
or
sourceSpec(e, package, type, name, signature, _, _)
) and
ExternalFlow::neutralModel(package, type, name, [signature, ""], "sink", _)
)
}
@@ -127,10 +227,20 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
additional predicate sinkSpec(
Endpoint e, string package, string type, string name, string signature, string ext, string input
) {
FrameworkModeGetCallable::getCallable(e).hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(FrameworkModeGetCallable::getCallable(e)) and
e.getEnclosingCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getEnclosingCallable()) and
ext = "" and
input = AutomodelJavaUtil::getArgumentForIndex(e.getIndex())
input = e.getMaDInput()
}
additional predicate sourceSpec(
Endpoint e, string package, string type, string name, string signature, string ext,
string output
) {
e.getEnclosingCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getEnclosingCallable()) and
ext = "" and
output = e.getMaDOutput()
}
/**
@@ -140,28 +250,13 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
*/
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
type = MethodDoc() and
result = FrameworkModeGetCallable::getCallable(e).(Documentable).getJavadoc()
result = e.getEnclosingCallable().(Documentable).getJavadoc()
or
type = ClassDoc() and
result = FrameworkModeGetCallable::getCallable(e).getDeclaringType().(Documentable).getJavadoc()
result = e.getEnclosingCallable().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.
*
* Each Java mode should implement this predicate.
*/
Callable getCallable(Endpoint e) { result = e.getEnclosingCallable() }
}
module CharacteristicsImpl = SharedCharacteristics::SharedCharacteristics<FrameworkCandidatesImpl>;
class EndpointCharacteristic = CharacteristicsImpl::EndpointCharacteristic;
@@ -180,11 +275,12 @@ class FrameworkModeMetadataExtractor extends string {
predicate hasMetadata(
Endpoint e, string package, string type, string subtypes, string name, string signature,
string input, string parameterName
string input, string output, string parameterName
) {
parameterName = e.getParamName() and
(if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and
name = e.getEnclosingCallable().getName() and
input = AutomodelJavaUtil::getArgumentForIndex(e.getIndex()) and
(if exists(e.getMaDInput()) then input = e.getMaDInput() else input = "") and
(if exists(e.getMaDOutput()) then output = e.getMaDOutput() else output = "") and
package = e.getEnclosingCallable().getDeclaringType().getPackage().getName() and
type = e.getEnclosingCallable().getDeclaringType().getErasure().(RefType).nestedName() and
subtypes = AutomodelJavaUtil::considerSubtypes(e.getEnclosingCallable()).toString() and
@@ -210,8 +306,8 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _, _) and
FrameworkModeGetCallable::getCallable(e).getName().matches("is%") and
FrameworkModeGetCallable::getCallable(e).getReturnType() instanceof BooleanType
e.getEnclosingCallable().getName().matches("is%") and
e.getEnclosingCallable().getReturnType() instanceof BooleanType
}
}
@@ -229,7 +325,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _, _) and
exists(Callable callable |
callable = FrameworkModeGetCallable::getCallable(e) and
callable = e.getEnclosingCallable() and
callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType
)
@@ -243,8 +339,7 @@ private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkChara
ExceptionCharacteristic() { this = "exception" }
override predicate appliesToEndpoint(Endpoint e) {
FrameworkModeGetCallable::getCallable(e).getDeclaringType().getASupertype*() instanceof
TypeThrowable
e.getEnclosingCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable
}
}
@@ -252,92 +347,10 @@ private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkChara
* A characteristic that limits candidates to parameters of methods that are recognized as `ModelApi`, iow., APIs that
* are considered worth modeling.
*/
private class NotAModelApiParameter extends CharacteristicsImpl::UninterestingToModelCharacteristic {
NotAModelApiParameter() { this = "not a model API parameter" }
private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelCharacteristic {
NotAModelApi() { this = "not a model API" }
override predicate appliesToEndpoint(Endpoint e) {
not e.getEnclosingCallable() instanceof ModelExclusions::ModelApi
}
}
/**
* A negative characteristic that filters out non-public methods. Non-public methods are not interesting to include in
* the standard Java modeling, because they cannot be called from outside the package.
*/
private class NonPublicMethodCharacteristic extends CharacteristicsImpl::UninterestingToModelCharacteristic
{
NonPublicMethodCharacteristic() { this = "non-public method" }
override predicate appliesToEndpoint(Endpoint e) {
not FrameworkModeGetCallable::getCallable(e).isPublic()
}
}
/**
* Holds if the given endpoint has a self-contradictory combination of characteristics. Detects errors in our endpoint
* characteristics. Lists the problematic characteristics and their implications for all such endpoints, together with
* an error message indicating why this combination is problematic.
*
* Copied from
* javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/ContradictoryEndpointCharacteristics.ql
*/
predicate erroneousEndpoints(
Endpoint endpoint, EndpointCharacteristic characteristic,
AutomodelEndpointTypes::EndpointType endpointType, float confidence, string errorMessage,
boolean ignoreKnownModelingErrors
) {
// An endpoint's characteristics should not include positive indicators with medium/high confidence for more than one
// sink/source type (including the negative type).
exists(
EndpointCharacteristic characteristic2, AutomodelEndpointTypes::EndpointType endpointClass2,
float confidence2
|
endpointType != endpointClass2 and
(
endpointType instanceof AutomodelEndpointTypes::SinkType and
endpointClass2 instanceof AutomodelEndpointTypes::SinkType
or
endpointType instanceof AutomodelEndpointTypes::SourceType and
endpointClass2 instanceof AutomodelEndpointTypes::SourceType
) and
characteristic.appliesToEndpoint(endpoint) and
characteristic2.appliesToEndpoint(endpoint) and
characteristic.hasImplications(endpointType, true, confidence) and
characteristic2.hasImplications(endpointClass2, true, confidence2) and
confidence > SharedCharacteristics::mediumConfidence() and
confidence2 > SharedCharacteristics::mediumConfidence() and
(
ignoreKnownModelingErrors = true and
not knownOverlappingCharacteristics(characteristic, characteristic2)
or
ignoreKnownModelingErrors = false
)
) and
errorMessage = "Endpoint has high-confidence positive indicators for multiple classes"
or
// An endpoint's characteristics should not include positive indicators with medium/high confidence for some class and
// also include negative indicators with medium/high confidence for this same class.
exists(EndpointCharacteristic characteristic2, float confidence2 |
characteristic.appliesToEndpoint(endpoint) and
characteristic2.appliesToEndpoint(endpoint) and
characteristic.hasImplications(endpointType, true, confidence) and
characteristic2.hasImplications(endpointType, false, confidence2) and
confidence > SharedCharacteristics::mediumConfidence() and
confidence2 > SharedCharacteristics::mediumConfidence()
) and
ignoreKnownModelingErrors = false and
errorMessage = "Endpoint has high-confidence positive and negative indicators for the same class"
}
/**
* Holds if `characteristic1` and `characteristic2` are among the pairs of currently known positive characteristics that
* have some overlap in their results. This indicates a problem with the underlying Java modeling. Specifically,
* `PathCreation` is prone to FPs.
*/
private predicate knownOverlappingCharacteristics(
EndpointCharacteristic characteristic1, EndpointCharacteristic characteristic2
) {
characteristic1 != characteristic2 and
characteristic1 = ["mad taint step", "create path", "read file", "known non-sink"] and
characteristic2 = ["mad taint step", "create path", "read file", "known non-sink"]
}

View File

@@ -16,13 +16,16 @@ private import AutomodelFrameworkModeCharacteristics
private import AutomodelJavaUtil
from
Endpoint endpoint, string message, FrameworkModeMetadataExtractor meta, DollarAtString package,
Endpoint endpoint, FrameworkModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString parameterName, DollarAtString alreadyAiModeled
DollarAtString input, DollarAtString output, DollarAtString parameterName,
DollarAtString alreadyAiModeled, DollarAtString extensibleType
where
endpoint.getExtensibleType() = extensibleType and
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
) and
CharacteristicsImpl::isSinkCandidate(endpoint, _) 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
// 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
@@ -34,19 +37,10 @@ where
alreadyAiModeled.matches("%ai-%") and
CharacteristicsImpl::isSink(endpoint, _, alreadyAiModeled)
) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, parameterName) 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
CharacteristicsImpl::isSinkCandidate(endpoint, sinkType)
|
sinkType, ", "
)
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName) and
includeAutomodelCandidate(package, type, name, signature)
select endpoint,
message + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@.", //
"Related locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
@@ -55,5 +49,7 @@ select endpoint,
name, "name", //
signature, "signature", //
input, "input", //
output, "output", //
parameterName, "parameterName", //
alreadyAiModeled, "alreadyAiModeled"
alreadyAiModeled, "alreadyAiModeled", //
extensibleType, "extensibleType"

View File

@@ -16,15 +16,14 @@ from
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence,
DollarAtString message, FrameworkModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString parameterName
DollarAtString input, DollarAtString output, DollarAtString parameterName,
DollarAtString extensibleType
where
endpoint.getExtensibleType() = extensibleType and
characteristic.appliesToEndpoint(endpoint) and
confidence >= SharedCharacteristics::highConfidence() and
characteristic.hasImplications(any(NegativeSinkType negative), true, confidence) and
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
// certain about in the prompt.
not erroneousEndpoints(endpoint, _, _, _, _, false) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, parameterName) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName) and
// 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
// `isSink(n) and not isSanitizer(n)`. We don't want to include such nodes as negative examples in the prompt, because
@@ -37,7 +36,7 @@ where
) and
message = characteristic
select endpoint,
message + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
message + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
@@ -46,4 +45,6 @@ select endpoint,
name, "name", //
signature, "signature", //
input, "input", //
parameterName, "parameterName" //
output, "output", //
parameterName, "parameterName", //
extensibleType, "extensibleType"

View File

@@ -15,16 +15,15 @@ private import AutomodelJavaUtil
from
Endpoint endpoint, SinkType sinkType, FrameworkModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString parameterName
DollarAtString input, DollarAtString output, DollarAtString parameterName,
DollarAtString extensibleType
where
// Exclude endpoints that have contradictory endpoint characteristics, because we only want examples we're highly
// certain about in the prompt.
not erroneousEndpoints(endpoint, _, _, _, _, false) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, parameterName) and
endpoint.getExtensibleType() = extensibleType and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName) and
// Extract positive examples of sinks belonging to the existing ATM query configurations.
CharacteristicsImpl::isKnownSink(endpoint, sinkType, _)
CharacteristicsImpl::isKnownAs(endpoint, sinkType, _)
select endpoint,
sinkType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@.", //
sinkType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //
@@ -33,4 +32,6 @@ select endpoint,
name, "name", //
signature, "signature", //
input, "input", //
parameterName, "parameterName" //
output, "output", //
parameterName, "parameterName", //
extensibleType, "extensibleType"

View File

@@ -39,14 +39,9 @@ predicate isKnownKind(string kind, AutomodelEndpointTypes::EndpointType type) {
or
kind = "command-injection" and
type instanceof AutomodelEndpointTypes::CommandInjectionSinkType
}
/** Gets the models-as-data description for the method argument with the index `index`. */
bindingset[index]
string getArgumentForIndex(int index) {
index = -1 and result = "Argument[this]"
or
index >= 0 and result = "Argument[" + index + "]"
kind = "remote" and
type instanceof AutomodelEndpointTypes::RemoteSourceType
}
/**

View File

@@ -62,6 +62,11 @@ signature module CandidateSig {
*/
predicate isSink(Endpoint e, string kind, string provenance);
/**
* Holds if `e` is a sink with the label `kind`, and provenance `provenance`.
*/
predicate isSource(Endpoint e, string kind, string provenance);
/**
* Holds if `e` is not a sink of any kind.
*/
@@ -91,17 +96,23 @@ module SharedCharacteristics<CandidateSig Candidate> {
predicate isNeutral = Candidate::isNeutral/1;
predicate isModeled(Candidate::Endpoint e, string kind, string extensibleKind, string provenance) {
Candidate::isSink(e, kind, provenance) and extensibleKind = "sinkModel"
or
Candidate::isSource(e, kind, provenance) and extensibleKind = "sourceModel"
}
/**
* Holds if `sink` is a known sink of type `endpointType`.
* Holds if `endpoint` is modeled as `endpointType` (endpoint type must not be negative).
*/
predicate isKnownSink(
Candidate::Endpoint sink, Candidate::EndpointType endpointType,
predicate isKnownAs(
Candidate::Endpoint endpoint, 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
characteristic.appliesToEndpoint(sink) and
characteristic.appliesToEndpoint(endpoint) and
characteristic.hasImplications(endpointType, true, maximalConfidence())
}
@@ -209,6 +220,25 @@ module SharedCharacteristics<CandidateSig Candidate> {
}
}
/**
* A high-confidence characteristic that indicates that an endpoint is a source of a specified type. These endpoints can
* be used as positive samples for training or for a few-shot prompt.
*/
abstract class SourceCharacteristic extends EndpointCharacteristic {
bindingset[this]
SourceCharacteristic() { any() }
abstract Candidate::EndpointType getSourceType();
final override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
endpointType = this.getSourceType() and
isPositiveIndicator = true and
confidence = maximalConfidence()
}
}
/**
* A high-confidence characteristic that indicates that an endpoint is not a sink of any type. These endpoints can be
* used as negative samples for training or for a few-shot prompt.
@@ -292,6 +322,25 @@ module SharedCharacteristics<CandidateSig Candidate> {
override Candidate::EndpointType getSinkType() { result = endpointType }
}
private class KnownSourceCharacteristic extends SourceCharacteristic {
string madKind;
Candidate::EndpointType endpointType;
string provenance;
KnownSourceCharacteristic() {
Candidate::isKnownKind(madKind, endpointType) and
// bind "this" to a unique string differing from that of the SinkType classes
this = madKind + "_" + provenance + "_characteristic" and
Candidate::isSource(_, madKind, provenance)
}
override predicate appliesToEndpoint(Candidate::Endpoint e) {
Candidate::isSource(e, madKind, provenance)
}
override Candidate::EndpointType getSourceType() { result = endpointType }
}
/**
* A negative characteristic that indicates that an endpoint was manually modeled as a neutral model.
*/

View File

@@ -1,4 +1,13 @@
| 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://:1:1:1:1 | | 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://:1:1:1:1 | | 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://ai-manual:1:1:1:1 | ai-manual | 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://:1:1:1:1 | | alreadyAiModeled |
| PluginImpl.java:5:27:5:37 | name | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | PluginImpl.java:5:27:5:37 | name | CallContext | hudson/Plugin.java:5:5:5:31 | /** Configure method doc */ | MethodDoc | hudson/Plugin.java:3:1:3:17 | /** Plugin doc */ | ClassDoc | file://hudson:1:1:1:1 | hudson | package | file://Plugin:1:1:1:1 | Plugin | type | file://true:1:1:1:1 | true | subtypes | file://configure:1:1:1:1 | configure | name | file://(String,String):1:1:1:1 | (String,String) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| PluginImpl.java:5:40:5:51 | value | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | PluginImpl.java:5:40:5:51 | value | CallContext | hudson/Plugin.java:5:5:5:31 | /** Configure method doc */ | MethodDoc | hudson/Plugin.java:3:1:3:17 | /** Plugin doc */ | ClassDoc | file://hudson:1:1:1:1 | hudson | package | file://Plugin:1:1:1:1 | Plugin | type | file://true:1:1:1:1 | true | subtypes | file://configure:1:1:1:1 | configure | name | file://(String,String):1:1:1:1 | (String,String) | signature | file://:1:1:1:1 | | input | file://Parameter[1]:1:1:1:1 | Parameter[1] | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:18:3:18:11 | reference | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:18:3:18:24 | set(...) | CallContext | Test.java:18:3:18:11 | reference | MethodDoc | Test.java:18:3:18:11 | reference | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:23:3:23:10 | supplier | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:23:3:23:16 | get(...) | CallContext | Test.java:23:3:23:10 | supplier | MethodDoc | Test.java:23:3:23:10 | supplier | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:23:3:23:16 | get(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:23:3:23:16 | get(...) | CallContext | Test.java:23:3:23:16 | get(...) | MethodDoc | Test.java:23:3:23:16 | get(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:27:3:31:3 | copy(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:27:3:31:3 | copy(...) | CallContext | Test.java:27:3:31:3 | copy(...) | MethodDoc | Test.java:27:3:31:3 | copy(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:35:10:37:3 | newInputStream(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:35:10:37:3 | newInputStream(...) | CallContext | Test.java:35:10:37:3 | newInputStream(...) | MethodDoc | Test.java:35:10:37:3 | newInputStream(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:36:4:36:11 | openPath | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:35:10:37:3 | newInputStream(...) | CallContext | Test.java:36:4:36:11 | openPath | MethodDoc | Test.java:36:4:36:11 | openPath | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://ai-manual:1:1:1:1 | ai-manual | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:42:4:42:22 | get(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:42:4:42:22 | get(...) | CallContext | Test.java:42:4:42:22 | get(...) | MethodDoc | Test.java:42:4:42:22 | get(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:53:3:58:3 | walk(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:53:3:58:3 | walk(...) | CallContext | Test.java:53:3:58:3 | walk(...) | MethodDoc | Test.java:53:3:58:3 | walk(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:55:4:55:4 | o | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:53:3:58:3 | walk(...) | CallContext | Test.java:53:3:58:3 | walk(...) | MethodDoc | Test.java:53:3:58:3 | walk(...) | ClassDoc | 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://:1:1:1:1 | | output | file://true:1:1:1:1 | true | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:62:3:62:3 | c | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:62:3:62:20 | getInputStream(...) | CallContext | Test.java:62:3:62:3 | c | MethodDoc | Test.java:62:3:62:3 | c | ClassDoc | file://java.net:1:1:1:1 | java.net | package | file://URLConnection:1:1:1:1 | URLConnection | type | file://true:1:1:1:1 | true | subtypes | file://getInputStream:1:1:1:1 | getInputStream | name | file://():1:1:1:1 | () | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:67:30:67:47 | writer | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:67:30:67:47 | writer | CallContext | Test.java:67:30:67:47 | writer | MethodDoc | Test.java:67:30:67:47 | writer | ClassDoc | file://java.lang:1:1:1:1 | java.lang | package | file://Throwable:1:1:1:1 | Throwable | type | file://true:1:1:1:1 | true | subtypes | file://printStackTrace:1:1:1:1 | printStackTrace | name | file://(PrintWriter):1:1:1:1 | (PrintWriter) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://false:1:1:1:1 | false | isVarargsArray | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |

View File

@@ -1,2 +1,4 @@
| 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: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 |
| Test.java:47:10:49:3 | compareTo(...) | known sanitizer\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:47:10:49:3 | compareTo(...) | CallContext | Test.java:47:10:49:3 | compareTo(...) | MethodDoc | Test.java:47:10:49:3 | compareTo(...) | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| Test.java:48:4:48:5 | f2 | known non-sink\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:47:10:49:3 | compareTo(...) | CallContext | Test.java:48:4:48:5 | f2 | MethodDoc | Test.java:48:4:48:5 | f2 | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:54:4:54:4 | p | taint step\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:53:3:58:3 | walk(...) | CallContext | Test.java:54:4:54:4 | p | MethodDoc | Test.java:54:4:54:4 | p | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:66:7:66:18 | this <constr(this)> | exception\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:66:7:66:18 | super(...) | CallContext | Test.java:66:7:66:18 | super(...) | MethodDoc | Test.java:66:7:66:18 | super(...) | ClassDoc | file://java.lang:1:1:1:1 | java.lang | package | file://Exception:1:1:1:1 | Exception | type | file://true:1:1:1:1 | true | subtypes | file://Exception:1:1:1:1 | Exception | name | file://():1:1:1:1 | () | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |

View File

@@ -1,3 +1,4 @@
| 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 | 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 | file://false:1:1:1:1 | false | isVarargsArray |
| Test.java:28:4:28:9 | source | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:27:3:31:3 | copy(...) | CallContext | Test.java:28:4:28:9 | source | MethodDoc | Test.java:28:4:28:9 | source | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:29:4:29:9 | target | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:27:3:31:3 | copy(...) | CallContext | Test.java:29:4:29:9 | target | MethodDoc | Test.java:29:4:29:9 | target | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:36:4:36:11 | openPath | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:35:10:37:3 | newInputStream(...) | CallContext | Test.java:36:4:36:11 | openPath | MethodDoc | Test.java:36:4:36:11 | openPath | ClassDoc | 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://:1:1:1:1 | | output | file://false:1:1:1:1 | false | isVarargsArray | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| Test.java:62:3:62:20 | getInputStream(...) | remote\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:62:3:62:20 | getInputStream(...) | CallContext | Test.java:62:3:62:20 | getInputStream(...) | MethodDoc | Test.java:62:3:62:20 | getInputStream(...) | ClassDoc | file://java.net:1:1:1:1 | java.net | package | file://URLConnection:1:1:1:1 | URLConnection | type | file://true:1:1:1:1 | true | subtypes | file://getInputStream:1:1:1:1 | getInputStream | name | file://():1:1:1:1 | () | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://false:1:1:1:1 | false | isVarargsArray | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |

View File

@@ -0,0 +1,8 @@
import hudson.Plugin;
public class PluginImpl extends Plugin {
@Override
public void configure(String name, String value) {
// ...
}
}

View File

@@ -1,6 +1,7 @@
package com.github.codeql.test;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -9,6 +10,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import java.io.File;
import java.nio.file.FileVisitOption;
import java.net.URLConnection;
class Test {
public static void main(String[] args) throws Exception {
@@ -18,11 +20,11 @@ class Test {
}
public static void callSupplier(Supplier<String> supplier) {
supplier.get(); // Argument[this] is a candidate
supplier.get(); // Argument[this] is a sink candidate; the call is a source candidate
}
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
Files.copy(
Files.copy( // the call is a source candidate
source, // positive example (known sink)
target, // positive example (known sink)
option // no candidate (not modeled, but source and target are modeled)
@@ -30,29 +32,39 @@ class Test {
}
public static InputStream getInputStream(Path openPath) throws Exception {
return Files.newInputStream(
return Files.newInputStream( // the call is a source candidate
openPath // positive example (known sink), candidate ("only" ai-modeled, and useful as a candidate in regression testing)
);
}
public static InputStream getInputStream(String openPath) throws Exception {
return Test.getInputStream(
Paths.get(openPath) // no candidate (argument to local call)
return Test.getInputStream( // the call is not a source candidate (argument to local call)
Paths.get(openPath) // no sink candidate (argument to local call); the call is a source candidate
);
}
public static int compareFiles(File f1, File f2) {
return f1.compareTo(
f2 // negative example (modeled as not a sink)
);
return f1.compareTo( // compareTo call is a known sanitizer
f2 // negative sink example (modeled as not a sink)
); // the call is a negative source candidate (sanitizer)
}
public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
Files.walk(
Files.walk( // the call is a source candidate
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)
);
}
public static void WebSocketExample(URLConnection c) throws Exception {
c.getInputStream(); // the call is a source example, c is a sink candidate
}
}
class OverrideTest extends Exception {
public void printStackTrace(PrintWriter writer) { // writer is a source candidate because it overrides an existing method
return;
}
}

View File

@@ -0,0 +1,7 @@
package hudson;
/** Plugin doc */
public class Plugin {
/** Configure method doc */
public void configure(String name, String value) {}
}

View File

@@ -1,9 +1,24 @@
| com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | MethodDoc | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| java/nio/file/Files.java:14:9:14:24 | out | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:14:9:14:24 | out | MethodDoc | java/nio/file/Files.java:14:9:14:24 | out | ClassDoc | 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,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input | file://out:1:1:1:1 | out | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| java/nio/file/Files.java:25:9:25:21 | openPath | command-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:25:9:25:21 | openPath | MethodDoc | java/nio/file/Files.java:25:9:25:21 | openPath | ClassDoc | 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://openPath:1:1:1:1 | openPath | parameterName | file://ai-manual:1:1:1:1 | ai-manual | alreadyAiModeled |
| java/nio/file/Files.java:26:9:26:29 | options | command-injection, path-injection, request-forgery, sql-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:26:9:26:29 | options | MethodDoc | java/nio/file/Files.java:26:9:26:29 | options | ClassDoc | 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[1]:1:1:1:1 | Argument[1] | input | file://options:1:1:1:1 | options | parameterName | file://:1:1:1:1 | | alreadyAiModeled |
| com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | MethodDoc | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[this]:1:1:1:1 | Parameter[this] | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | MethodDoc | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | MethodDoc | com/github/codeql/test/PublicClass.java:4:15:4:19 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:4:21:4:30 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicClass.java:8:22:8:32 | staticStuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:8:22:8:32 | staticStuff | MethodDoc | com/github/codeql/test/PublicClass.java:8:22:8:32 | staticStuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:8:34:8:43 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | MethodDoc | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://nonPublicStuff:1:1:1:1 | nonPublicStuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[this]:1:1:1:1 | Parameter[this] | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | MethodDoc | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://nonPublicStuff:1:1:1:1 | nonPublicStuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | MethodDoc | com/github/codeql/test/PublicClass.java:13:18:13:31 | nonPublicStuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://nonPublicStuff:1:1:1:1 | nonPublicStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://nonPublicStuff:1:1:1:1 | nonPublicStuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | MethodDoc | com/github/codeql/test/PublicClass.java:13:33:13:42 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicClass:1:1:1:1 | PublicClass | type | file://true:1:1:1:1 | true | subtypes | file://nonPublicStuff:1:1:1:1 | nonPublicStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[this]:1:1:1:1 | Parameter[this] | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:17:4:21 | stuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://this:1:1:1:1 | this | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:23:4:32 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://true:1:1:1:1 | true | subtypes | file://stuff:1:1:1:1 | stuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:6:24:6:34 | staticStuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:6:24:6:34 | staticStuff | MethodDoc | com/github/codeql/test/PublicInterface.java:6:24:6:34 | staticStuff | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:6:36:6:45 | arg | ClassDoc | file://com.github.codeql.test:1:1:1:1 | com.github.codeql.test | package | file://PublicInterface:1:1:1:1 | PublicInterface | type | file://false:1:1:1:1 | false | subtypes | file://staticStuff:1:1:1:1 | staticStuff | name | file://(String):1:1:1:1 | (String) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://arg:1:1:1:1 | arg | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| java/nio/file/Files.java:12:24:12:27 | copy | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:12:24:12:27 | copy | MethodDoc | java/nio/file/Files.java:12:24:12:27 | copy | ClassDoc | 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,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| java/nio/file/Files.java:14:9:14:24 | out | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:14:9:14:24 | out | MethodDoc | java/nio/file/Files.java:14:9:14:24 | out | ClassDoc | 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,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[1]:1:1:1:1 | Argument[1] | input | file://:1:1:1:1 | | output | file://out:1:1:1:1 | out | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| java/nio/file/Files.java:24:31:24:44 | newInputStream | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:24:31:24:44 | newInputStream | MethodDoc | java/nio/file/Files.java:24:31:24:44 | newInputStream | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| java/nio/file/Files.java:25:9:25:21 | openPath | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:25:9:25:21 | openPath | MethodDoc | java/nio/file/Files.java:25:9:25:21 | openPath | ClassDoc | 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://:1:1:1:1 | | output | file://openPath:1:1:1:1 | openPath | parameterName | file://ai-manual:1:1:1:1 | ai-manual | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| java/nio/file/Files.java:26:9:26:29 | options | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:26:9:26:29 | options | MethodDoc | java/nio/file/Files.java:26:9:26:29 | options | ClassDoc | 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[1]:1:1:1:1 | Argument[1] | input | file://:1:1:1:1 | | output | file://options:1:1:1:1 | options | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |

View File

@@ -1,2 +1,5 @@
| java/io/File.java:4:9:4:17 | compareTo | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:4:9:4:17 | compareTo | MethodDoc | java/io/File.java:4:9:4:17 | compareTo | ClassDoc | 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[this]:1:1:1:1 | Argument[this] | input | file://this:1:1:1:1 | this | parameterName |
| java/io/File.java:5:9:5:21 | pathname | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:5:9:5:21 | pathname | MethodDoc | java/io/File.java:5:9:5:21 | pathname | ClassDoc | 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://pathname:1:1:1:1 | pathname | parameterName |
| java/io/File.java:4:16:4:24 | compareTo | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:4:16:4:24 | compareTo | MethodDoc | java/io/File.java:4:16:4:24 | compareTo | ClassDoc | 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://:1:1:1:1 | | input | file://Parameter[this]:1:1:1:1 | Parameter[this] | output | file://this:1:1:1:1 | this | parameterName | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| java/io/File.java:4:16:4:24 | compareTo | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:4:16:4:24 | compareTo | MethodDoc | java/io/File.java:4:16:4:24 | compareTo | ClassDoc | 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://:1:1:1:1 | | input | file://ReturnValue:1:1:1:1 | ReturnValue | output | file://:1:1:1:1 | | parameterName | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| java/io/File.java:4:16:4:24 | compareTo | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:4:16:4:24 | compareTo | MethodDoc | java/io/File.java:4:16:4:24 | compareTo | ClassDoc | 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[this]:1:1:1:1 | Argument[this] | input | file://:1:1:1:1 | | output | file://this:1:1:1:1 | this | parameterName | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| java/io/File.java:5:9:5:21 | pathname | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:5:9:5:21 | pathname | MethodDoc | java/io/File.java:5:9:5:21 | pathname | ClassDoc | 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://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://pathname:1:1:1:1 | pathname | parameterName | file://sourceModel:1:1:1:1 | sourceModel | extensibleType |
| java/io/File.java:5:9:5:21 | pathname | known non-sink\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:5:9:5:21 | pathname | MethodDoc | java/io/File.java:5:9:5:21 | pathname | ClassDoc | 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://:1:1:1:1 | | output | file://pathname:1:1:1:1 | pathname | parameterName | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |

View File

@@ -1,2 +1,2 @@
| java/nio/file/Files.java:13:9:13:19 | source | path-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:13:9:13:19 | source | MethodDoc | java/nio/file/Files.java:13:9:13:19 | source | ClassDoc | 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,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://source:1:1:1:1 | source | parameterName |
| java/nio/file/Files.java:25:9:25:21 | openPath | path-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:25:9:25:21 | openPath | MethodDoc | java/nio/file/Files.java:25:9:25:21 | openPath | ClassDoc | 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://openPath:1:1:1:1 | openPath | parameterName |
| java/nio/file/Files.java:13:9:13:19 | source | path-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:13:9:13:19 | source | MethodDoc | java/nio/file/Files.java:13:9:13:19 | source | ClassDoc | 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,OutputStream):1:1:1:1 | (Path,OutputStream) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://source:1:1:1:1 | source | parameterName | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| java/nio/file/Files.java:25:9:25:21 | openPath | path-injection\nrelated locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/nio/file/Files.java:25:9:25:21 | openPath | MethodDoc | java/nio/file/Files.java:25:9:25:21 | openPath | ClassDoc | 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://:1:1:1:1 | | output | file://openPath:1:1:1:1 | openPath | parameterName | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |

View File

@@ -1,15 +1,15 @@
package com.github.codeql.test;
public class PublicClass {
public void stuff(String arg) { // `arg` is a candidate, `this` is a candidate
public void stuff(String arg) { // `arg` is a sink candidate, `this` is a candidate, `arg` is a source candidate (overrideable method)
System.out.println(arg);
}
} // method stuff is a candidate source
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method), `arg` is not a source candidate (static methods can not be overloaded)
System.out.println(arg);
}
} // method staticStuff is a candidate source
// `arg` and `this` are not a candidate because the method is not public:
// `arg` and `this` are candidates because the method is protected (may be called from downstream repositories). The return value is a candidate source for the same reason.
protected void nonPublicStuff(String arg) {
System.out.println(arg);
}

View File

@@ -1,9 +1,9 @@
package com.github.codeql.test;
public interface PublicInterface {
public void stuff(String arg); // `arg` is a candidate, `this` is a candidate
public void stuff(String arg); // `arg` is a candidate, `this` is a candidate, method stuff is a candidate source, `arg` is a source candidate (overrideable method)
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
System.out.println(arg);
}
} // method staticStuff is a candidate source
}

View File

@@ -1,9 +1,9 @@
package java.io;
public class File {
int compareTo( // `this` is a negative example - this is modeled as a neutral model
public int compareTo( // `this` is a negative example - this is modeled as a neutral model
File pathname // negative example - this is modeled as a neutral model
) {
return 0;
}
} // also a negative example for ReturnValue source
}

View File

@@ -19,12 +19,12 @@ public class Files {
*/
) throws IOException {
// ...
}
} // method copy is a candidate source
public static InputStream newInputStream(
Path openPath ,// positive example (known sink), candidate (ai-modeled, and useful as a candidate in regression testing)
OpenOption... options
) throws IOException {
return new FileInputStream(openPath.toFile());
}
} // method newInputStream is a candidate source
}

View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>maven-sample</artifactId>
<version>1.0-SNAPSHOT</version>
<name>maven-sample</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>1.1.1</version>
<executions>
<execution>
<id>check-maven-version</id>
<phase>package</phase>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>com.example.App</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<java>
<licenseHeader>
<content>/* FAIL ME */</content>
</licenseHeader>
</java>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -0,0 +1,30 @@
package com.example;
import java.util.regex.Pattern;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
String expectedVersion = System.getenv("EXPECT_MAVEN");
Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize();
String observedVersion = mavenHome.getFileName().toString();
if (expectedVersion != null && !expectedVersion.equals(observedVersion)) {
System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome);
System.exit(1);
}
String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX");
String command = System.getProperty("sun.java.command");
if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) {
System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'");
System.exit(1);
}
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title>A sample</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<struts>
This is a sample file
</struts>

View File

@@ -0,0 +1,20 @@
package com.example;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}

View File

@@ -0,0 +1,8 @@
xmlFiles
| pom.xml:0:0:0:0 | pom.xml |
| src/main/resources/page.xml:0:0:0:0 | src/main/resources/page.xml |
| src/main/resources/struts.xml:0:0:0:0 | src/main/resources/struts.xml |
propertiesFiles
#select
| src/main/java/com/example/App.java:0:0:0:0 | App |
| src/test/java/com/example/AppTest.java:0:0:0:0 | AppTest |

View File

@@ -0,0 +1,5 @@
import sys
from create_database_utils import *
run_codeql_database_create([], lang="java", extra_env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true", "CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true"})

View File

@@ -0,0 +1,9 @@
import java
from File f
where f.isSourceFile()
select f
query predicate xmlFiles(XmlFile x) { any() }
query predicate propertiesFiles(File f) { f.getExtension() = "properties" }

View File

@@ -0,0 +1,3 @@
Test2.java:
# 0| [CompilationUnit] Test2
# 1| 1: [Class] Test2

View File

@@ -0,0 +1,5 @@
import sys
from create_database_utils import *
run_codeql_database_create([], lang="java", extra_args=["--extractor-option=buildless=true"])

View File

@@ -0,0 +1,35 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>snapshot-test-repo</id>
<url>http://localhost:9427/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.my.snapshot.test</groupId>
<artifactId>snapshottest</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,24 @@
<metadata modelVersion="1.1.0">
<groupId>com.github.my.snapshot.test</groupId>
<artifactId>snapshottest</artifactId>
<version>1.0-SNAPSHOT</version>
<versioning>
<lastUpdated>20230101020304</lastUpdated>
<snapshot>
<timestamp>20230901.050514</timestamp>
<buildNumber>100</buildNumber>
</snapshot>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0-20230901.050514-100</value>
<updated>20230101020304</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
<value>1.0-20230901.050514-100</value>
<updated>20230101020304</updated>
</snapshotVersion>
</snapshotVersions>
</versioning>
</metadata>

View File

@@ -0,0 +1,13 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.my.snapshot.test</groupId>
<artifactId>snapshottest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

View File

@@ -0,0 +1,7 @@
import testpkg.DepClass;
public class Test {
DepClass dc;
}

View File

@@ -0,0 +1,3 @@
diagnostics
#select
| DepClass |

View File

@@ -0,0 +1,12 @@
import sys
from create_database_utils import *
import subprocess
repo_server_process = subprocess.Popen(["python3", "-m", "http.server", "9427"], cwd = "repo")
try:
run_codeql_database_create([], lang="java", extra_args=["--extractor-option=buildless=true"], extra_env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS_CLASSPATH_FROM_BUILD_FILES": "true"})
finally:
repo_server_process.kill()

View File

@@ -0,0 +1,8 @@
import java
import semmle.code.java.Diagnostics
query predicate diagnostics(Diagnostic d) { any() }
from Class c
where c.getName() = "DepClass"
select c.toString()

View File

@@ -0,0 +1,30 @@
package com.example;
import java.util.regex.Pattern;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
String expectedVersion = System.getenv("EXPECT_MAVEN");
Path mavenHome = Paths.get(System.getProperty("maven.home")).normalize();
String observedVersion = mavenHome.getFileName().toString();
if (expectedVersion != null && !expectedVersion.equals(observedVersion)) {
System.err.println("Wrong maven version, expected '" + expectedVersion + "' but got '" + observedVersion + "'" + mavenHome);
System.exit(1);
}
String commandMatcher = System.getenv("EXPECT_COMMAND_REGEX");
String command = System.getProperty("sun.java.command");
if (commandMatcher != null && !Pattern.matches(commandMatcher, command)) {
System.err.println("Wrong command line, '" + command + "' does not match '" + commandMatcher + "'");
System.exit(1);
}
}
}

View File

@@ -0,0 +1,8 @@
<html>
<head>
<title>A sample</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<struts>
This is a sample file
</struts>

View File

@@ -0,0 +1,20 @@
package com.example;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* Unit test for simple App.
*/
public class AppTest
{
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue()
{
assertTrue( true );
}
}

View File

@@ -0,0 +1,7 @@
xmlFiles
| src/main/resources/page.xml:0:0:0:0 | src/main/resources/page.xml |
| src/main/resources/struts.xml:0:0:0:0 | src/main/resources/struts.xml |
propertiesFiles
#select
| src/main/java/com/example/App.java:0:0:0:0 | App |
| src/test/java/com/example/AppTest.java:0:0:0:0 | AppTest |

View File

@@ -0,0 +1,5 @@
import sys
from create_database_utils import *
run_codeql_database_create([], lang="java", extra_env={"CODEQL_EXTRACTOR_JAVA_OPTION_BUILDLESS": "true"})

View File

@@ -0,0 +1,9 @@
import java
from File f
where f.isSourceFile()
select f
query predicate xmlFiles(XmlFile x) { any() }
query predicate propertiesFiles(File f) { f.getExtension() = "properties" }

View File

@@ -0,0 +1,3 @@
# We currently have a bug where gradle tests become flaky when executed in parallel
# - sometimes, gradle fails to connect to the gradle daemon.
# Therefore, force this test to run sequentially.

View File

@@ -1,5 +1,5 @@
{
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.9.20.",
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 1.9.30.",
"severity": "error",
"source": {
"extractorName": "java",

View File

@@ -1,3 +1,3 @@
from create_database_utils import *
run_codeql_database_create(["kotlinc SomeClass.kt"], lang="java")
run_codeql_database_create(["kotlinc -J-Xmx2G SomeClass.kt"], lang="java")

View File

@@ -1,3 +1,3 @@
from create_database_utils import *
run_codeql_database_create(["kotlinc -language-version 2.0 SomeClass.kt"], lang="java")
run_codeql_database_create(["kotlinc -J-Xmx2G -language-version 2.0 SomeClass.kt"], lang="java")

View File

@@ -0,0 +1,3 @@
# We currently have a bug where gradle tests become flaky when executed in parallel
# - sometimes, gradle fails to connect to the gradle daemon.
# Therefore, force this test to run sequentially.

View File

@@ -0,0 +1,3 @@
# We currently have a bug where gradle tests become flaky when executed in parallel
# - sometimes, gradle fails to connect to the gradle daemon.
# Therefore, force this test to run sequentially.

View File

@@ -0,0 +1,3 @@
# We currently have a bug where gradle tests become flaky when executed in parallel
# - sometimes, gradle fails to connect to the gradle daemon.
# Therefore, force this test to run sequentially.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Regular expressions containing multiple parse mode flags are now interpretted correctly. For example `"(?is)abc.*"` with both the `i` and `s` flags.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added new dataflow models for the Apache CXF framework.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Kotlin versions up to 1.9.20 are now supported.

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* The regular expressions library no longer incorrectly matches mode flag characters against the input.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved the class `ArithExpr` of the `Overflow.qll` module to also include compound operators. Because of this, new alerts may be raised in queries related to overflows/underflows.

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* Fixed a control-flow bug where case rule statements would incorrectly include a fall-through edge.
* Added support for default cases as proper guards in switch expressions to match switch statements.

View File

@@ -130,6 +130,7 @@ extensions:
- ["java.lang", "Thread", True, "getName", "()", "", "Argument[this].SyntheticField[java.lang.Thread.name]", "ReturnValue", "value", "manual"]
- ["java.lang", "ThreadLocal", True, "get", "()", "", "Argument[this].SyntheticField[java.lang.ThreadLocal.value]", "ReturnValue", "value", "manual"]
- ["java.lang", "ThreadLocal", True, "set", "(Object)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.ThreadLocal.value]", "value", "manual"]
- ["java.lang", "ThreadLocal", False, "withInitial", "(Supplier)", "", "Argument[0].ReturnValue", "ReturnValue.SyntheticField[java.lang.ThreadLocal.value]", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "Throwable", True, "getCause", "()", "", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "ReturnValue", "value", "manual"]

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.catalog", "OASISCatalogManager", True, "loadCatalog", "(URL)", "", "Argument[0]", "request-forgery", "manual"]

View File

@@ -0,0 +1,8 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.common.classloader", "ClassLoaderUtils", True, "getResourceAsStream", "(String,Class)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.common.classloader", "ClassLoaderUtils", True, "getURLClassLoader", "(URL[],ClassLoader)", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.cxf.common.classloader", "ClassLoaderUtils", True, "getURLClassLoader", "(List,ClassLoader)", "", "Argument[0]", "request-forgery", "manual"]

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.common.jaxb", "JAXBUtils", True, "createFileCodeWriter", "", "", "Argument[0]", "path-injection", "manual"]

View File

@@ -0,0 +1,11 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String)", "", "Argument[2]", "log-injection", "manual"]
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String,Object)", "", "Argument[2]", "log-injection", "manual"]
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String,Object[])", "", "Argument[2]", "log-injection", "manual"]
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String,Throwable)", "", "Argument[2]", "log-injection", "manual"]
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String,Throwable,Object)", "", "Argument[2]", "log-injection", "manual"]
- ["org.apache.cxf.common.logging", "LogUtils", True, "log", "(Logger,Level,String,Throwable,Object[])", "", "Argument[2]", "log-injection", "manual"]

View File

@@ -0,0 +1,7 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.configuration.jsse", "SSLUtils", True, "loadFile", "(String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.configuration.jsse", "TLSClientParameters", True, "setHostnameVerifier", "(HostnameVerifier)", "", "Argument[0]", "hostname-verification", "manual"]

View File

@@ -0,0 +1,8 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.transform", "XSLTUtils", True, "transform", "(Templates,InputStream)", "", "Argument[0]", "xslt-injection", "manual"]
- ["org.apache.cxf.transform", "XSLTUtils", True, "transform", "(Templates,Reader)", "", "Argument[0]", "xslt-injection", "manual"]
- ["org.apache.cxf.transform", "XSLTUtils", True, "transform", "(Templates,Document)", "", "Argument[0]", "xslt-injection", "manual"]

View File

@@ -0,0 +1,15 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.helpers", "FileUtils", True, "delete", "(File)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.helpers", "FileUtils", True, "delete", "(File,boolean)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.helpers", "FileUtils", True, "mkdir", "(File)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.helpers", "FileUtils", True, "readLines", "(File)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.helpers", "FileUtils", True, "removeDir", "(File)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.helpers", "XPathUtils", True, "getValue", "(String,Node,QName)", "", "Argument[0]", "xpath-injection", "manual"]
- ["org.apache.cxf.helpers", "XPathUtils", True, "getValueList", "(String,Node)", "", "Argument[0]", "xpath-injection", "manual"]
- ["org.apache.cxf.helpers", "XPathUtils", True, "getValueNode", "(String,Node)", "", "Argument[0]", "xpath-injection", "manual"]
- ["org.apache.cxf.helpers", "XPathUtils", True, "getValueString", "(String,Node)", "", "Argument[0]", "xpath-injection", "manual"]
- ["org.apache.cxf.helpers", "XPathUtils", True, "isExist", "(String,Node,QName)", "", "Argument[0]", "xpath-injection", "manual"]

View File

@@ -0,0 +1,14 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.resource", "ExtendedURIResolver", True, "resolve", "(String,String)", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.cxf.resource", "ExtendedURIResolver", True, "resolve", "(String,String)", "", "Argument[1]", "path-injection", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "URIResolver", "(String)", "", "Argument[0]", "request-forgery", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "URIResolver", "(String,String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "URIResolver", "(String,String)", "", "Argument[1]", "request-forgery", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "URIResolver", "(String,String,Class)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "URIResolver", "(String,String,Class)", "", "Argument[1]", "request-forgery", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "resolve", "(String,String,Class)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.resource", "URIResolver", True, "resolve", "(String,String,Class)", "", "Argument[1]", "request-forgery", "manual"]

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.staxutils", "StaxUtils", True, "read", "(File)", "", "Argument[0]", "path-injection", "manual"]

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.tools.corba.utils", "FileOutputStreamFactory", true, "FileOutputStreamFactory", "(String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.corba.utils", "FileOutputStreamFactory", true, "FileOutputStreamFactory", "(String,FileOutputStreamFactory)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.corba.utils", "OutputStreamFactory", true, "createOutputStream", "(String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.corba.utils", "OutputStreamFactory", true, "createOutputStream", "(String,String)", "", "Argument[0..1]", "path-injection", "manual"]

View File

@@ -0,0 +1,15 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "FileWriterUtil", "(String,OutputStreamCreator)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "buildDir", "(String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getFileToWrite", "(String,String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getFileToWrite", "(String,String)", "", "Argument[1]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getWriter", "(File,String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getWriter", "(String,String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getWriter", "(String,String)", "", "Argument[1]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getWriter", "(String,String,String)", "", "Argument[0]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "FileWriterUtil", True, "getWriter", "(String,String,String)", "", "Argument[1]", "path-injection", "manual"]
- ["org.apache.cxf.tools.util", "OutputStreamCreator", true, "createOutputStream", "(File)", "", "Argument[0]", "path-injection", "manual"]

View File

@@ -6,11 +6,6 @@ extensions:
data:
# Default threat model
- ["remote", "default"]
- ["uri-path", "default"]
# Android threat models
- ["android-external-storage-dir", "android"]
- ["contentprovider", "android"]
# Remote threat models
- ["request", "remote"]
@@ -18,6 +13,10 @@ extensions:
# Local threat models
- ["database", "local"]
- ["cli", "local"]
- ["commandargs", "local"]
- ["environment", "local"]
- ["file", "local"]
# Android threat models
- ["android-external-storage-dir", "android"]
- ["contentprovider", "android"]

View File

@@ -1,171 +1,37 @@
/** Provides classes for working with files and folders. */
import Location
private import codeql.util.FileSystem
private module Input implements InputSig {
abstract class ContainerBase extends @container {
abstract string getAbsolutePath();
ContainerBase getParentContainer() { containerparent(result, this) }
string toString() { result = this.getAbsolutePath() }
}
class FolderBase extends ContainerBase, @folder {
override string getAbsolutePath() { folders(this, result) }
}
class FileBase extends ContainerBase, @file {
override string getAbsolutePath() { files(this, result) }
}
predicate hasSourceLocationPrefix = sourceLocationPrefix/1;
}
private module Impl = Make<Input>;
/** A file or folder. */
class Container extends @container, Top {
/**
* Gets the absolute, canonical path of this container, using forward slashes
* as path separator.
*
* The path starts with a _root prefix_ followed by zero or more _path
* segments_ separated by forward slashes.
*
* The root prefix is of one of the following forms:
*
* 1. A single forward slash `/` (Unix-style)
* 2. An upper-case drive letter followed by a colon and a forward slash,
* such as `C:/` (Windows-style)
* 3. Two forward slashes, a computer name, and then another forward slash,
* such as `//FileServer/` (UNC-style)
*
* Path segments are never empty (that is, absolute paths never contain two
* contiguous slashes, except as part of a UNC-style root prefix). Also, path
* segments never contain forward slashes, and no path segment is of the
* form `.` (one dot) or `..` (two dots).
*
* Note that an absolute path never ends with a forward slash, except if it is
* a bare root prefix, that is, the path has no path segments. A container
* whose absolute path has no segments is always a `Folder`, not a `File`.
*/
abstract string getAbsolutePath();
/**
* Gets a URL representing the location of this container.
*
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
*/
abstract string getURL();
/**
* Gets the relative path of this file or folder from the root folder of the
* analyzed source location. The relative path of the root folder itself is
* the empty string.
*
* This has no result if the container is outside the source root, that is,
* if the root folder is not a reflexive, transitive parent of this container.
*/
string getRelativePath() {
exists(string absPath, string pref |
absPath = this.getAbsolutePath() and sourceLocationPrefix(pref)
|
absPath = pref and result = ""
or
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
not result.matches("/%")
)
}
/**
* Gets the base name of this container including extension, that is, the last
* segment of its absolute path, or the empty string if it has no segments.
*
* Here are some examples of absolute paths and the corresponding base names
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Base name</th></tr>
* <tr><td>"/tmp/tst.java"</td><td>"tst.java"</td></tr>
* <tr><td>"C:/Program Files (x86)"</td><td>"Program Files (x86)"</td></tr>
* <tr><td>"/"</td><td>""</td></tr>
* <tr><td>"C:/"</td><td>""</td></tr>
* <tr><td>"D:/"</td><td>""</td></tr>
* <tr><td>"//FileServer/"</td><td>""</td></tr>
* </table>
*/
string getBaseName() {
result = this.getAbsolutePath().regexpCapture(".*/(([^/]*?)(?:\\.([^.]*))?)", 1)
}
/**
* Gets the extension of this container, that is, the suffix of its base name
* after the last dot character, if any.
*
* In particular,
*
* - if the name does not include a dot, there is no extension, so this
* predicate has no result;
* - if the name ends in a dot, the extension is the empty string;
* - if the name contains multiple dots, the extension follows the last dot.
*
* Here are some examples of absolute paths and the corresponding extensions
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Extension</th></tr>
* <tr><td>"/tmp/tst.java"</td><td>"java"</td></tr>
* <tr><td>"/tmp/.classpath"</td><td>"classpath"</td></tr>
* <tr><td>"/bin/bash"</td><td>not defined</td></tr>
* <tr><td>"/tmp/tst2."</td><td>""</td></tr>
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
}
/**
* Gets the stem of this container, that is, the prefix of its base name up to
* (but not including) the last dot character if there is one, or the entire
* base name if there is not.
*
* Here are some examples of absolute paths and the corresponding stems
* (surrounded with quotes to avoid ambiguity):
*
* <table border="1">
* <tr><th>Absolute path</th><th>Stem</th></tr>
* <tr><td>"/tmp/tst.java"</td><td>"tst"</td></tr>
* <tr><td>"/tmp/.classpath"</td><td>""</td></tr>
* <tr><td>"/bin/bash"</td><td>"bash"</td></tr>
* <tr><td>"/tmp/tst2."</td><td>"tst2"</td></tr>
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() {
result = this.getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
}
/** Gets the parent container of this file or folder, if any. */
Container getParentContainer() { containerparent(result, this) }
/** Gets a file or sub-folder in this container. */
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() { result = this.getAChildContainer() }
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
result = this.getAFile() and
result.getBaseName() = baseName
}
/** Gets a sub-folder in this container. */
Folder getAFolder() { result = this.getAChildContainer() }
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
result = this.getAFolder() and
result.getBaseName() = baseName
}
/**
* Gets a textual representation of this container.
*
* The default implementation gets the absolute path to the container, but subclasses may override
* to provide a different result. To get the absolute path of any `Container`, call
* `Container.getAbsolutePath()` directly.
*/
override string toString() { result = this.getAbsolutePath() }
class Container extends Impl::Container, Top {
override string toString() { result = Impl::Container.super.toString() }
}
/** A folder. */
class Folder extends Container, @folder {
override string getAbsolutePath() { folders(this, result) }
/** Gets the URL of this folder. */
override string getURL() { result = "folder://" + this.getAbsolutePath() }
class Folder extends Container, Impl::Folder {
override string getAPrimaryQlClass() { result = "Folder" }
}
@@ -174,12 +40,7 @@ class Folder extends Container, @folder {
*
* Note that `File` extends `Container` as it may be a `jar` file.
*/
class File extends Container, @file {
override string getAbsolutePath() { files(this, result) }
/** Gets the URL of this file. */
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
class File extends Container, Impl::File {
override string getAPrimaryQlClass() { result = "File" }
/** Holds if this is a (Java or Kotlin) source file. */

View File

@@ -477,6 +477,8 @@ private module ControlFlowGraphImpl {
or
this instanceof Call // includes both expressions and statements
or
this instanceof ErrorExpr
or
this instanceof ReturnStmt
or
this instanceof ThrowStmt
@@ -869,7 +871,13 @@ private module ControlFlowGraphImpl {
)
or
// the last node in a case rule is the last node in the right-hand side
last(n.(SwitchCase).getRuleStatement(), last, completion)
// if the rhs is a statement we wrap the completion as a break
exists(Completion caseCompletion |
last(n.(SwitchCase).getRuleStatement(), last, caseCompletion) and
if caseCompletion instanceof NormalOrBooleanCompletion
then completion = anonymousBreakCompletion()
else completion = caseCompletion
)
or
// ...and if the rhs is an expression we wrap the completion as a yield
exists(Completion caseCompletion |

View File

@@ -276,7 +276,8 @@ class ExprParent extends @exprparent, Top { }
* An error expression.
*
* These may be generated by upgrade or downgrade scripts when databases
* cannot be fully converted.
* cannot be fully converted, or generated by the extractor when extracting
* source code containing errors.
*/
class ErrorExpr extends Expr, @errorexpr {
override string toString() { result = "<error expr>" }
@@ -1243,7 +1244,12 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr {
override Stmt getEnclosingStmt() { result = Expr.super.getEnclosingStmt() }
/** Gets a printable representation of this expression. */
override string toString() { result = "new " + this.getConstructor().getName() + "(...)" }
override string toString() {
result = "new " + this.getConstructor().getName() + "(...)"
or
not exists(this.getConstructor()) and
result = "<ClassInstanceExpr that calls a missing constructor>"
}
override string getAPrimaryQlClass() { result = "ClassInstanceExpr" }
}
@@ -1670,13 +1676,25 @@ abstract class InstanceAccess extends Expr {
/** Holds if this instance access is to an enclosing instance of type `t`. */
predicate isEnclosingInstanceAccess(RefType t) {
t = this.getQualifier().getType().(RefType).getSourceDeclaration() and
t != this.getEnclosingCallable().getDeclaringType()
t != this.getEnclosingCallable().getDeclaringType() and
not this.isSuperInterfaceAccess()
or
not exists(this.getQualifier()) and
(not exists(this.getQualifier()) or this.isSuperInterfaceAccess()) and
exists(LambdaExpr lam | lam.asMethod() = this.getEnclosingCallable() |
t = lam.getAnonymousClass().getEnclosingType()
)
}
// A default method on an interface, `I`, may be invoked using `I.super.m()`.
// This always refers to the implemented interfaces of `this`. This form of
// qualified `super` cannot be combined with accessing an enclosing instance.
// JLS 15.11.2. "Accessing Superclass Members using super"
// JLS 15.12. "Method Invocation Expressions"
// JLS 15.12.1. "Compile-Time Step 1: Determine Type to Search"
private predicate isSuperInterfaceAccess() {
this instanceof SuperAccess and
this.getQualifier().getType().(RefType).getSourceDeclaration() instanceof Interface
}
}
/**

View File

@@ -80,11 +80,19 @@ class ArithExpr extends Expr {
(
this instanceof UnaryAssignExpr or
this instanceof AddExpr or
this instanceof AssignAddExpr or
this instanceof MulExpr or
this instanceof AssignMulExpr or
this instanceof SubExpr or
this instanceof DivExpr
this instanceof AssignSubExpr or
this instanceof DivExpr or
this instanceof AssignDivExpr
) and
forall(Expr e | e = this.(BinaryExpr).getAnOperand() or e = this.(UnaryAssignExpr).getExpr() |
forall(Expr e |
e = this.(BinaryExpr).getAnOperand() or
e = this.(UnaryAssignExpr).getExpr() or
e = this.(AssignOp).getSource()
|
e.getType() instanceof NumType
)
}
@@ -103,17 +111,21 @@ class ArithExpr extends Expr {
*/
Expr getLeftOperand() {
result = this.(BinaryExpr).getLeftOperand() or
result = this.(UnaryAssignExpr).getExpr()
result = this.(UnaryAssignExpr).getExpr() or
result = this.(AssignOp).getDest()
}
/**
* Gets the right-hand operand if this is a binary expression.
*/
Expr getRightOperand() { result = this.(BinaryExpr).getRightOperand() }
Expr getRightOperand() {
result = this.(BinaryExpr).getRightOperand() or result = this.(AssignOp).getRhs()
}
/** Gets an operand of this arithmetic expression. */
Expr getAnOperand() {
result = this.(BinaryExpr).getAnOperand() or
result = this.(UnaryAssignExpr).getExpr()
result = this.(UnaryAssignExpr).getExpr() or
result = this.(AssignOp).getSource()
}
}

View File

@@ -57,6 +57,8 @@ predicate implies_v1(Guard g1, boolean b1, Guard g2, boolean b2) {
or
g1.(DefaultCase).getSwitch().getAConstCase() = g2 and b1 = true and b2 = false
or
g1.(DefaultCase).getSwitchExpr().getAConstCase() = g2 and b1 = true and b2 = false
or
exists(MethodAccess check, int argIndex | check = g1 |
conditionCheckArgument(check, argIndex, _) and
g2 = check.getArgument(argIndex) and

View File

@@ -26,6 +26,6 @@ private string getChildThreatModel(string group) { threatModelGrouping(result, g
* Holds if the source model kind `kind` is relevant for generic queries
* under the current threat model configuration.
*/
predicate sourceModelKindConfig(string kind) {
predicate currentThreatModel(string kind) {
exists(string group | supportedThreatModels(group) and kind = getChildThreatModel*(group))
}

View File

@@ -29,11 +29,42 @@ import semmle.code.java.frameworks.struts.StrutsActions
import semmle.code.java.frameworks.Thrift
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.ExternalFlowConfiguration
/**
* A data flow source.
*/
abstract class SourceNode extends DataFlow::Node {
/**
* Gets a string that represents the source kind with respect to threat modeling.
*/
abstract string getThreatModel();
}
/**
* A class of data flow sources that respects the
* current threat model configuration.
*/
class ThreatModelFlowSource extends DataFlow::Node {
ThreatModelFlowSource() {
// Expansive threat model.
currentThreatModel("all") and
(this instanceof SourceNode or sourceNode(this, _))
or
exists(string kind |
// Specific threat model.
currentThreatModel(kind) and
(this.(SourceNode).getThreatModel() = kind or sourceNode(this, kind))
)
}
}
/** A data flow source of remote user input. */
abstract class RemoteFlowSource extends DataFlow::Node {
abstract class RemoteFlowSource extends SourceNode {
/** Gets a string that describes the type of this remote flow source. */
abstract string getSourceType();
override string getThreatModel() { result = "remote" }
}
/**
@@ -175,14 +206,47 @@ abstract class UserInput extends DataFlow::Node { }
private class RemoteUserInput extends UserInput instanceof RemoteFlowSource { }
/** A node with input that may be controlled by a local user. */
abstract class LocalUserInput extends UserInput { }
abstract class LocalUserInput extends UserInput, SourceNode {
override string getThreatModel() { result = "local" }
}
/**
* DEPRECATED: Use the threat models feature.
* That is, use `ThreatModelFlowSource` as the class of nodes for sources
* and set up the threat model configuration to filter source nodes.
* Alternatively, use `getThreatModel` to filter nodes to create the
* class of nodes you need.
*
* A node with input from the local environment, such as files, standard in,
* environment variables, and main method parameters.
*/
class EnvInput extends LocalUserInput {
deprecated class EnvInput extends DataFlow::Node {
EnvInput() {
this instanceof EnvironmentInput or
this instanceof CliInput or
this instanceof FileInput
}
}
/**
* A node with input from the local environment, such as
* environment variables.
*/
private class EnvironmentInput extends LocalUserInput {
EnvironmentInput() {
// Results from various specific methods.
this.asExpr().(MethodAccess).getMethod() instanceof EnvReadMethod
}
override string getThreatModel() { result = "environment" }
}
/**
* A node with input from the command line, such as standard in
* and main method parameters.
*/
private class CliInput extends LocalUserInput {
CliInput() {
// Parameters to a main method.
exists(MainMethod main | this.asParameter() = main.getParameter(0))
or
@@ -191,23 +255,46 @@ class EnvInput extends LocalUserInput {
f.getAnAnnotation().getType().getQualifiedName() = "org.kohsuke.args4j.Argument"
)
or
// Results from various specific methods.
this.asExpr().(MethodAccess).getMethod() instanceof EnvReadMethod
or
// Access to `System.in`.
exists(Field f | this.asExpr() = f.getAnAccess() | f instanceof SystemIn)
or
}
override string getThreatModel() { result = "commandargs" }
}
/**
* A node with input from the local environment, such as files.
*/
private class FileInput extends LocalUserInput {
FileInput() {
// Access to files.
this.asExpr()
.(ConstructorCall)
.getConstructedType()
.hasQualifiedName("java.io", "FileInputStream")
}
override string getThreatModel() { result = "file" }
}
/** A node with input from a database. */
class DatabaseInput extends LocalUserInput {
DatabaseInput() { this.asExpr().(MethodAccess).getMethod() instanceof ResultSetGetStringMethod }
/**
* DEPRECATED: Use the threat models feature.
* That is, use `ThreatModelFlowSource` as the class of nodes for sources
* and set up the threat model configuration to filter source nodes.
* Alternatively, use `getThreatModel` to filter nodes to create the
* class of nodes you need.
*
* A node with input from a database.
*/
deprecated class DatabaseInput = DbInput;
/**
* A node with input from a database.
*/
private class DbInput extends LocalUserInput {
DbInput() { this.asExpr().(MethodAccess).getMethod() instanceof ResultSetGetStringMethod }
override string getThreatModel() { result = "database" }
}
/** A method that reads from the environment, such as `System.getProperty` or `System.getenv`. */

View File

@@ -23,6 +23,7 @@ private module Frameworks {
private import semmle.code.java.frameworks.InputStream
private import semmle.code.java.frameworks.Properties
private import semmle.code.java.frameworks.Protobuf
private import semmle.code.java.frameworks.ThreadLocal
private import semmle.code.java.frameworks.ratpack.RatpackExec
private import semmle.code.java.frameworks.stapler.Stapler
}
@@ -57,6 +58,22 @@ abstract class FluentMethod extends ValuePreservingMethod {
override predicate returnsValue(int arg) { arg = -1 }
}
/**
* A unit class for adding additional data flow nodes.
*
* Extend this class to add additional data flow nodes for use in globally
* applicable additional steps.
*/
class AdditionalDataFlowNode extends Unit {
/**
* Holds if an additional node is needed in relation to `e`. The pair `(e,id)`
* must uniquely identify the node.
* The added node can be selected for use in a predicate by the corresponding
* `DataFlow::AdditionalNode.nodeAt(Expr e, string id)` predicate.
*/
abstract predicate nodeAt(Expr e, string id);
}
/**
* A unit class for adding additional taint steps.
*
@@ -85,6 +102,36 @@ class AdditionalValueStep extends Unit {
abstract predicate step(DataFlow::Node node1, DataFlow::Node node2);
}
/**
* A unit class for adding additional store steps.
*
* Extend this class to add additional store steps that should apply to all
* data flow configurations. A store step must be local, so non-local steps are
* ignored.
*/
class AdditionalStoreStep extends Unit {
/**
* Holds if the step from `node1` to `node2` is a store step of `c` and should
* apply to all data flow configurations.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Content c, DataFlow::Node node2);
}
/**
* A unit class for adding additional read steps.
*
* Extend this class to add additional read steps that should apply to all
* data flow configurations. A read step must be local, so non-local steps are
* ignored.
*/
class AdditionalReadStep extends Unit {
/**
* Holds if the step from `node1` to `node2` is a read step of `c` and should
* apply to all data flow configurations.
*/
abstract predicate step(DataFlow::Node node1, DataFlow::Content c, DataFlow::Node node2);
}
/**
* A method or constructor that preserves taint.
*

View File

@@ -440,6 +440,18 @@ predicate arrayInstanceOfGuarded(ArrayAccess aa, RefType t) {
)
}
/**
* Holds if `t` is the type of the `this` value corresponding to the the
* `SuperAccess`. As the `SuperAccess` expression has the type of the supertype,
* the type `t` is a stronger type bound.
*/
private predicate superAccess(SuperAccess sup, RefType t) {
sup.isEnclosingInstanceAccess(t)
or
sup.isOwnInstanceAccess() and
t = sup.getEnclosingCallable().getDeclaringType()
}
/**
* Holds if `n` has type `t` and this information is discarded, such that `t`
* might be a better type bound for nodes where `n` flows to. This might include
@@ -452,7 +464,8 @@ private predicate typeFlowBaseCand(TypeFlowNode n, RefType t) {
downcastSuccessor(n.asExpr(), srctype) or
instanceOfGuarded(n.asExpr(), srctype) or
arrayInstanceOfGuarded(n.asExpr(), srctype) or
n.asExpr().(FunctionalExpr).getConstructedType() = srctype
n.asExpr().(FunctionalExpr).getConstructedType() = srctype or
superAccess(n.asExpr(), srctype)
|
t = srctype.(BoundedType).getAnUltimateUpperBoundType()
or

View File

@@ -171,16 +171,6 @@ private module DispatchImpl {
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[inline]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
/**
* Holds if flow from `call`'s argument `arg` to parameter `p` is permissible.
*
* This is a temporary hook to support technical debt in the Go language; do not use.
*/
pragma[inline]
predicate golangSpecificParamArgFilter(DataFlowCall call, ParameterNode p, ArgumentNode arg) {
any()
}
}
import DispatchImpl

View File

@@ -297,6 +297,10 @@ private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isBarrierIn(Node node, FlowState state) { none() }
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)

View File

@@ -297,6 +297,10 @@ private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isBarrierIn(Node node, FlowState state) { none() }
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)

View File

@@ -297,6 +297,10 @@ private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node) { any(Configuration config).isBarrierOut(node) }
predicate isBarrierIn(Node node, FlowState state) { none() }
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)

Some files were not shown because too many files have changed in this diff Show More