Merge remote-tracking branch 'origin/codeql-cli-2.16.1' into henrymercer/2.16.0-mergeback

This commit is contained in:
Henry Mercer
2024-01-26 13:53:13 +00:00
998 changed files with 31034 additions and 13698 deletions

View File

@@ -1,20 +1,59 @@
#!/bin/bash
set -e
# Add help message
help="Usage: ./publish [--override-release] [--dry-run]
Publish the automodel query pack.
If no arguments are provided, publish the version of the codeql repo specified by the latest official release of the codeml-automodel repo.
If the --override-release argument is provided, your current local HEAD is used (for unofficial releases or patching).
If the --dry-run argument is provided, the release is not published (for testing purposes)."
# Echo the help message
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
echo "Usage: ./publish [override-release]"
echo "By default we publish the version of the codeql repo specified by the latest official release defined by the codeml-automodel repo."
echo "Otherwise, the optional argument override-release forces your current HEAD to be published."
echo "$help"
exit 0
fi
# Check that either there are 0 or 1 arguments, and if 1 argument then check that it is "override-release"
if [ $# -gt 1 ] || [ $# -eq 1 ] && [ "$1" != "override-release" ]; then
echo "Error: Invalid arguments. Please run './publish --help' for usage information."
# Check the number of arguments are valid
if [ $# -gt 2 ]; then
echo "Error: Invalid arguments provided"
echo "$help"
exit 1
fi
OVERRIDE_RELEASE=0
DRY_RUN=0
for arg in "$@"
do
case $arg in
--override-release)
OVERRIDE_RELEASE=1
shift # Remove --override-release from processing
;;
--dry-run)
DRY_RUN=1
shift # Remove --dry-run from processing
;;
*)
echo "Error: Invalid argument provided: $arg"
echo "$help"
exit 1
;;
esac
done
# Describe what we're about to do based on the command-line arguments
if [ $OVERRIDE_RELEASE = 1 ]; then
echo "Publishing the current HEAD of the automodel repo"
else
echo "Publishing the version of the automodel repo specified by the latest official release of the codeml-automodel repo"
fi
if [ $DRY_RUN = 1 ]; then
echo "Dry run: we will step through the process but we won't publish the query pack"
else
echo "Not a dry run! Publishing the query pack"
fi
# If we're publishing the codeml-automodel release then we will checkout the sha specified in the release.
# So we need to check that there are no uncommitted changes in the local branch.
# And, if we're publishing the current HEAD, it's cleaner to ensure that there are no uncommitted changes.
@@ -28,10 +67,6 @@ if [ -z "${GITHUB_TOKEN}" ]; then
echo "Error: GITHUB_TOKEN environment variable not set. Please set this to a token with package:write permissions to codeql."
exit 1
fi
if [ -z "${CODEQL_DIST}" ]; then
echo "Error: CODEQL_DIST environment variable not set. Please set this to the path of a codeql distribution."
exit 1
fi
if [ -z "${GH_TOKEN}" ]; then
echo "Error: GH_TOKEN environment variable not set. Please set this to a token with repo permissions to github/codeml-automodel."
exit 1
@@ -49,8 +84,14 @@ fi
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
CURRENT_SHA=$(git rev-parse HEAD)
if [ -z "${1:-}" ]; then
# If the first argument is empty, use the latest release of codeml-automodel
if [ $OVERRIDE_RELEASE = 1 ]; then
# Check that the current HEAD is downstream from PREVIOUS_RELEASE_SHA
if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$CURRENT_SHA"; then
echo "Error: The current HEAD is not downstream from the previous release"
exit 1
fi
else
# Get the latest release of codeml-automodel
TAG_NAME=$(gh api -H 'Accept: application/vnd.github+json' -H 'X-GitHub-Api-Version: 2022-11-28' /repos/github/codeml-automodel/releases/latest | jq -r .tag_name)
# Check TAG_NAME is not empty
if [ -z "$TAG_NAME" ]; then
@@ -73,12 +114,6 @@ if [ -z "${1:-}" ]; then
fi
# Get the version of the codeql code specified by the codeml-automodel release
git checkout "$REVISION"
else
# Check that the current HEAD is downstream from PREVIOUS_RELEASE_SHA
if ! git merge-base --is-ancestor "$PREVIOUS_RELEASE_SHA" "$CURRENT_SHA"; then
echo "Error: The current HEAD is not downstream from the previous release"
exit 1
fi
fi
# Get the absolute path of the automodel repo
@@ -88,21 +123,28 @@ WORKSPACE_ROOT="$AUTOMODEL_ROOT/../../.."
# Specify the groups of queries to test and publish
GRPS="automodel,-test"
# Install the codeql gh extension
gh extensions install github/gh-codeql
pushd "$AUTOMODEL_ROOT"
echo Testing automodel queries
"${CODEQL_DIST}/codeql" test run test
gh codeql test run test
popd
pushd "$WORKSPACE_ROOT"
echo "Preparing the release"
"${CODEQL_DIST}/codeql" pack release --groups $GRPS -v
gh codeql pack release --groups $GRPS -v
echo "Publishing the release"
# Add --dry-run to test publishing
"${CODEQL_DIST}/codeql" pack publish --groups $GRPS -v
if [ $DRY_RUN = 1 ]; then
echo "Dry run: not publishing the query pack"
gh codeql pack publish --groups $GRPS --dry-run -v
else
echo "Not a dry run! Publishing the query pack"
gh codeql pack publish --groups $GRPS -v
fi
echo "Bumping versions"
"${CODEQL_DIST}/codeql" pack post-release --groups $GRPS -v
gh codeql pack post-release --groups $GRPS -v
popd
# The above commands update
@@ -112,18 +154,44 @@ popd
# and add a new file
# ./src/change-notes/released/<version>.md
if [ -z "${1:-}" ]; then
# If we used the latest release of codeml-automodel, then we need to return to the current branch
git checkout "$CURRENT_BRANCH"
# Get the filename of the most recently created file in ./src/change-notes/released/*.md
# This will be the file for the new release
NEW_CHANGE_NOTES_FILE=$(ls -t ./src/change-notes/released/*.md | head -n 1)
# Make a copy of the modified files
mv ./src/CHANGELOG.md ./src/CHANGELOG.md.dry-run
mv ./src/codeql-pack.release.yml ./src/codeql-pack.release.yml.dry-run
mv ./src/qlpack.yml ./src/qlpack.yml.dry-run
mv "$NEW_CHANGE_NOTES_FILE" ./src/change-notes/released.md.dry-run
if [ $OVERRIDE_RELEASE = 1 ]; then
# Restore the original files
git checkout ./src/CHANGELOG.md
git checkout ./src/codeql-pack.release.yml
git checkout ./src/qlpack.yml
else
# Restore the original files
git checkout "$CURRENT_BRANCH" --force
fi
# Add the updated files to the current branch
git add ./src/CHANGELOG.md
git add ./src/codeql-pack.release.yml
git add ./src/qlpack.yml
git add ./src/change-notes/released/*
echo "Added the following updated version files to the current branch:"
git status -s
echo "Automodel packs successfully published. Local files have been modified. Please commit and push the version changes and then merge into main."
if [ $DRY_RUN = 1 ]; then
echo "Inspect the updated dry-run version files:"
ls -l ./src/*.dry-run
ls -l ./src/change-notes/*.dry-run
else
# Add the updated files to the current branch
echo "Adding the version changes"
mv -f ./src/CHANGELOG.md.dry-run ./src/CHANGELOG.md
mv -f ./src/codeql-pack.release.yml.dry-run ./src/codeql-pack.release.yml
mv -f ./src/qlpack.yml.dry-run ./src/qlpack.yml
mv -f ./src/change-notes/released.md.dry-run "$NEW_CHANGE_NOTES_FILE"
git add ./src/CHANGELOG.md
git add ./src/codeql-pack.release.yml
git add ./src/qlpack.yml
git add "$NEW_CHANGE_NOTES_FILE"
echo "Added the following updated version files to the current branch:"
git status -s
echo "To complete the release, please commit these files and merge to the main branch"
fi
echo "Done"

View File

@@ -15,7 +15,6 @@ private import semmle.code.java.security.QueryInjection
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
private import AutomodelJavaUtil as AutomodelJavaUtil
private import semmle.code.java.security.PathSanitizer as PathSanitizer
private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
import AutomodelSharedCharacteristics as SharedCharacteristics
import AutomodelEndpointTypes as AutomodelEndpointTypes
@@ -26,14 +25,18 @@ newtype JavaRelatedLocationType =
newtype TApplicationModeEndpoint =
TExplicitArgument(Call call, DataFlow::Node arg) {
AutomodelJavaUtil::isFromSource(call) and
exists(Argument argExpr |
arg.asExpr() = argExpr and call = argExpr.getCall() and not argExpr.isVararg()
)
} or
TInstanceArgument(Call call, DataFlow::Node arg) {
arg = DataFlow::getInstanceArgument(call) and not call instanceof ConstructorCall
AutomodelJavaUtil::isFromSource(call) and
arg = DataFlow::getInstanceArgument(call) and
not call instanceof ConstructorCall
} or
TImplicitVarargsArray(Call call, DataFlow::Node arg, int idx) {
AutomodelJavaUtil::isFromSource(call) and
exists(Argument argExpr |
arg.asExpr() = argExpr and
call.getArgument(idx) = argExpr and
@@ -41,8 +44,12 @@ newtype TApplicationModeEndpoint =
not exists(int i | i < idx and call.getArgument(i).(Argument).isVararg())
)
} or
TMethodReturnValue(Call call) { not call instanceof ConstructorCall } or
TMethodReturnValue(Call call) {
AutomodelJavaUtil::isFromSource(call) and
not call instanceof ConstructorCall
} or
TOverriddenParameter(Parameter p, Method overriddenMethod) {
AutomodelJavaUtil::isFromSource(p) and
not p.getCallable().callsConstructor(_) and
p.getCallable().(Method).overrides(overriddenMethod)
}
@@ -56,8 +63,6 @@ abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint
*/
abstract Callable getCallable();
abstract Call getCall();
/**
* Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
*
@@ -91,50 +96,50 @@ abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint
abstract string toString();
}
class TCallArgument = TExplicitArgument or TInstanceArgument or TImplicitVarargsArray;
/**
* A class representing nodes that are arguments to calls.
* An endpoint that represents an "argument" to a call in a broad sense, including
* both explicit arguments and the instance argument.
*/
class ExplicitArgument extends ApplicationModeEndpoint, TExplicitArgument {
abstract class CallArgument extends ApplicationModeEndpoint, TCallArgument {
Call call;
DataFlow::Node arg;
ExplicitArgument() { this = TExplicitArgument(call, arg) }
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
override Call getCall() { result = call }
override string getMaDOutput() { none() }
override DataFlow::Node asNode() { result = arg }
Call getCall() { result = call }
override string toString() { result = arg.toString() }
}
/**
* An endpoint that represents an explicit argument to a call.
*/
class ExplicitArgument extends CallArgument, TExplicitArgument {
ExplicitArgument() { this = TExplicitArgument(call, arg) }
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() }
override DataFlow::Node asNode() { result = arg }
override string toString() { result = arg.toString() }
}
class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
Call call;
DataFlow::Node arg;
/**
* An endpoint that represents the instance argument to a call.
*/
class InstanceArgument extends CallArgument, TInstanceArgument {
InstanceArgument() { this = TInstanceArgument(call, arg) }
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
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 }
override DataFlow::Node asNode() { result = arg }
override string toString() { result = arg.toString() }
}
@@ -147,26 +152,14 @@ class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
* In order to be able to distinguish between varargs endpoints and regular endpoints, we export the `isVarargsArray`
* meta data field in the extraction queries.
*/
class ImplicitVarargsArray extends ApplicationModeEndpoint, TImplicitVarargsArray {
Call call;
DataFlow::Node vararg;
class ImplicitVarargsArray extends CallArgument, TImplicitVarargsArray {
int idx;
ImplicitVarargsArray() { this = TImplicitVarargsArray(call, vararg, idx) }
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
override Call getCall() { result = call }
ImplicitVarargsArray() { this = TImplicitVarargsArray(call, arg, idx) }
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() }
}
/**
@@ -180,8 +173,6 @@ class MethodReturnValue extends ApplicationModeEndpoint, TMethodReturnValue {
override Callable getCallable() { result = call.getCallee().getSourceDeclaration() }
override Call getCall() { result = call }
override string getMaDInput() { none() }
override string getMaDOutput() { result = "ReturnValue" }
@@ -211,8 +202,6 @@ class OverriddenParameter extends ApplicationModeEndpoint, TOverriddenParameter
result = overriddenMethod.getSourceDeclaration()
}
override Call getCall() { none() }
private int getArgIndex() { p.getCallable().getParameter(result) = p }
override string getMaDInput() { none() }
@@ -239,7 +228,9 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
class EndpointType = AutomodelEndpointTypes::EndpointType;
class NegativeEndpointType = AutomodelEndpointTypes::NegativeSinkType;
class SinkType = AutomodelEndpointTypes::SinkType;
class SourceType = AutomodelEndpointTypes::SourceType;
class RelatedLocation = Location::Top;
@@ -248,13 +239,12 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
// Sanitizers are currently not modeled in MaD. TODO: check if this has large negative impact.
predicate isSanitizer(Endpoint e, EndpointType t) {
exists(t) and
(
e.asNode().getType() instanceof BoxedType
or
e.asNode().getType() instanceof PrimitiveType
or
e.asNode().getType() instanceof NumberType
)
AutomodelJavaUtil::isUnexploitableType([
// for most endpoints, we can get the type from the node
e.asNode().getType(),
// but not for calls to void methods, where we need to go via the AST
e.asTop().(Expr).getType()
])
or
t instanceof AutomodelEndpointTypes::PathInjectionSinkType and
e.asNode() instanceof PathSanitizer::PathInjectionSanitizer
@@ -316,7 +306,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
*/
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
type = CallContext() and
result = e.getCall()
result = e.(CallArgument).getCall()
or
type = MethodDoc() and
result = e.getCallable().(Documentable).getJavadoc()
@@ -326,22 +316,6 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
}
}
private class JavaCallable = Callable;
private module ApplicationModeGetCallable implements AutomodelSharedGetCallable::GetCallableSig {
class Callable = JavaCallable;
class Endpoint = ApplicationCandidatesImpl::Endpoint;
/**
* Returns the API callable being modeled.
*
* We usually want to use `.getSourceDeclaration()` instead of just 'the' callable,
* because the source declaration callable has erased generic type parameters.
*/
Callable getCallable(Endpoint e) { result = e.getCall().getCallee() }
}
/**
* Contains endpoints that are defined in QL code rather than as a MaD model. Ideally this predicate
* should be empty.
@@ -369,10 +343,10 @@ class ApplicationModeMetadataExtractor extends string {
predicate hasMetadata(
Endpoint e, string package, string type, string subtypes, string name, string signature,
string input, string output, string isVarargsArray
string input, string output, string isVarargsArray, string alreadyAiModeled,
string extensibleType
) {
exists(Callable callable |
e.getCallable() = callable and
exists(Callable callable | e.getCallable() = callable |
(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
@@ -382,19 +356,107 @@ class ApplicationModeMetadataExtractor extends string {
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
name = callable.getName() and
signature = ExternalFlow::paramsString(callable) and
if e instanceof ImplicitVarargsArray
then isVarargsArray = "true"
else isVarargsArray = "false"
(
if e instanceof ImplicitVarargsArray
then isVarargsArray = "true"
else isVarargsArray = "false"
) and
extensibleType = e.getExtensibleType()
) and
(
not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
or
CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
)
}
}
/**
* Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
*
* The other parameters record various other properties of interest.
*/
predicate isCandidate(
Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
) {
CharacteristicsImpl::isCandidate(endpoint, _) and
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
) and
any(ApplicationModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargs,
alreadyAiModeled, 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.
alreadyAiModeled.matches(["", "%ai-%"]) and
AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
}
/**
* Holds if the given `endpoint` is a negative example for the `extensibleType`
* because of the `characteristic`.
*
* The other parameters record various other properties of interest.
*/
predicate isNegativeExample(
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
string type, string subtypes, string name, string signature, string input, string output,
string isVarargsArray, string extensibleType
) {
characteristic.appliesToEndpoint(endpoint) and
// the node is known not to be an endpoint of any appropriate type
forall(AutomodelEndpointTypes::EndpointType tp |
tp = CharacteristicsImpl::getAPotentialType(endpoint)
|
characteristic.hasImplications(tp, false, _)
) and
// the lowest confidence across all endpoint types should be at least highConfidence
confidence =
min(float c |
characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
) and
confidence >= SharedCharacteristics::highConfidence() and
any(ApplicationModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
isVarargsArray, _, extensibleType) and
// It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
// as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
not exists(EndpointCharacteristic characteristic2, float confidence2 |
characteristic2 != characteristic
|
characteristic2.appliesToEndpoint(endpoint) and
confidence2 >= SharedCharacteristics::maximalConfidence() and
characteristic2
.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
)
}
/**
* Holds if the given `endpoint` is a positive example for the `endpointType`.
*
* The other parameters record various other properties of interest.
*/
predicate isPositiveExample(
Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
string signature, string input, string output, string isVarargsArray, string extensibleType
) {
any(ApplicationModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output,
isVarargsArray, _, extensibleType) and
CharacteristicsImpl::isKnownAs(endpoint, endpointType, _) and
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
}
/*
* EndpointCharacteristic classes that are specific to Automodel for Java.
*/
/**
* A negative characteristic that indicates that an is-style boolean method is unexploitable even if it is a sink.
* A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks.
*
* A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
* type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
@@ -406,15 +468,15 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
UnexploitableIsCharacteristic() { this = "unexploitable (is-style boolean method)" }
override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::isSink(e, _, _) and
e.getCallable().getName().matches("is%") and
e.getCallable().getReturnType() instanceof BooleanType
e.getCallable().getReturnType() instanceof BooleanType and
not ApplicationCandidatesImpl::isSink(e, _, _)
}
}
/**
* A negative characteristic that indicates that an existence-checking boolean method is unexploitable even if it is a
* sink.
* A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
* considered sinks.
*
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
@@ -424,9 +486,7 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
override predicate appliesToEndpoint(Endpoint e) {
not ApplicationCandidatesImpl::isSink(e, _, _) and
exists(Callable callable |
callable = ApplicationModeGetCallable::getCallable(e) and
exists(Callable callable | callable = e.getCallable() |
callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType
)
@@ -434,14 +494,23 @@ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::Not
}
/**
* A negative characteristic that indicates that an endpoint is an argument to an exception, which is not a sink.
* A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
* and its return value should not be considered a source.
*/
private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
{
ExceptionCharacteristic() { this = "exception" }
override predicate appliesToEndpoint(Endpoint e) {
ApplicationModeGetCallable::getCallable(e).getDeclaringType().getASupertype*() instanceof
TypeThrowable
e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
(
e.getExtensibleType() = "sinkModel" and
not ApplicationCandidatesImpl::isSink(e, _, _)
or
e.getExtensibleType() = "sourceModel" and
not ApplicationCandidatesImpl::isSource(e, _, _) and
e.getMaDOutput() = "ReturnValue"
)
}
}
@@ -454,7 +523,6 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
IsMaDTaintStepCharacteristic() { this = "taint step" }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(e.asNode(), _, _)
or
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(e.asNode(), _, _)
@@ -475,18 +543,20 @@ private class LocalCall extends CharacteristicsImpl::UninterestingToModelCharact
LocalCall() { this = "local call" }
override predicate appliesToEndpoint(Endpoint e) {
ApplicationModeGetCallable::getCallable(e).fromSource()
e.(CallArgument).getCallable().fromSource()
or
e.(MethodReturnValue).getCallable().fromSource()
}
}
/**
* A Characteristic that marks endpoints as uninteresting to model, according to the Java ModelExclusions module.
* A characteristic that marks endpoints as uninteresting to model, according to the Java ModelExclusions module.
*/
private class ExcludedFromModeling extends CharacteristicsImpl::UninterestingToModelCharacteristic {
ExcludedFromModeling() { this = "excluded from modeling" }
override predicate appliesToEndpoint(Endpoint e) {
ModelExclusions::isUninterestingForModels(ApplicationModeGetCallable::getCallable(e))
ModelExclusions::isUninterestingForModels(e.getCallable())
}
}
@@ -499,8 +569,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()
exists(Callable c | c = e.getCallable() | not c.isPublic())
}
}
@@ -522,11 +591,10 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
}
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
not ApplicationCandidatesImpl::isSink(e, _, _) and
exists(Endpoint otherSink |
exists(CallArgument otherSink |
ApplicationCandidatesImpl::isSink(otherSink, _, "manual") and
e.getCall() = otherSink.getCall() and
e.(CallArgument).getCall() = otherSink.getCall() and
e != otherSink
)
}
@@ -540,10 +608,7 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
private class FunctionValueCharacteristic extends CharacteristicsImpl::LikelyNotASinkCharacteristic {
FunctionValueCharacteristic() { this = "function value" }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
e.asNode().asExpr() instanceof FunctionalExpr
}
override predicate appliesToEndpoint(Endpoint e) { e.asNode().asExpr() instanceof FunctionalExpr }
}
/**
@@ -557,10 +622,7 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
{
CannotBeTaintedCharacteristic() { this = "cannot be tainted" }
override predicate appliesToEndpoint(Endpoint e) {
e.getExtensibleType() = "sinkModel" and
not this.isKnownOutNodeForStep(e)
}
override predicate appliesToEndpoint(Endpoint e) { not this.isKnownOutNodeForStep(e) }
/**
* Holds if the node `n` is known as the predecessor in a modeled flow step.

View File

@@ -25,20 +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 output, string isVarargs, string extensibleType
string input, string output, string isVarargs, string extensibleType, string alreadyAiModeled
) {
exists(int n, int num_endpoints, ApplicationModeMetadataExtractor meta |
num_endpoints =
count(Endpoint e |
e.getExtensibleType() = extensibleType and
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs)
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
alreadyAiModeled, extensibleType)
)
|
result =
rank[n](Endpoint e, Location loc |
loc = e.asTop().getLocation() and
e.getExtensibleType() = extensibleType and
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs)
meta.hasMetadata(e, package, type, subtypes, name, signature, input, output, isVarargs,
alreadyAiModeled, extensibleType)
|
e
order by
@@ -55,31 +55,15 @@ private Endpoint getSampleForSignature(
}
from
Endpoint endpoint, ApplicationModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString output, DollarAtString isVarargsArray,
DollarAtString alreadyAiModeled, DollarAtString extensibleType
Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
DollarAtString name, DollarAtString signature, DollarAtString input, DollarAtString output,
DollarAtString isVarargsArray, DollarAtString alreadyAiModeled, DollarAtString extensibleType
where
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
) and
CharacteristicsImpl::isSinkCandidate(endpoint, _) and
isCandidate(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray,
extensibleType, alreadyAiModeled) and
endpoint =
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::isModeled(endpoint, _, _, _) and alreadyAiModeled = ""
or
alreadyAiModeled.matches("%ai-%") and
CharacteristicsImpl::isModeled(endpoint, _, _, alreadyAiModeled)
) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, isVarargsArray) and
includeAutomodelCandidate(package, type, name, signature)
isVarargsArray, extensibleType, alreadyAiModeled)
select endpoint.asNode(),
"Related locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()), "CallContext", //

View File

@@ -42,25 +42,13 @@ Endpoint getSampleForCharacteristic(EndpointCharacteristic c, int limit) {
from
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string message,
ApplicationModeMetadataExtractor meta, DollarAtString package, DollarAtString type,
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
DollarAtString output, DollarAtString isVarargsArray, DollarAtString extensibleType
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
DollarAtString signature, DollarAtString input, 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
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
// they're ambiguous and might confuse the model, so we explicitly exclude all known sinks from the negative examples.
not exists(EndpointCharacteristic characteristic2, float confidence2, SinkType positiveType |
not positiveType instanceof NegativeSinkType and
characteristic2.appliesToEndpoint(endpoint) and
confidence2 >= SharedCharacteristics::maximalConfidence() and
characteristic2.hasImplications(positiveType, true, confidence2)
) and
isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
input, output, isVarargsArray, extensibleType) and
message = characteristic
select endpoint.asNode(),
message + "\nrelated locations: $@, $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //

View File

@@ -18,11 +18,8 @@ from
DollarAtString signature, DollarAtString input, DollarAtString output,
DollarAtString isVarargsArray, DollarAtString extensibleType
where
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::isKnownAs(endpoint, endpointType, _) and
exists(CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, CallContext()))
isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
isVarargsArray, extensibleType)
select endpoint.asNode(),
endpointType + "\nrelated locations: $@, $@, $@." +
"\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //

View File

@@ -30,11 +30,6 @@ abstract class SinkType extends EndpointType {
SinkType() { any() }
}
/** The `Negative` class for non-sinks. */
class NegativeSinkType extends SinkType {
NegativeSinkType() { this = "non-sink" }
}
/** A sink relevant to the SQL injection query */
class SqlInjectionSinkType extends SinkType {
SqlInjectionSinkType() { this = "sql-injection" }

View File

@@ -15,7 +15,6 @@ private import semmle.code.java.security.QueryInjection
private import semmle.code.java.security.RequestForgery
private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
private import AutomodelJavaUtil as AutomodelJavaUtil
private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
import AutomodelSharedCharacteristics as SharedCharacteristics
import AutomodelEndpointTypes as AutomodelEndpointTypes
@@ -25,32 +24,29 @@ newtype JavaRelatedLocationType =
newtype TFrameworkModeEndpoint =
TExplicitParameter(Parameter p) {
not p.getType() instanceof PrimitiveType and
not p.getType() instanceof BoxedType and
not p.getType() instanceof NumberType
AutomodelJavaUtil::isFromSource(p) and
not AutomodelJavaUtil::isUnexploitableType(p.getType())
} or
TQualifier(Callable c) { not c instanceof Constructor } or
TQualifier(Callable c) { AutomodelJavaUtil::isFromSource(c) and not c instanceof Constructor } or
TReturnValue(Callable c) {
AutomodelJavaUtil::isFromSource(c) and
c instanceof Constructor
or
AutomodelJavaUtil::isFromSource(c) and
c instanceof Method and
(
not c.getReturnType() instanceof VoidType and
not c.getReturnType() instanceof PrimitiveType
)
not AutomodelJavaUtil::isUnexploitableType(c.getReturnType())
} or
TOverridableParameter(Method m, Parameter p) {
AutomodelJavaUtil::isFromSource(p) and
not AutomodelJavaUtil::isUnexploitableType(p.getType()) and
p.getCallable() = m and
m instanceof ModelExclusions::ModelApi and
not m.getDeclaringType().isFinal() and
not m.isFinal() and
not m.isStatic()
AutomodelJavaUtil::isOverridable(m)
} or
TOverridableQualifier(Method m) {
AutomodelJavaUtil::isFromSource(m) and
m instanceof ModelExclusions::ModelApi and
not m.getDeclaringType().isFinal() and
not m.isFinal() and
not m.isStatic()
AutomodelJavaUtil::isOverridable(m)
}
/**
@@ -79,7 +75,7 @@ abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
/**
* Returns the callable that contains the endpoint.
*/
abstract Callable getEnclosingCallable();
abstract Callable getCallable();
abstract Top asTop();
@@ -101,7 +97,7 @@ class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParamete
override string getParamName() { result = param.getName() }
override Callable getEnclosingCallable() { result = param.getCallable() }
override Callable getCallable() { result = param.getCallable() }
override Top asTop() { result = param }
@@ -121,7 +117,7 @@ class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
override string getParamName() { result = "this" }
override Callable getEnclosingCallable() { result = callable }
override Callable getCallable() { result = callable }
override Top asTop() { result = callable }
@@ -139,7 +135,7 @@ class ReturnValue extends FrameworkModeEndpoint, TReturnValue {
override string getParamName() { none() }
override Callable getEnclosingCallable() { result = callable }
override Callable getCallable() { result = callable }
override Top asTop() { result = callable }
@@ -158,7 +154,7 @@ class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter
override string getParamName() { result = param.getName() }
override Callable getEnclosingCallable() { result = method }
override Callable getCallable() { result = method }
override Top asTop() { result = param }
@@ -176,7 +172,7 @@ class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier
override string getParamName() { result = "this" }
override Callable getEnclosingCallable() { result = m }
override Callable getCallable() { result = m }
override Top asTop() { result = m }
@@ -197,7 +193,9 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
class EndpointType = AutomodelEndpointTypes::EndpointType;
class NegativeEndpointType = AutomodelEndpointTypes::NegativeSinkType;
class SinkType = AutomodelEndpointTypes::SinkType;
class SourceType = AutomodelEndpointTypes::SourceType;
class RelatedLocation = Location::Top;
@@ -239,8 +237,8 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
additional predicate sinkSpec(
Endpoint e, string package, string type, string name, string signature, string ext, string input
) {
e.getEnclosingCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getEnclosingCallable()) and
e.getCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getCallable()) and
ext = "" and
input = e.getMaDInput()
}
@@ -249,8 +247,8 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
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
e.getCallable().hasQualifiedName(package, type, name) and
signature = ExternalFlow::paramsString(e.getCallable()) and
ext = "" and
output = e.getMaDOutput()
}
@@ -262,10 +260,10 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
*/
RelatedLocation getRelatedLocation(Endpoint e, RelatedLocationType type) {
type = MethodDoc() and
result = e.getEnclosingCallable().(Documentable).getJavadoc()
result = e.getCallable().(Documentable).getJavadoc()
or
type = ClassDoc() and
result = e.getEnclosingCallable().getDeclaringType().(Documentable).getJavadoc()
result = e.getCallable().getDeclaringType().(Documentable).getJavadoc()
}
}
@@ -287,25 +285,116 @@ class FrameworkModeMetadataExtractor extends string {
predicate hasMetadata(
Endpoint e, string package, string type, string subtypes, string name, string signature,
string input, string output, string parameterName
string input, string output, string parameterName, string alreadyAiModeled,
string extensibleType
) {
(if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and
name = e.getEnclosingCallable().getName() 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
signature = ExternalFlow::paramsString(e.getEnclosingCallable())
exists(Callable callable | e.getCallable() = callable |
(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.
type = callable.getDeclaringType().getErasure().(RefType).nestedName() and
subtypes = AutomodelJavaUtil::considerSubtypes(callable).toString() and
name = callable.getName() and
signature = ExternalFlow::paramsString(callable) and
(if exists(e.getParamName()) then parameterName = e.getParamName() else parameterName = "") and
e.getExtensibleType() = extensibleType
) and
(
not CharacteristicsImpl::isModeled(e, _, extensibleType, _) and alreadyAiModeled = ""
or
CharacteristicsImpl::isModeled(e, _, extensibleType, alreadyAiModeled)
)
}
}
/**
* Holds if the given `endpoint` should be considered a candidate for the `extensibleType`.
*
* The other parameters record various other properties of interest.
*/
predicate isCandidate(
Endpoint endpoint, string package, string type, string subtypes, string name, string signature,
string input, string output, string parameterName, string extensibleType, string alreadyAiModeled
) {
CharacteristicsImpl::isCandidate(endpoint, _) and
not exists(CharacteristicsImpl::UninterestingToModelCharacteristic u |
u.appliesToEndpoint(endpoint)
) and
any(FrameworkModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
alreadyAiModeled, 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.
alreadyAiModeled.matches(["", "%ai-%"]) and
AutomodelJavaUtil::includeAutomodelCandidate(package, type, name, signature)
}
/**
* Holds if the given `endpoint` is a negative example for the `extensibleType`
* because of the `characteristic`.
*
* The other parameters record various other properties of interest.
*/
predicate isNegativeExample(
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence, string package,
string type, string subtypes, string name, string signature, string input, string output,
string parameterName, string extensibleType
) {
characteristic.appliesToEndpoint(endpoint) and
// the node is known not to be an endpoint of any appropriate type
forall(AutomodelEndpointTypes::EndpointType tp |
tp = CharacteristicsImpl::getAPotentialType(endpoint)
|
characteristic.hasImplications(tp, false, _)
) and
// the lowest confidence across all endpoint types should be at least highConfidence
confidence =
min(float c |
characteristic.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), false, c)
) and
confidence >= SharedCharacteristics::highConfidence() and
any(FrameworkModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
_, extensibleType) and
// It's valid for a node to be both a potential source/sanitizer and a sink. We don't want to include such nodes
// as negative examples in the prompt, because they're ambiguous and might confuse the model, so we explicitly exclude them here.
not exists(EndpointCharacteristic characteristic2, float confidence2 |
characteristic2 != characteristic
|
characteristic2.appliesToEndpoint(endpoint) and
confidence2 >= SharedCharacteristics::maximalConfidence() and
characteristic2
.hasImplications(CharacteristicsImpl::getAPotentialType(endpoint), true, confidence2)
)
}
/**
* Holds if the given `endpoint` is a positive example for the `endpointType`.
*
* The other parameters record various other properties of interest.
*/
predicate isPositiveExample(
Endpoint endpoint, string endpointType, string package, string type, string subtypes, string name,
string signature, string input, string output, string parameterName, string extensibleType
) {
any(FrameworkModeMetadataExtractor meta)
.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
_, extensibleType) and
CharacteristicsImpl::isKnownAs(endpoint, endpointType, _)
}
/*
* EndpointCharacteristic classes that are specific to Automodel for Java.
*/
/**
* A negative characteristic that indicates that an is-style boolean method is unexploitable even if it is a sink.
* A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks,
* and its return value should not be considered a source.
*
* A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
* type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
@@ -313,45 +402,70 @@ class FrameworkModeMetadataExtractor extends string {
*
* TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
*/
private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
{
UnexploitableIsCharacteristic() { this = "unexploitable (is-style boolean method)" }
override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _, _) and
e.getEnclosingCallable().getName().matches("is%") and
e.getEnclosingCallable().getReturnType() instanceof BooleanType
}
}
/**
* A negative characteristic that indicates that an existence-checking boolean method is unexploitable even if it is a
* sink.
*
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
* dangerous/interesting thing, so we want the latter to be modeled as the sink.
*/
private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
override predicate appliesToEndpoint(Endpoint e) {
not FrameworkCandidatesImpl::isSink(e, _, _) and
exists(Callable callable |
callable = e.getEnclosingCallable() and
callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType
e.getCallable().getName().matches("is%") and
e.getCallable().getReturnType() instanceof BooleanType and
(
e.getExtensibleType() = "sinkModel" and
not FrameworkCandidatesImpl::isSink(e, _, _)
or
e.getExtensibleType() = "sourceModel" and
not FrameworkCandidatesImpl::isSource(e, _, _) and
e.getMaDOutput() = "ReturnValue"
)
}
}
/**
* A negative characteristic that indicates that an endpoint is an argument to an exception, which is not a sink.
* A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
* considered sinks, and its return value should not be considered a source.
*
* A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
* boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
* dangerous/interesting thing, so we want the latter to be modeled as the sink.
*/
private class ExceptionCharacteristic extends CharacteristicsImpl::NotASinkCharacteristic {
private class UnexploitableExistsCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
{
UnexploitableExistsCharacteristic() { this = "unexploitable (existence-checking boolean method)" }
override predicate appliesToEndpoint(Endpoint e) {
exists(Callable callable |
callable = e.getCallable() and
callable.getName().toLowerCase() = ["exists", "notexists"] and
callable.getReturnType() instanceof BooleanType
|
e.getExtensibleType() = "sinkModel" and
not FrameworkCandidatesImpl::isSink(e, _, _)
or
e.getExtensibleType() = "sourceModel" and
not FrameworkCandidatesImpl::isSource(e, _, _) and
e.getMaDOutput() = "ReturnValue"
)
}
}
/**
* A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
* and its return value should not be considered a source.
*/
private class ExceptionCharacteristic extends CharacteristicsImpl::NeitherSourceNorSinkCharacteristic
{
ExceptionCharacteristic() { this = "exception" }
override predicate appliesToEndpoint(Endpoint e) {
e.getEnclosingCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable
e.getCallable().getDeclaringType().getASupertype*() instanceof TypeThrowable and
(
e.getExtensibleType() = "sinkModel" and
not FrameworkCandidatesImpl::isSink(e, _, _)
or
e.getExtensibleType() = "sourceModel" and
not FrameworkCandidatesImpl::isSource(e, _, _) and
e.getMaDOutput() = "ReturnValue"
)
}
}
@@ -363,6 +477,6 @@ private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelChar
NotAModelApi() { this = "not a model API" }
override predicate appliesToEndpoint(Endpoint e) {
not e.getEnclosingCallable() instanceof ModelExclusions::ModelApi
not e.getCallable() instanceof ModelExclusions::ModelApi
}
}

View File

@@ -16,29 +16,12 @@ private import AutomodelFrameworkModeCharacteristics
private import AutomodelJavaUtil
from
Endpoint endpoint, FrameworkModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString output, DollarAtString parameterName,
DollarAtString alreadyAiModeled, DollarAtString extensibleType
Endpoint endpoint, DollarAtString package, DollarAtString type, DollarAtString subtypes,
DollarAtString name, DollarAtString signature, 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
// 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 = ""
or
alreadyAiModeled.matches("%ai-%") and
CharacteristicsImpl::isSink(endpoint, _, alreadyAiModeled)
) and
meta.hasMetadata(endpoint, package, type, subtypes, name, signature, input, output, parameterName) and
includeAutomodelCandidate(package, type, name, signature)
isCandidate(endpoint, package, type, subtypes, name, signature, input, output, parameterName,
extensibleType, alreadyAiModeled)
select endpoint,
"Related locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //

View File

@@ -14,29 +14,15 @@ private import AutomodelJavaUtil
from
Endpoint endpoint, EndpointCharacteristic characteristic, float confidence,
DollarAtString message, FrameworkModeMetadataExtractor meta, DollarAtString package,
DollarAtString type, DollarAtString subtypes, DollarAtString name, DollarAtString signature,
DollarAtString input, DollarAtString output, DollarAtString parameterName,
DollarAtString extensibleType
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
DollarAtString signature, 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
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
// they're ambiguous and might confuse the model, so we explicitly exclude all known sinks from the negative examples.
not exists(EndpointCharacteristic characteristic2, float confidence2, SinkType positiveType |
not positiveType instanceof NegativeSinkType and
characteristic2.appliesToEndpoint(endpoint) and
confidence2 >= SharedCharacteristics::maximalConfidence() and
characteristic2.hasImplications(positiveType, true, confidence2)
) and
message = characteristic
isNegativeExample(endpoint, characteristic, confidence, package, type, subtypes, name, signature,
input, output, parameterName, extensibleType)
select endpoint,
message + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
characteristic + "\nrelated locations: $@, $@." +
"\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, ClassDoc()), "ClassDoc", //
package, "package", //

View File

@@ -13,15 +13,12 @@ private import AutomodelEndpointTypes
private import AutomodelJavaUtil
from
Endpoint endpoint, EndpointType endpointType, FrameworkModeMetadataExtractor meta,
DollarAtString package, DollarAtString type, DollarAtString subtypes, DollarAtString name,
DollarAtString signature, DollarAtString input, DollarAtString output,
DollarAtString parameterName, DollarAtString extensibleType
Endpoint endpoint, EndpointType endpointType, DollarAtString package, DollarAtString type,
DollarAtString subtypes, DollarAtString name, DollarAtString signature, DollarAtString input,
DollarAtString output, DollarAtString parameterName, DollarAtString extensibleType
where
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::isKnownAs(endpoint, endpointType, _)
isPositiveExample(endpoint, endpointType, package, type, subtypes, name, signature, input, output,
parameterName, extensibleType)
select endpoint,
endpointType + "\nrelated locations: $@, $@." + "\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
CharacteristicsImpl::getRelatedLocationOrCandidate(endpoint, MethodDoc()), "MethodDoc", //

View File

@@ -82,3 +82,43 @@ predicate includeAutomodelCandidate(string package, string type, string name, st
not automodelCandidateFilter(_, _, _, _) or
automodelCandidateFilter(package, type, name, signature)
}
/**
* Holds if the given program element corresponds to a piece of source code,
* that is, it is not compiler-generated.
*
* Note: This is a stricter check than `Element::fromSource`, which simply
* checks whether the element is in a source file as opposed to a JAR file.
* There can be compiler-generated elements in source files (especially for
* Kotlin), which we also want to exclude.
*/
predicate isFromSource(Element e) {
// from a source file (not a JAR)
e.fromSource() and
// not explicitly marked as compiler-generated
not e.isCompilerGenerated() and
// does not have a dummy location
not e.hasLocationInfo(_, 0, 0, 0, 0)
}
/**
* Holds if taint cannot flow through the given type (because it is a numeric
* type or some other type with a fixed set of values).
*/
predicate isUnexploitableType(Type tp) {
tp instanceof PrimitiveType or
tp instanceof BoxedType or
tp instanceof NumberType or
tp instanceof VoidType
}
/**
* Holds if the given method can be overridden, that is, it is not final,
* static, or private.
*/
predicate isOverridable(Method m) {
not m.getDeclaringType().isFinal() and
not m.isFinal() and
not m.isStatic() and
not m.isPrivate()
}

View File

@@ -16,7 +16,17 @@ signature module CandidateSig {
* An endpoint is a potential candidate for modeling. This will typically be bound to the language's
* DataFlow node class, or a subtype thereof.
*/
class Endpoint;
class Endpoint {
/**
* Gets the kind of this endpoint, either "sourceModel" or "sinkModel".
*/
string getExtensibleType();
/**
* Gets a string representation of this endpoint.
*/
string toString();
}
/**
* A related location for an endpoint. This will typically be bound to the supertype of all AST nodes (eg., `Top`).
@@ -31,14 +41,19 @@ signature module CandidateSig {
class RelatedLocationType;
/**
* A class kind for an endpoint.
* An endpoint type considered by this specification.
*/
class EndpointType extends string;
/**
* An EndpointType that denotes the absence of any sink.
* A sink endpoint type considered by this specification.
*/
class NegativeEndpointType extends EndpointType;
class SinkType extends EndpointType;
/**
* A source endpoint type considered by this specification.
*/
class SourceType extends EndpointType;
/**
* Gets the endpoint as a location.
@@ -103,7 +118,7 @@ module SharedCharacteristics<CandidateSig Candidate> {
}
/**
* Holds if `endpoint` is modeled as `endpointType` (endpoint type must not be negative).
* Holds if `endpoint` is modeled as `endpointType`.
*/
predicate isKnownAs(
Candidate::Endpoint endpoint, Candidate::EndpointType endpointType,
@@ -111,19 +126,31 @@ module SharedCharacteristics<CandidateSig Candidate> {
) {
// 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(endpoint) and
characteristic.hasImplications(endpointType, true, maximalConfidence())
}
/**
* Holds if the candidate sink `candidateSink` should be considered as a possible sink of type `sinkType`, and
* classified by the ML model. A candidate sink is a node that cannot be excluded from `sinkType` based on its
* characteristics.
* Gets a potential type of this endpoint to make sure that sources are
* associated with source types and sinks with sink types.
*/
predicate isSinkCandidate(Candidate::Endpoint candidateSink, Candidate::EndpointType sinkType) {
not sinkType instanceof Candidate::NegativeEndpointType and
not exists(getAReasonSinkExcluded(candidateSink, sinkType))
Candidate::EndpointType getAPotentialType(Candidate::Endpoint endpoint) {
endpoint.getExtensibleType() = "sourceModel" and
result instanceof Candidate::SourceType
or
endpoint.getExtensibleType() = "sinkModel" and
result instanceof Candidate::SinkType
}
/**
* Holds if the given `endpoint` should be considered as a candidate for type `endpointType`,
* and classified by the ML model.
*
* A candidate is an endpoint that cannot be excluded from `endpointType` based on its characteristics.
*/
predicate isCandidate(Candidate::Endpoint endpoint, Candidate::EndpointType endpointType) {
endpointType = getAPotentialType(endpoint) and
not exists(getAnExcludingCharacteristic(endpoint, endpointType))
}
/**
@@ -139,27 +166,16 @@ module SharedCharacteristics<CandidateSig Candidate> {
}
/**
* Gets the list of characteristics that cause `candidateSink` to be excluded as an effective sink for a given sink
* type.
* Gets a characteristics that disbar `endpoint` from being a candidate for `endpointType`
* with at least medium confidence.
*/
EndpointCharacteristic getAReasonSinkExcluded(
Candidate::Endpoint candidateSink, Candidate::EndpointType sinkType
EndpointCharacteristic getAnExcludingCharacteristic(
Candidate::Endpoint endpoint, Candidate::EndpointType endpointType
) {
// An endpoint is a sink candidate if none of its characteristics give much indication whether or not it is a sink.
not sinkType instanceof Candidate::NegativeEndpointType and
result.appliesToEndpoint(candidateSink) and
(
// Exclude endpoints that have a characteristic that implies they're not sinks for _any_ sink type.
exists(float confidence |
confidence >= mediumConfidence() and
result.hasImplications(any(Candidate::NegativeEndpointType t), true, confidence)
)
or
// Exclude endpoints that have a characteristic that implies they're not sinks for _this particular_ sink type.
exists(float confidence |
confidence >= mediumConfidence() and
result.hasImplications(sinkType, false, confidence)
)
result.appliesToEndpoint(endpoint) and
exists(float confidence |
confidence >= mediumConfidence() and
result.hasImplications(endpointType, false, confidence)
)
}
@@ -250,12 +266,46 @@ module SharedCharacteristics<CandidateSig Candidate> {
override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
endpointType instanceof Candidate::NegativeEndpointType and
isPositiveIndicator = true and
endpointType instanceof Candidate::SinkType and
isPositiveIndicator = false and
confidence = highConfidence()
}
}
/**
* A high-confidence characteristic that indicates that an endpoint is not a source of any type. These endpoints can be
* used as negative samples for training or for a few-shot prompt.
*/
abstract class NotASourceCharacteristic extends EndpointCharacteristic {
bindingset[this]
NotASourceCharacteristic() { any() }
override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
endpointType instanceof Candidate::SourceType and
isPositiveIndicator = false and
confidence = highConfidence()
}
}
/**
* A high-confidence characteristic that indicates that an endpoint is neither a source nor a sink of any type.
*/
abstract class NeitherSourceNorSinkCharacteristic extends NotASinkCharacteristic,
NotASourceCharacteristic
{
bindingset[this]
NeitherSourceNorSinkCharacteristic() { any() }
final override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
NotASinkCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence) or
NotASourceCharacteristic.super.hasImplications(endpointType, isPositiveIndicator, confidence)
}
}
/**
* A medium-confidence characteristic that indicates that an endpoint is unlikely to be a sink of any type. These
* endpoints can be excluded from scoring at inference time, both to save time and to avoid false positives. They should
@@ -269,8 +319,8 @@ module SharedCharacteristics<CandidateSig Candidate> {
override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
endpointType instanceof Candidate::NegativeEndpointType and
isPositiveIndicator = true and
endpointType instanceof Candidate::SinkType and
isPositiveIndicator = false and
confidence = mediumConfidence()
}
}
@@ -290,8 +340,8 @@ module SharedCharacteristics<CandidateSig Candidate> {
override predicate hasImplications(
Candidate::EndpointType endpointType, boolean isPositiveIndicator, float confidence
) {
endpointType instanceof Candidate::NegativeEndpointType and
isPositiveIndicator = true and
endpointType instanceof Candidate::SinkType and
isPositiveIndicator = false and
confidence = mediumConfidence()
}
}
@@ -344,17 +394,16 @@ module SharedCharacteristics<CandidateSig Candidate> {
/**
* A negative characteristic that indicates that an endpoint was manually modeled as a neutral model.
*/
private class NeutralModelCharacteristic extends NotASinkCharacteristic {
private class NeutralModelCharacteristic extends NeitherSourceNorSinkCharacteristic {
NeutralModelCharacteristic() { this = "known non-sink" }
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isNeutral(e) }
}
/**
* A negative characteristic that indicates that an endpoint is not part of the source code for the project being
* analyzed.
* A negative characteristic that indicates that an endpoint is a sanitizer, and thus not a source.
*/
private class IsSanitizerCharacteristic extends NotASinkCharacteristic {
private class IsSanitizerCharacteristic extends NotASourceCharacteristic {
IsSanitizerCharacteristic() { this = "known sanitizer" }
override predicate appliesToEndpoint(Candidate::Endpoint e) { Candidate::isSanitizer(e, _) }

View File

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

View File

@@ -1,3 +1,7 @@
## 0.0.13
No user-facing changes.
## 0.0.12
No user-facing changes.

View File

@@ -0,0 +1,3 @@
## 0.0.13
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.0.12
lastReleaseVersion: 0.0.13

View File

@@ -1,5 +1,5 @@
name: codeql/java-automodel-queries
version: 0.0.12
version: 0.0.13
groups:
- java
- automodel

View File

@@ -1,13 +0,0 @@
| 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:19:3:19:11 | reference | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:19:3:19:24 | set(...) | CallContext | Test.java:19:3:19:11 | reference | MethodDoc | Test.java:19:3:19: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://(Object):1:1:1:1 | (Object) | 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:24:3:24:10 | supplier | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:24:3:24:16 | get(...) | CallContext | Test.java:24:3:24:10 | supplier | MethodDoc | Test.java:24:3:24: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:24:3:24:16 | get(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:24:3:24:16 | get(...) | CallContext | Test.java:24:3:24:16 | get(...) | MethodDoc | Test.java:24:3:24: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:28:3:32:3 | copy(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:28:3:32:3 | copy(...) | CallContext | Test.java:28:3:32:3 | copy(...) | MethodDoc | Test.java:28:3:32: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:36:10:38:3 | newInputStream(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:36:10:38:3 | newInputStream(...) | CallContext | Test.java:36:10:38:3 | newInputStream(...) | MethodDoc | Test.java:36:10:38: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:37:4:37:11 | openPath | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:36:10:38:3 | newInputStream(...) | CallContext | Test.java:37:4:37:11 | openPath | MethodDoc | Test.java:37:4:37: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:43:4:43:22 | get(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:43:4:43:22 | get(...) | CallContext | Test.java:43:4:43:22 | get(...) | MethodDoc | Test.java:43:4:43: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:54:3:59:3 | walk(...) | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:54:3:59:3 | walk(...) | CallContext | Test.java:54:3:59:3 | walk(...) | MethodDoc | Test.java:54:3:59: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:56:4:56:4 | o | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:54:3:59:3 | walk(...) | CallContext | Test.java:54:3:59:3 | walk(...) | MethodDoc | Test.java:54:3:59: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:63:3:63:3 | c | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:63:3:63:20 | getInputStream(...) | CallContext | Test.java:63:3:63:3 | c | MethodDoc | Test.java:63:3:63: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:68:30:68:47 | writer | Related locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:68:30:68:47 | writer | CallContext | Test.java:68:30:68:47 | writer | MethodDoc | Test.java:68:30:68: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 +0,0 @@
AutomodelApplicationModeExtractCandidates.ql

View File

@@ -1,3 +0,0 @@
| Test.java:48:10:50:3 | compareTo(...) | known sanitizer\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:48:10:50:3 | compareTo(...) | CallContext | Test.java:48:10:50:3 | compareTo(...) | MethodDoc | Test.java:48:10:50: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:49:4:49:5 | f2 | known non-sink\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:48:10:50:3 | compareTo(...) | CallContext | Test.java:49:4:49:5 | f2 | MethodDoc | Test.java:49:4:49: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:55:4:55:4 | p | taint step\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:54:3:59:3 | walk(...) | CallContext | Test.java:55:4:55:4 | p | MethodDoc | Test.java:55:4:55: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 |

View File

@@ -1 +0,0 @@
AutomodelApplicationModeExtractNegativeExamples.ql

View File

@@ -1,4 +0,0 @@
| Test.java:29:4:29:9 | source | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:28:3:32:3 | copy(...) | CallContext | Test.java:29:4:29:9 | source | MethodDoc | Test.java:29:4:29: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:30:4:30:9 | target | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:28:3:32:3 | copy(...) | CallContext | Test.java:30:4:30:9 | target | MethodDoc | Test.java:30:4:30: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:37:4:37:11 | openPath | path-injection\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:36:10:38:3 | newInputStream(...) | CallContext | Test.java:37:4:37:11 | openPath | MethodDoc | Test.java:37:4:37: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:63:3:63:20 | getInputStream(...) | remote\nrelated locations: $@, $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@. | Test.java:63:3:63:20 | getInputStream(...) | CallContext | Test.java:63:3:63:20 | getInputStream(...) | MethodDoc | Test.java:63:3:63: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

@@ -1 +0,0 @@
AutomodelApplicationModeExtractPositiveExamples.ql

View File

@@ -0,0 +1,35 @@
import java
import AutomodelApplicationModeCharacteristics as Characteristics
import AutomodelExtractionTests
module TestHelper implements TestHelperSig<Characteristics::ApplicationCandidatesImpl> {
Location getEndpointLocation(Characteristics::Endpoint endpoint) {
result = endpoint.asTop().getLocation()
}
predicate isCandidate(
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType
) {
Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
extensibleType, _)
}
predicate isPositiveExample(
Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
string input, string output, string extensibleType
) {
Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
output, _, extensibleType)
}
predicate isNegativeExample(
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType
) {
Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
extensibleType)
}
}
import MakeTest<Extraction<Characteristics::ApplicationCandidatesImpl, TestHelper>>

View File

@@ -2,7 +2,7 @@ import hudson.Plugin;
public class PluginImpl extends Plugin {
@Override
public void configure(String name, String value) {
public void configure(String name, String value) { // $ sourceModelCandidate=configure(String,String):Parameter[0] sourceModelCandidate=configure(String,String):Parameter[1]
// ...
}
}

View File

@@ -16,56 +16,59 @@ import java.util.concurrent.FutureTask;
class Test {
public static void main(String[] args) throws Exception {
AtomicReference<String> reference = new AtomicReference<>(); // uninteresting (parameterless constructor)
reference.set(args[0]); // arg[0] is not a candidate (modeled as value flow step)
// ^^^^^^ Argument[this] is a candidate
reference.set( // $ sinkModelCandidate=set(Object):Argument[this]
args[0] // $ negativeSinkExample=set(Object):Argument[0] // modeled as a flow step
); // $ negativeSourceExample=set(Object):ReturnValue // return type is void
}
public static void callSupplier(Supplier<String> supplier) {
supplier.get(); // Argument[this] is a sink candidate; the call is a source candidate
supplier.get(); // $ sourceModelCandidate=get():ReturnValue sinkModelCandidate=get():Argument[this]
}
public static void copyFiles(Path source, Path target, CopyOption option) throws Exception {
Files.copy( // the call is a source candidate
source, // positive example (known sink)
target, // positive example (known sink)
Files.copy(
source, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[0](path-injection)
target, // $ positiveSinkExample=copy(Path,Path,CopyOption[]):Argument[1](path-injection)
option // no candidate (not modeled, but source and target are modeled)
);
); // $ sourceModelCandidate=copy(Path,Path,CopyOption[]):ReturnValue
}
public static InputStream getInputStream(Path openPath) throws Exception {
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)
);
return Files.newInputStream(
openPath // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) // sink candidate because "only" ai-modeled, and useful as a candidate in regression testing
); // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
}
public static InputStream getInputStream(String openPath) throws Exception {
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
Paths.get(
openPath // $ negativeSinkExample=get(String,String[]):Argument[0] // modeled as a flow step
) // $ sourceModelCandidate=get(String,String[]):ReturnValue
);
}
public static int compareFiles(File f1, File f2) {
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)
return f1.compareTo( // $ negativeSinkExample=compareTo(File):Argument[this]
f2 // $ negativeSinkExample=compareTo(File):Argument[0] // modeled as not a sink
); // $ negativeSourceExample=compareTo(File):ReturnValue // return type is int
}
public static void FilesWalkExample(Path p, FileVisitOption o) throws Exception {
Files.walk( // the call is a source candidate
p, // negative example (modeled as a taint step)
o, // the implicit varargs array is a candidate
Files.walk(
p, // $ negativeSinkExample=walk(Path,FileVisitOption[]):Argument[0] // modeled as a flow step
o, // the implicit varargs array is a candidate, annotated on the last line of the call
o // not a candidate (only the first arg corresponding to a varargs array
// is extracted)
);
); // $ sourceModelCandidate=walk(Path,FileVisitOption[]):ReturnValue sinkModelCandidate=walk(Path,FileVisitOption[]):Argument[1]
}
public static void WebSocketExample(URLConnection c) throws Exception {
c.getInputStream(); // the call is a source example, c is a sink candidate
c.getInputStream(); // $ sinkModelCandidate=getInputStream():Argument[this] positiveSourceExample=getInputStream():ReturnValue(remote) // not a source candidate (manual modeling)
}
}
class OverrideTest extends Exception {
public void printStackTrace(PrintWriter writer) { // writer is a source candidate because it overrides an existing method
public void printStackTrace(PrintWriter writer) { // $ sourceModelCandidate=printStackTrace(PrintWriter):Parameter[0]
return;
}
@@ -80,3 +83,21 @@ class TaskUtils {
return ft;
}
}
class MoreTests {
public static void FilesListExample(Path p) throws Exception {
Files.list(
Files.createDirectories(
p // $ positiveSinkExample=createDirectories(Path,FileAttribute[]):Argument[0](path-injection)
) // $ sourceModelCandidate=createDirectories(Path,FileAttribute[]):ReturnValue negativeSinkExample=list(Path):Argument[0] // modeled as a flow step
); // $ sourceModelCandidate=list(Path):ReturnValue
Files.delete(
p // $ sinkModelCandidate=delete(Path):Argument[0] positiveSinkExample=delete(Path):Argument[0](path-injection)
); // $ negativeSourceExample=delete(Path):ReturnValue // return type is void
Files.deleteIfExists(
p // $ sinkModelCandidate=deleteIfExists(Path):Argument[0] positiveSinkExample=deleteIfExists(Path):Argument[0](path-injection)
); // $ negativeSourceExample=deleteIfExists(Path):ReturnValue // return type is boolean
}
}

View File

@@ -0,0 +1,77 @@
import java
import TestUtilities.InlineExpectationsTest
import AutomodelSharedCharacteristics
signature module TestHelperSig<CandidateSig Candidate> {
Location getEndpointLocation(Candidate::Endpoint e);
predicate isCandidate(
Candidate::Endpoint e, string name, string signature, string input, string output,
string extensibleType
);
predicate isPositiveExample(
Candidate::Endpoint e, string endpointType, string name, string signature, string input,
string output, string extensibleType
);
predicate isNegativeExample(
Candidate::Endpoint e, string name, string signature, string input, string output,
string extensibleType
);
}
module Extraction<CandidateSig Candidate, TestHelperSig<Candidate> TestHelper> implements TestSig {
string getARelevantTag() {
result in [
"sourceModelCandidate", "sinkModelCandidate", // a candidate source/sink
"positiveSourceExample", "positiveSinkExample", // a known source/sink
"negativeSourceExample", "negativeSinkExample" // a known non-source/non-sink
]
}
/**
* If `extensibleType` is `sourceModel` then the result is `ifSource`, if it
* is `sinkModel` then the result is `ifSink`.
*/
bindingset[extensibleType, ifSource, ifSink]
private string ifSource(string extensibleType, string ifSource, string ifSink) {
extensibleType = "sourceModel" and result = ifSource
or
extensibleType = "sinkModel" and result = ifSink
}
additional predicate selectEndpoint(
Candidate::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType, string tag, string suffix
) {
TestHelper::isCandidate(endpoint, name, signature, input, output, extensibleType) and
tag = ifSource(extensibleType, "sourceModelCandidate", "sinkModelCandidate") and
suffix = ""
or
TestHelper::isNegativeExample(endpoint, name, signature, input, output, extensibleType) and
tag = "negative" + ifSource(extensibleType, "Source", "Sink") + "Example" and
suffix = ""
or
exists(string endpointType |
TestHelper::isPositiveExample(endpoint, endpointType, name, signature, input, output,
extensibleType) and
tag = "positive" + ifSource(extensibleType, "Source", "Sink") + "Example" and
suffix = "(" + endpointType + ")"
)
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(
Candidate::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType, string suffix
|
selectEndpoint(endpoint, name, signature, input, output, extensibleType, tag, suffix)
|
TestHelper::getEndpointLocation(endpoint) = location and
endpoint.toString() = element and
// for source models only the output is relevant, and vice versa for sink models
value = name + signature + ":" + ifSource(extensibleType, output, input) + suffix
)
}
}

View File

@@ -1,23 +0,0 @@
| 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://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: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://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/PublicClass.java:22:10:22:20 | PublicClass | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:22:10:22:20 | PublicClass | MethodDoc | com/github/codeql/test/PublicClass.java:22:10:22:20 | PublicClass | 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://PublicClass:1:1:1:1 | PublicClass | name | file://(Object):1:1:1:1 | (Object) | 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:22:22:22:33 | input | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicClass.java:22:22:22:33 | input | MethodDoc | com/github/codeql/test/PublicClass.java:22:22:22:33 | input | 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://PublicClass:1:1:1:1 | PublicClass | name | file://(Object):1:1:1:1 | (Object) | signature | file://Argument[0]:1:1:1:1 | Argument[0] | input | file://:1:1:1:1 | | output | file://input:1:1:1:1 | input | parameterName | file://:1:1:1:1 | | alreadyAiModeled | file://sinkModel:1:1:1:1 | sinkModel | extensibleType |
| com/github/codeql/test/PublicInterface.java:4:16:4:20 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:16:4:20 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:16:4:20 | 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:16:4:20 | stuff | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:16:4:20 | stuff | MethodDoc | com/github/codeql/test/PublicInterface.java:4:16:4:20 | 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:22:4:31 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:22:4:31 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:22:4:31 | 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:22:4:31 | arg | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | com/github/codeql/test/PublicInterface.java:4:22:4:31 | arg | MethodDoc | com/github/codeql/test/PublicInterface.java:4:22:4:31 | 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: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/io/File.java:10:20:10:34 | setLastModified | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:10:20:10:34 | setLastModified | MethodDoc | java/io/File.java:10:20:10:34 | setLastModified | 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://setLastModified:1:1:1:1 | setLastModified | name | file://(long):1:1:1:1 | (long) | 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 |
| java/io/File.java:10:20:10:34 | setLastModified | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:10:20:10:34 | setLastModified | MethodDoc | java/io/File.java:10:20:10:34 | setLastModified | 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://setLastModified:1:1:1:1 | setLastModified | name | file://(long):1:1:1:1 | (long) | 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 |
| java/io/File.java:10:36:10:44 | time | Related locations: $@, $@.\nmetadata: $@, $@, $@, $@, $@, $@, $@, $@, $@, $@. | java/io/File.java:10:36:10:44 | time | MethodDoc | java/io/File.java:10:36:10:44 | time | 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://setLastModified:1:1:1:1 | setLastModified | name | file://(long):1:1:1:1 | (long) | signature | file://:1:1:1:1 | | input | file://Parameter[0]:1:1:1:1 | Parameter[0] | output | file://time:1:1:1:1 | time | 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 +0,0 @@
AutomodelFrameworkModeExtractCandidates.ql

View File

@@ -1,4 +0,0 @@
| 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://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 +0,0 @@
AutomodelFrameworkModeExtractNegativeExamples.ql

View File

@@ -1,2 +0,0 @@
| 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 +0,0 @@
AutomodelFrameworkModeExtractPositiveExamples.ql

View File

@@ -0,0 +1,35 @@
import java
import AutomodelFrameworkModeCharacteristics as Characteristics
import AutomodelExtractionTests
module TestHelper implements TestHelperSig<Characteristics::FrameworkCandidatesImpl> {
Location getEndpointLocation(Characteristics::Endpoint endpoint) {
result = endpoint.asTop().getLocation()
}
predicate isCandidate(
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType
) {
Characteristics::isCandidate(endpoint, _, _, _, name, signature, input, output, _,
extensibleType, _)
}
predicate isPositiveExample(
Characteristics::Endpoint endpoint, string endpointType, string name, string signature,
string input, string output, string extensibleType
) {
Characteristics::isPositiveExample(endpoint, endpointType, _, _, _, name, signature, input,
output, _, extensibleType)
}
predicate isNegativeExample(
Characteristics::Endpoint endpoint, string name, string signature, string input, string output,
string extensibleType
) {
Characteristics::isNegativeExample(endpoint, _, _, _, _, _, name, signature, input, output, _,
extensibleType)
}
}
import MakeTest<Extraction<Characteristics::FrameworkCandidatesImpl, TestHelper>>

View File

@@ -1,25 +1,27 @@
package com.github.codeql.test;
public class PublicClass {
public void stuff(String arg) { // `arg` is a sink candidate, `this` is a candidate, `arg` is a source candidate (overrideable method)
public void stuff(String arg) { // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // source candidates because it is an overrideable method
System.out.println(arg);
}
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)
public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // `arg` is not a source candidate (not overrideabe); `this` is not a candidate (static method)
System.out.println(arg);
}
// `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) {
protected void nonPublicStuff(String arg) { // $ sinkModelCandidate=nonPublicStuff(String):Argument[this] sourceModelCandidate=nonPublicStuff(String):Parameter[this] sinkModelCandidate=nonPublicStuff(String):Argument[0] sourceModelCandidate=nonPublicStuff(String):Parameter[0]
System.out.println(arg);
}
// `arg` and `this are not candidates because the method is not public:
void packagePrivateStuff(String arg) {
void packagePrivateStuff(String arg) { // no candidates because the method is not public
System.out.println(arg);
}
public PublicClass(Object input) {
// the `this` qualifier is not a candidate
public PublicClass(Object input) { // $ sourceModelCandidate=PublicClass(Object):ReturnValue sinkModelCandidate=PublicClass(Object):Argument[0] // `this` is not a candidate because it is a constructor
}
// `input` and `input` are source candidates, but not sink candidates (is-style method)
public Boolean isIgnored(Object input) { // $ negativeSinkExample=isIgnored(Object):Argument[this] sourceModelCandidate=isIgnored(Object):Parameter[this] negativeSinkExample=isIgnored(Object):Argument[0] sourceModelCandidate=isIgnored(Object):Parameter[0]
return false;
}
}

View File

@@ -1,9 +1,9 @@
package com.github.codeql.test;
public interface PublicInterface {
public int stuff(String arg); // `arg` is a candidate, `this` is a candidate, method stuff is _not_ a candidate source (primitive return type), `arg` is a source candidate (overridable method)
public int stuff(String arg); // $ sinkModelCandidate=stuff(String):Argument[this] sourceModelCandidate=stuff(String):Parameter[this] sinkModelCandidate=stuff(String):Argument[0] sourceModelCandidate=stuff(String):Parameter[0] // result is _not_ a source candidate source (primitive return type)
public static void staticStuff(String arg) { // `arg` is a candidate, `this` is not a candidate (static method)
public static void staticStuff(String arg) { // $ sinkModelCandidate=staticStuff(String):Argument[0] // not a source candidate (static method)
System.out.println(arg);
}
}

View File

@@ -1,13 +1,13 @@
package java.io;
public class File {
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
public int compareTo( // $ negativeSinkExample=compareTo(File):Argument[this] negativeSourceExample=compareTo(File):Parameter[this] // modeled as neutral
File pathname // $ negativeSinkExample=compareTo(File):Argument[0] negativeSourceExample=compareTo(File):Parameter[0] // modeled as neutral
) {
return 0;
}
public boolean setLastModified(long time) {
public boolean setLastModified(long time) { // $ sinkModelCandidate=setLastModified(long):Argument[this] sourceModelCandidate=setLastModified(long):Parameter[this] // time is not a candidate (primitive type)
return false;
} // return value is not a source candidate because it's a primitive
}

View File

@@ -9,9 +9,10 @@ import java.io.OutputStream;
import java.nio.file.OpenOption;
public class Files {
public static void copy(
Path source, // a positive example because a manual model exists
OutputStream out /* a candidate. NB: may be worthwhile to implement the
public static void copy( // method result is not a candidate source (void)
Path source, // $ positiveSinkExample=copy(Path,OutputStream):Argument[0](path-injection) // manual model exists
OutputStream out // $ sinkModelCandidate=copy(Path,OutputStream):Argument[1]
/* NB: may be worthwhile to implement the
same behavior as in application mode where out would not be a
candidate because there already is a model for another parameter of
the same method and we assume that methods are always modeled
@@ -19,12 +20,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
public static InputStream newInputStream( // $ sourceModelCandidate=newInputStream(Path,OpenOption[]):ReturnValue
Path openPath, // $ positiveSinkExample=newInputStream(Path,OpenOption[]):Argument[0](path-injection) sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[0] // known sink, but still a candidate (ai-modeled, and useful as a candidate in regression testing)
OpenOption... options // $ sinkModelCandidate=newInputStream(Path,OpenOption[]):Argument[1]
) throws IOException {
return new FileInputStream(openPath.toFile());
} // method newInputStream is a candidate source
}
}

View File

@@ -7,6 +7,7 @@ groups:
dependencies:
codeql/java-all: ${workspace}
codeql/java-automodel-queries: ${workspace}
codeql/java-tests: ${workspace}
extractor: java
tests: .
warnOnImplicitThis: true

View File

@@ -1,3 +1,29 @@
## 0.8.7
### New Features
* Added a new library `semmle.code.java.security.Sanitizers` which contains a new sanitizer class `SimpleTypeSanitizer`, which represents nodes which cannot realistically carry taint for most queries (e.g. primitives, their boxed equivalents, and numeric types).
* Converted definitions of `isBarrier` and sanitizer classes to use `SimpleTypeSanitizer` instead of checking if `node.getType()` is `PrimitiveType` or `BoxedType`.
### Minor Analysis Improvements
* Deleted many deprecated predicates and classes with uppercase `EJB`, `JMX`, `NFE`, `DNS` etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `semmle/code/java/security/OverlyLargeRangeQuery.qll`, `semmle/code/java/security/regexp/ExponentialBackTracking.qll`, `semmle/code/java/security/regexp/NfaUtils.qll`, and `semmle/code/java/security/regexp/NfaUtils.qll` files.
* Improved models for `java.lang.Throwable` and `java.lang.Exception`, and the `valueOf` method of `java.lang.String`.
* Added taint tracking for the following GSON methods:
* `com.google.gson.stream.JsonReader` constructor
* `com.google.gson.stream.JsonWriter` constructor
* `com.google.gson.JsonObject.getAsJsonArray`
* `com.google.gson.JsonObject.getAsJsonObject`
* `com.google.gson.JsonObject.getAsJsonPrimitive`
* `com.google.gson.JsonParser.parseReader`
* `com.google.gson.JsonParser.parseString`
* Added a dataflow model for `java.awt.Desktop.browse(URI)`.
### Bug Fixes
* Fixed regular expressions containing flags not being parsed correctly in some cases.
## 0.8.6
### Deprecated APIs

View File

@@ -0,0 +1,25 @@
## 0.8.7
### New Features
* Added a new library `semmle.code.java.security.Sanitizers` which contains a new sanitizer class `SimpleTypeSanitizer`, which represents nodes which cannot realistically carry taint for most queries (e.g. primitives, their boxed equivalents, and numeric types).
* Converted definitions of `isBarrier` and sanitizer classes to use `SimpleTypeSanitizer` instead of checking if `node.getType()` is `PrimitiveType` or `BoxedType`.
### Minor Analysis Improvements
* Deleted many deprecated predicates and classes with uppercase `EJB`, `JMX`, `NFE`, `DNS` etc. in their names. Use the PascalCased versions instead.
* Deleted the deprecated `semmle/code/java/security/OverlyLargeRangeQuery.qll`, `semmle/code/java/security/regexp/ExponentialBackTracking.qll`, `semmle/code/java/security/regexp/NfaUtils.qll`, and `semmle/code/java/security/regexp/NfaUtils.qll` files.
* Improved models for `java.lang.Throwable` and `java.lang.Exception`, and the `valueOf` method of `java.lang.String`.
* Added taint tracking for the following GSON methods:
* `com.google.gson.stream.JsonReader` constructor
* `com.google.gson.stream.JsonWriter` constructor
* `com.google.gson.JsonObject.getAsJsonArray`
* `com.google.gson.JsonObject.getAsJsonObject`
* `com.google.gson.JsonObject.getAsJsonPrimitive`
* `com.google.gson.JsonParser.parseReader`
* `com.google.gson.JsonParser.parseString`
* Added a dataflow model for `java.awt.Desktop.browse(URI)`.
### Bug Fixes
* Fixed regular expressions containing flags not being parsed correctly in some cases.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.6
lastReleaseVersion: 0.8.7

View File

@@ -19,6 +19,8 @@ extensions:
- ["com.google.gson", "Gson", False, "newJsonWriter", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.google.gson.stream", "JsonReader", False, "nextName", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson.stream", "JsonReader", False, "nextString", "", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson.stream", "JsonReader", False, "JsonReader", "(Reader)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["com.google.gson.stream", "JsonWriter", False, "JsonWriter", "(Writer)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["com.google.gson", "JsonElement", True, "getAsByte", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonElement", True, "getAsCharacter", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonElement", True, "getAsJsonArray", "()", "", "Argument[this]", "ReturnValue", "taint", "manual"]
@@ -44,6 +46,12 @@ extensions:
- ["com.google.gson", "JsonObject", True, "entrySet", "", "", "Argument[this].MapKey", "ReturnValue.Element.MapKey", "value", "manual"]
- ["com.google.gson", "JsonObject", True, "entrySet", "", "", "Argument[this].MapValue", "ReturnValue.Element.MapValue", "value", "manual"]
- ["com.google.gson", "JsonObject", True, "get", "", "", "Argument[this].MapValue", "ReturnValue", "value", "manual"]
- ["com.google.gson", "JsonObject", True, "getAsJsonArray", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonObject", True, "getAsJsonObject", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonObject", True, "getAsJsonPrimitive", "(String)", "", "Argument[this]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonObject", True, "keySet", "", "", "Argument[this].MapKey", "ReturnValue.Element", "value", "manual"]
- ["com.google.gson", "JsonParser", True, "parseReader", "(JsonReader)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonParser", True, "parseReader", "(Reader)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonParser", True, "parseString", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["com.google.gson", "JsonPrimitive", True, "JsonPrimitive", "(Character)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["com.google.gson", "JsonPrimitive", True, "JsonPrimitive", "(String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]

View File

@@ -32,8 +32,11 @@ extensions:
- ["hudson", "FilePath", True, "write", "(String,String)", "", "Argument[0]", "file-content-store", "manual"]
- ["hudson", "Launcher$ProcStarter", False, "cmds", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher$ProcStarter", False, "cmdAsSingleString", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher$ProcStarter", False, "envs", "(String[])", "", "Argument[0]", "environment-injection", "manual"]
- ["hudson", "Launcher", True, "launch", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher", True, "decorateByEnv", "(String[])", "", "Argument[0]", "environment-injection", "manual"]
- ["hudson", "Launcher", True, "launchChannel", "", "", "Argument[0]", "command-injection", "manual"]
- ["hudson", "Launcher", True, "launchChannel", "", "", "Argument[3]", "environment-injection", "manual"]
- ["hudson", "XmlFile", False, "XmlFile", "(XStream,File)", "", "Argument[1]", "path-injection", "ai-manual"]
- addsTo:
pack: codeql/java-all

View File

@@ -6,7 +6,6 @@ extensions:
- ["java.awt", "Container", True, "add", "(Component)", "", "Argument[0]", "Argument[this].Element", "value", "manual"]
- ["java.awt", "Container", True, "add", "(Component)", "", "Argument[0]", "ReturnValue", "value", "manual"]
- ["java.awt", "Container", True, "add", "(Component,Object)", "", "Argument[0]", "Argument[this].Element", "value", "manual"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
@@ -14,3 +13,8 @@ extensions:
# The below APIs have numeric flow and are currently being stored as neutral models.
# These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
- ["java.awt", "Insets", "Insets", "(int,int,int,int)", "summary", "manual"] # value-numeric
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["java.awt", "Desktop", True, "browse", "(URI)", "", "Argument[0]", "url-redirection", "ai-manual"]

View File

@@ -22,6 +22,8 @@ extensions:
- ["java.lang", "Runtime", True, "exec", "(String,String[])", "", "Argument[0]", "command-injection", "ai-manual"]
- ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[0]", "command-injection", "ai-manual"]
- ["java.lang", "Runtime", True, "exec", "(String,String[],File)", "", "Argument[2]", "command-injection", "ai-manual"]
# All implementations of `java.lang.Runtime::exec` take the environment variables as their second argument.
- ["java.lang", "Runtime", True, "exec", "", "", "Argument[1]", "environment-injection", "manual"]
# These are potential vulnerabilities, but not for command-injection. No query for this kind of vulnerability currently exists.
# - ["java.lang", "Runtime", False, "load", "(String)", "", "Argument[0]", "command-injection", "ai-manual"]
# - ["java.lang", "Runtime", False, "loadLibrary", "(String)", "", "Argument[0]", "command-injection", "ai-manual"]
@@ -77,6 +79,8 @@ extensions:
- ["java.lang", "Exception", False, "Exception", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "Exception", False, "Exception", "(String,Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "Exception", False, "Exception", "(String,Throwable)", "", "Argument[1]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Exception", False, "Exception", "(Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Exception", False, "Exception", "(Throwable)", "", "Argument[0].SyntheticField[java.lang.Throwable.message]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "taint", "manual"]
- ["java.lang", "IllegalArgumentException", False, "IllegalArgumentException", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "IllegalStateException", False, "IllegalStateException", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "IndexOutOfBoundsException", False, "IndexOutOfBoundsException", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
@@ -129,6 +133,7 @@ extensions:
- ["java.lang", "String", False, "valueOf", "(char)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "valueOf", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "valueOf", "(char[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "valueOf", "(CharSequence)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "StringBuffer", True, "StringBuffer", "(CharSequence)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["java.lang", "StringBuffer", True, "StringBuffer", "(String)", "", "Argument[0]", "Argument[this]", "taint", "manual"]
- ["java.lang", "StringBuilder", True, "StringBuilder", "", "", "Argument[0]", "Argument[this]", "taint", "manual"]
@@ -139,11 +144,17 @@ extensions:
- ["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", False, "Throwable", "(String,Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(String,Throwable)", "", "Argument[1]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(Throwable)", "", "Argument[0].SyntheticField[java.lang.Throwable.message]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "taint", "manual"]
- ["java.lang", "Throwable", True, "getCause", "()", "", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "getMessage", "()", "", "Argument[this].SyntheticField[java.lang.Throwable.message]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "getLocalizedMessage", "()", "", "Argument[this].SyntheticField[java.lang.Throwable.message]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "initCause", "(Throwable)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", True, "initCause", "(Throwable)", "", "Argument[0]", "ReturnValue.SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", True, "initCause", "(Throwable)", "", "Argument[this]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "toString", "()", "", "Argument[this].SyntheticField[java.lang.Throwable.message]", "ReturnValue", "taint", "manual"]
- ["java.lang", "UnsupportedOperationException", False, "UnsupportedOperationException", "(String)", "", "Argument[0]", "Argument[this].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- addsTo:
@@ -200,6 +211,7 @@ extensions:
- ["java.lang", "String", "length", "()", "summary", "manual"]
- ["java.lang", "String", "startsWith", "(String)", "summary", "manual"]
- ["java.lang", "String", "valueOf", "(boolean)", "summary", "manual"]
- ["java.lang", "String", "valueOf", "(Object)", "summary", "manual"]
- ["java.lang", "System", "currentTimeMillis", "()", "summary", "manual"]
- ["java.lang", "System", "exit", "(int)", "summary", "manual"]
- ["java.lang", "System", "getenv", "(String)", "summary", "manual"]
@@ -211,6 +223,14 @@ extensions:
- ["java.lang", "Thread", "interrupt", "()", "summary", "manual"]
- ["java.lang", "Thread", "sleep", "(long)", "summary", "manual"]
- ["java.lang", "Thread", "start", "()", "summary", "manual"]
- ["java.lang", "Throwable", "addSuppressed", "(Throwable)", "summary", "manual"]
- ["java.lang", "Throwable", "fillInStackTrace", "()", "summary", "manual"]
- ["java.lang", "Throwable", "getStackTrace", "()", "summary", "manual"]
- ["java.lang", "Throwable", "getSuppressed", "()", "summary", "manual"]
- ["java.lang", "Throwable", "printStackTrace", "()", "summary", "manual"]
- ["java.lang", "Throwable", "printStackTrace", "(PrintStream)", "summary", "manual"]
- ["java.lang", "Throwable", "printStackTrace", "(PrintWriter)", "summary", "manual"]
- ["java.lang", "Throwable", "setStackTrace", "(StackTraceElement[])", "summary", "manual"]
# The below APIs have numeric flow and are currently being stored as neutral models.
# These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
- ["java.lang", "Double", "doubleToLongBits", "(double)", "summary", "manual"] # taint-numeric

View File

@@ -26,6 +26,7 @@ extensions:
- ["javax.servlet.http", "HttpServletResponse", False, "addHeader", "", "", "Argument[0..1]", "response-splitting", "manual"]
- ["javax.servlet.http", "HttpServletResponse", False, "sendError", "(int,String)", "", "Argument[1]", "information-leak", "manual"]
- ["javax.servlet.http", "HttpServletResponse", False, "setHeader", "", "", "Argument[0..1]", "response-splitting", "manual"]
# - ["javax.servlet.http", "HttpServletResponse", True, "sendRedirect", "(String)", "", "Argument[0]", "url-redirection", "ai-manual"] # QL model exists in java/ql/lib/semmle/code/java/security/UrlRedirect.qll
- ["javax.servlet.http", "HttpSession", True, "putValue", "", "", "Argument[0..1]", "trust-boundary-violation", "manual"]
- ["javax.servlet.http", "HttpSession", True, "setAttribute", "", "", "Argument[0..1]", "trust-boundary-violation", "manual"]
- addsTo:

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.commons.exec.environment", "EnvironmentUtils", True, "addVariableToEnvironment", "(Map,String)", "", "Argument[0]", "environment-injection", "manual"]

View File

@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.apache.commons.exec.launcher", "CommandLauncher", True, "exec", "", "", "Argument[1]", "environment-injection", "manual"]

View File

@@ -9,3 +9,5 @@ extensions:
- ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String,boolean)", "", "Argument[0]", "command-injection", "manual"]
- ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String[])", "", "Argument[0]", "command-injection", "manual"]
- ["org.apache.commons.exec", "CommandLine", True, "addArguments", "(String[],boolean)", "", "Argument[0]", "command-injection", "manual"]
- ["org.apache.commons.exec", "Executor", True, "execute", "(CommandLine,Map)", "", "Argument[1]", "environment-injection", "manual"]
- ["org.apache.commons.exec", "Executor", True, "execute", "(CommandLine,Map,ExecuteResultHandler)", "", "Argument[1]", "environment-injection", "manual"]

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "SecretEncryptionConfiguration", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecret", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecretBase64", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.encryption", "SecretEncryptionConfiguration", True, "setSecretBytes", "", "", "Argument[0]", "credentials-key", "manual"]

View File

@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: sinkModel
data:
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "SecretEncryptionConfiguration", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecret", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecretBase64", "", "", "Argument[0]", "credentials-key", "manual"]
- ["org.pac4j.jwt.config.signature", "SecretSignatureConfiguration", True, "setSecretBytes", "", "", "Argument[0]", "credentials-key", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/java-all
version: 0.8.6
version: 0.8.7
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java

View File

@@ -25,9 +25,6 @@ class LocalEjbHomeInterface extends Interface {
}
}
/** DEPRECATED: Alias for LocalEjbHomeInterface */
deprecated class LocalEJBHomeInterface = LocalEjbHomeInterface;
/** A remote EJB home interface. */
class RemoteEjbHomeInterface extends Interface {
RemoteEjbHomeInterface() {
@@ -35,9 +32,6 @@ class RemoteEjbHomeInterface extends Interface {
}
}
/** DEPRECATED: Alias for RemoteEjbHomeInterface */
deprecated class RemoteEJBHomeInterface = RemoteEjbHomeInterface;
/** A local EJB interface. */
class LocalEjbInterface extends Interface {
LocalEjbInterface() {
@@ -45,9 +39,6 @@ class LocalEjbInterface extends Interface {
}
}
/** DEPRECATED: Alias for LocalEjbInterface */
deprecated class LocalEJBInterface = LocalEjbInterface;
/** A remote EJB interface. */
class RemoteEjbInterface extends Interface {
RemoteEjbInterface() {
@@ -55,9 +46,6 @@ class RemoteEjbInterface extends Interface {
}
}
/** DEPRECATED: Alias for RemoteEjbInterface */
deprecated class RemoteEJBInterface = RemoteEjbInterface;
/** A message bean. */
class MessageBean extends Class {
MessageBean() {

View File

@@ -50,9 +50,6 @@ class JmxRegistrationCall extends MethodCall {
}
}
/** DEPRECATED: Alias for JmxRegistrationCall */
deprecated class JMXRegistrationCall = JmxRegistrationCall;
/**
* A method used to register `MBean` and `MXBean` instances with the `MBeanServer`.
*
@@ -90,9 +87,6 @@ class JmxRegistrationMethod extends Method {
}
}
/** DEPRECATED: Alias for JmxRegistrationMethod */
deprecated class JMXRegistrationMethod = JmxRegistrationMethod;
/** The class `javax.management.remote.JMXConnectorFactory`. */
class TypeJmxConnectorFactory extends Class {
TypeJmxConnectorFactory() {
@@ -100,21 +94,12 @@ class TypeJmxConnectorFactory extends Class {
}
}
/** DEPRECATED: Alias for TypeJmxConnectorFactory */
deprecated class TypeJMXConnectorFactory = TypeJmxConnectorFactory;
/** The class `javax.management.remote.JMXServiceURL`. */
class TypeJmxServiceUrl extends Class {
TypeJmxServiceUrl() { this.hasQualifiedName("javax.management.remote", "JMXServiceURL") }
}
/** DEPRECATED: Alias for TypeJmxServiceUrl */
deprecated class TypeJMXServiceURL = TypeJmxServiceUrl;
/** The class `javax.management.remote.rmi.RMIConnector`. */
class TypeRmiConnector extends Class {
TypeRmiConnector() { this.hasQualifiedName("javax.management.remote.rmi", "RMIConnector") }
}
/** DEPRECATED: Alias for TypeRmiConnector */
deprecated class TypeRMIConnector = TypeRmiConnector;

View File

@@ -33,9 +33,6 @@ private class SpecialMethodCall extends MethodCall {
this.isValueOfMethod("Float") or
this.isValueOfMethod("Double")
}
/** DEPRECATED: Alias for throwsNfe */
deprecated predicate throwsNFE() { this.throwsNfe() }
}
/** A `ClassInstanceExpr` that constructs a number from its string representation. */
@@ -54,9 +51,6 @@ private class SpecialClassInstanceExpr extends ClassInstanceExpr {
this.isStringConstructor("Float") or
this.isStringConstructor("Double")
}
/** DEPRECATED: Alias for throwsNfe */
deprecated predicate throwsNFE() { this.throwsNfe() }
}
/** The class `java.lang.NumberFormatException`. */
@@ -73,13 +67,7 @@ predicate catchesNfe(TryStmt t) {
)
}
/** DEPRECATED: Alias for catchesNfe */
deprecated predicate catchesNFE = catchesNfe/1;
/** Holds if `java.lang.NumberFormatException` can be thrown. */
predicate throwsNfe(Expr e) {
e.(SpecialClassInstanceExpr).throwsNfe() or e.(SpecialMethodCall).throwsNfe()
}
/** DEPRECATED: Alias for throwsNfe */
deprecated predicate throwsNFE = throwsNfe/1;

View File

@@ -528,6 +528,10 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
exists(Provenance provenance |
summaryElement(this, input, output, kind, provenance) and
provenance.isGenerated()
) and
not exists(Provenance provenance |
neutralElement(this, "summary", provenance) and
provenance.isManual()
)
}

View File

@@ -313,9 +313,6 @@ class ReverseDnsMethod extends Method {
}
}
/** DEPRECATED: Alias for ReverseDnsMethod */
deprecated class ReverseDNSMethod = ReverseDnsMethod;
/** Android `Intent` that may have come from a hostile application. */
class AndroidIntentInput extends DataFlow::Node {
Type receiverType;

View File

@@ -116,10 +116,10 @@ private module DispatchImpl {
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context. This is the case if the
* qualifier is a parameter of the enclosing callable `c`.
* qualifier is a parameter of the enclosing callable of `call`.
*/
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
mayBenefitFromCallContext(call.asCall(), c.asCallable(), _)
predicate mayBenefitFromCallContext(DataFlowCall call) {
mayBenefitFromCallContext(call.asCall(), _, _)
}
/**

View File

@@ -18,4 +18,8 @@ module JavaDataFlow implements InputSig {
import Public
Node exprNode(DataFlowExpr e) { result = Public::exprNode(e) }
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2;
}

View File

@@ -97,9 +97,6 @@ class SerialVersionUidField extends ReflectivelyReadField {
}
}
/** DEPRECATED: Alias for SerialVersionUidField */
deprecated class SerialVersionUIDField = SerialVersionUidField;
/**
* A field is read by the JAXB during serialization if it is a JAXB bound field, and if the
* containing class is considered "live".
@@ -173,6 +170,3 @@ class JpaReadField extends ReflectivelyReadField {
)
}
}
/** DEPRECATED: Alias for JpaReadField */
deprecated class JPAReadField = JpaReadField;

View File

@@ -135,10 +135,6 @@ class JaxAnnotationReflectivelyConstructedClass extends ReflectivelyConstructedC
}
}
/** DEPRECATED: Alias for JaxAnnotationReflectivelyConstructedClass */
deprecated class JAXAnnotationReflectivelyConstructedClass =
JaxAnnotationReflectivelyConstructedClass;
class DeserializedClass extends ReflectivelyConstructedClass {
DeserializedClass() {
exists(CastingExpr cast, ReadObjectMethod readObject |
@@ -324,9 +320,6 @@ class EjbHome extends Interface, EntryPoint {
override Callable getALiveCallable() { result = this.getACallable() }
}
/** DEPRECATED: Alias for EjbHome */
deprecated class EJBHome = EjbHome;
/**
* Entry point for EJB object interfaces.
*/
@@ -336,9 +329,6 @@ class EjbObject extends Interface, EntryPoint {
override Callable getALiveCallable() { result = this.getACallable() }
}
/** DEPRECATED: Alias for EjbObject */
deprecated class EJBObject = EjbObject;
class GsonDeserializationEntryPoint extends ReflectivelyConstructedClass {
GsonDeserializationEntryPoint() {
// Assume any class with a gson annotated field can be deserialized.
@@ -361,9 +351,6 @@ class JaxbDeserializationEntryPoint extends ReflectivelyConstructedClass {
}
}
/** DEPRECATED: Alias for JaxbDeserializationEntryPoint */
deprecated class JAXBDeserializationEntryPoint = JaxbDeserializationEntryPoint;
/**
* A `javax.annotation` for a method that is called after or before dependency injection on a type.
*

View File

@@ -115,9 +115,6 @@ class SpringCli extends CallableEntryPoint {
}
}
/** DEPRECATED: Alias for SpringCli */
deprecated class SpringCLI = SpringCli;
/**
* An entry point which acts as a remote API for a Flex application to access a Spring application.
*/

View File

@@ -57,9 +57,6 @@ class GwtEntryPointConstructedClass extends ReflectivelyConstructedClass {
GwtEntryPointConstructedClass() { this.(GwtEntryPointClass).isLive() }
}
/** DEPRECATED: Alias for GwtEntryPointConstructedClass */
deprecated class GWTEntryPointConstructedClass = GwtEntryPointConstructedClass;
/**
* Servlets referred to from a GWT module config file.
*/
@@ -79,9 +76,6 @@ class GwtServletClass extends ReflectivelyConstructedClass {
}
}
/** DEPRECATED: Alias for GwtServletClass */
deprecated class GWTServletClass = GwtServletClass;
/**
* Methods that may be called reflectively by the UiHandler framework.
*/

View File

@@ -302,8 +302,3 @@ private module Dispatch {
}
import Dispatch
/**
* DEPRECATED: Use `TypeFlow` instead.
*/
deprecated Expr variableTrack(Expr use) { result = use }

View File

@@ -17,9 +17,6 @@ class CamelToUri extends string {
}
}
/** DEPRECATED: Alias for CamelToUri */
deprecated class CamelToURI = CamelToUri;
/**
* A string describing a URI specified in an Apache Camel "to" declaration that maps to a
* SpringBean.
@@ -54,9 +51,6 @@ class CamelToBeanUri extends CamelToUri {
SpringBean getRefBean() { result.getBeanIdentifier() = this.getBeanIdentifier() }
}
/** DEPRECATED: Alias for CamelToBeanUri */
deprecated class CamelToBeanURI = CamelToBeanUri;
/**
* A Class whose methods may be called in response to an Apache Camel message.
*/

View File

@@ -9,9 +9,6 @@ class JaxbElement extends Class {
}
}
/** DEPRECATED: Alias for JaxbElement */
deprecated class JAXBElement = JaxbElement;
class JaxbMarshalMethod extends Method {
JaxbMarshalMethod() {
this.getDeclaringType().getQualifiedName() = "javax.xml.bind.Marshaller" and
@@ -19,9 +16,6 @@ class JaxbMarshalMethod extends Method {
}
}
/** DEPRECATED: Alias for JaxbMarshalMethod */
deprecated class JAXBMarshalMethod = JaxbMarshalMethod;
class JaxbAnnotationType extends AnnotationType {
JaxbAnnotationType() { this.getPackage().getName() = "javax.xml.bind.annotation" }
}

View File

@@ -0,0 +1,23 @@
/** Provides definitions related to the Netty framework. */
import java
/** The interface `Cookie` in the packages `io.netty.handler.codec.http` and `io.netty.handler.codec.http.cookie`. */
class NettyCookie extends Interface {
NettyCookie() { this.hasQualifiedName("io.netty.handler.codec.http" + [".cookie", ""], "Cookie") }
}
/** The class `DefaultCookie` in the packages `io.netty.handler.codec.http` and `io.netty.handler.codec.http.cookie`. */
class NettyDefaultCookie extends Class {
NettyDefaultCookie() {
this.hasQualifiedName("io.netty.handler.codec.http" + [".cookie", ""], "DefaultCookie")
}
}
/** The method `setValue` of the interface `Cookie` or a class implementing it. */
class NettySetCookieValueMethod extends Method {
NettySetCookieValueMethod() {
this.getDeclaringType*() instanceof NettyCookie and
this.hasName("setValue")
}
}

View File

@@ -0,0 +1,29 @@
/**
* Provides classes and predicates for working with the OpenSAML libraries.
*/
import java
private import semmle.code.java.security.InsecureRandomnessQuery
/** The interface `org.opensaml.saml.saml2.core.RequestAbstractType`. */
class SamlRequestAbstractType extends Interface {
SamlRequestAbstractType() {
this.hasQualifiedName("org.opensaml.saml.saml2.core", "RequestAbstractType")
}
}
/** The method `setID` of the interface `RequestAbstractType`. */
class SamlRequestSetIdMethod extends Method {
SamlRequestSetIdMethod() {
this.getDeclaringType() instanceof SamlRequestAbstractType and
this.hasName("setID")
}
}
private class SamlRequestSetIdSink extends InsecureRandomnessSink {
SamlRequestSetIdSink() {
exists(MethodCall c | c.getMethod() instanceof SamlRequestSetIdMethod |
c.getArgument(0) = this.asExpr()
)
}
}

View File

@@ -139,9 +139,6 @@ class HttpServletRequestGetRequestUriMethod extends Method {
}
}
/** DEPRECATED: Alias for HttpServletRequestGetRequestUriMethod */
deprecated class HttpServletRequestGetRequestURIMethod = HttpServletRequestGetRequestUriMethod;
/**
* The method `getRemoteUser()` declared in `javax.servlet.http.HttpServletRequest`.
*/
@@ -244,7 +241,7 @@ class TypeCookie extends Class {
}
/**
* The method `getValue(String)` declared in `javax.servlet.http.Cookie`.
* The method `getValue()` declared in `javax.servlet.http.Cookie`.
*/
class CookieGetValueMethod extends Method {
CookieGetValueMethod() {
@@ -254,6 +251,16 @@ class CookieGetValueMethod extends Method {
}
}
/**
* The method `setValue(String)` declared in `javax.servlet.http.Cookie`.
*/
class CookieSetValueMethod extends Method {
CookieSetValueMethod() {
this.getDeclaringType() instanceof TypeCookie and
this.hasName("setValue")
}
}
/**
* The method `getName()` declared in `javax.servlet.http.Cookie`.
*/

View File

@@ -62,9 +62,6 @@ class MethodUnboundIdFilterCreateAndFilter extends Method {
}
}
/** DEPRECATED: Alias for MethodUnboundIdFilterCreateAndFilter */
deprecated class MethodUnboundIdFilterCreateANDFilter = MethodUnboundIdFilterCreateAndFilter;
/** A method with the name `createORFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
class MethodUnboundIdFilterCreateORFilter extends Method {
MethodUnboundIdFilterCreateORFilter() {
@@ -73,9 +70,6 @@ class MethodUnboundIdFilterCreateORFilter extends Method {
}
}
/** DEPRECATED: Alias for MethodUnboundIdFilterCreateNOTFilter */
deprecated class MethodUnboundIdFilterCreateNOTFilter = MethodUnboundIdFilterCreateNotFilter;
/** A method with the name `createNOTFilter` declared in `com.unboundid.ldap.sdk.Filter`. */
class MethodUnboundIdFilterCreateNotFilter extends Method {
MethodUnboundIdFilterCreateNotFilter() {

View File

@@ -65,18 +65,6 @@ class AndroidServiceIntentMethod extends Method {
}
}
/**
* The method `Context.startActivity` or `startActivities`.
*
* DEPRECATED: Use `StartActivityMethod` instead.
*/
deprecated class ContextStartActivityMethod extends Method {
ContextStartActivityMethod() {
(this.hasName("startActivity") or this.hasName("startActivities")) and
this.getDeclaringType() instanceof TypeContext
}
}
/**
* The method `Context.startActivity`, `Context.startActivities`,
* `Activity.startActivity`,`Activity.startActivities`,

View File

@@ -47,9 +47,6 @@ class CamelJavaDslToDecl extends ProcessorDefinitionElement {
deprecated string getURI() { result = this.getUri() }
}
/** DEPRECATED: Alias for CamelJavaDslToDecl */
deprecated class CamelJavaDSLToDecl = CamelJavaDslToDecl;
/**
* A declaration of a "bean" target in the Apache Camel Java DSL.
*
@@ -74,9 +71,6 @@ class CamelJavaDslBeanDecl extends ProcessorDefinitionElement {
}
}
/** DEPRECATED: Alias for CamelJavaDslBeanDecl */
deprecated class CamelJavaDSLBeanDecl = CamelJavaDslBeanDecl;
/**
* A declaration of a "beanRef" target in the Apache Camel Java DSL.
*
@@ -106,9 +100,6 @@ class CamelJavaDslBeanRefDecl extends ProcessorDefinitionElement {
}
}
/** DEPRECATED: Alias for CamelJavaDslBeanRefDecl */
deprecated class CamelJavaDSLBeanRefDecl = CamelJavaDslBeanRefDecl;
/**
* A "method" Camel expression in the Apache Camel Java DSL.
*
@@ -140,6 +131,3 @@ class CamelJavaDslMethodDecl extends MethodCall {
else result = this.getArgument(0).getType()
}
}
/** DEPRECATED: Alias for CamelJavaDslMethodDecl */
deprecated class CamelJavaDSLMethodDecl = CamelJavaDslMethodDecl;

View File

@@ -99,9 +99,6 @@ class JsniComment extends Javadoc {
Method getImplementedMethod() { jsniComment(this, result) }
}
/** DEPRECATED: Alias for JsniComment */
deprecated class JSNIComment = JsniComment;
/**
* A JavaScript Native Interface (JSNI) method.
*/
@@ -111,6 +108,3 @@ class JsniMethod extends Method {
/** Gets the comment containing the JavaScript code for this method. */
JsniComment getImplementation() { jsniComment(result, this) }
}
/** DEPRECATED: Alias for JsniMethod */
deprecated class JSNIMethod = JsniMethod;

View File

@@ -16,9 +16,6 @@ class OcniComment extends Javadoc {
}
}
/** DEPRECATED: Alias for OcniComment */
deprecated class OCNIComment = OcniComment;
/** Auxiliary predicate: `ocni` is an OCNI comment associated with method `m`. */
private predicate ocniComment(OcniComment ocni, Method m) {
// The associated callable must be marked as `native` ...
@@ -40,9 +37,6 @@ class OcniMethodComment extends OcniComment {
Method getImplementedMethod() { ocniComment(this, result) }
}
/** DEPRECATED: Alias for OcniMethodComment */
deprecated class OCNIMethodComment = OcniMethodComment;
/**
* An Objective-C Native Interface (OCNI) native import comment.
*/
@@ -54,6 +48,3 @@ class OcniImport extends OcniComment {
)
}
}
/** DEPRECATED: Alias for OcniImport */
deprecated class OCNIImport = OcniImport;

View File

@@ -112,9 +112,6 @@ class SessionEjb extends EJB {
EjbAnnotatedInitMethod getAnAnnotatedInitMethod() { this.inherits(result) }
}
/** DEPRECATED: Alias for SessionEjb */
deprecated class SessionEJB = SessionEjb;
/**
* A stateful session EJB.
*/
@@ -132,9 +129,6 @@ class StatefulSessionEjb extends SessionEjb {
}
}
/** DEPRECATED: Alias for StatefulSessionEjb */
deprecated class StatefulSessionEJB = StatefulSessionEjb;
/**
* A stateless session EJB.
*/
@@ -152,9 +146,6 @@ class StatelessSessionEjb extends SessionEjb {
}
}
/** DEPRECATED: Alias for StatelessSessionEjb */
deprecated class StatelessSessionEJB = StatelessSessionEjb;
/**
* A message-driven EJB.
*/
@@ -190,9 +181,6 @@ class EntityEjb extends EJB {
}
}
/** DEPRECATED: Alias for EntityEjb */
deprecated class EntityEJB = EntityEjb;
/*
* Business interfaces (applicable to session beans).
*/
@@ -245,9 +233,6 @@ abstract class BusinessInterface extends Interface {
/** Gets an EJB to which this business interface belongs. */
abstract SessionEjb getAnEjb();
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
/** Holds if this business interface is declared local. */
abstract predicate isDeclaredLocal();
@@ -274,9 +259,6 @@ class XmlSpecifiedBusinessInterface extends BusinessInterface {
)
}
/** DEPRECATED: Alias for getAnEjb */
deprecated override SessionEJB getAnEJB() { result = this.getAnEjb() }
override predicate isDeclaredLocal() {
exists(EjbJarXmlFile f |
this.getQualifiedName() =
@@ -313,9 +295,6 @@ class AnnotatedBusinessInterface extends BusinessInterface {
result.getAnAnnotation().(BusinessInterfaceAnnotation).getANamedType() = this
}
/** DEPRECATED: Alias for getAnEjb */
deprecated override SessionEJB getAnEJB() { result = this.getAnEjb() }
override predicate isDeclaredLocal() { this instanceof LocalAnnotatedBusinessInterface }
override predicate isDeclaredRemote() { this instanceof RemoteAnnotatedBusinessInterface }
@@ -449,9 +428,6 @@ class XmlSpecifiedRemoteInterface extends LegacyEjbRemoteInterface {
result.getQualifiedName() = se.getAnEjbClassElement().getACharactersSet().getCharacters()
)
}
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
}
/** A legacy remote home interface. */
@@ -470,9 +446,6 @@ class AnnotatedRemoteHomeInterface extends LegacyEjbRemoteHomeInterface {
/** Gets an EJB to which this interface belongs. */
SessionEjb getAnEjb() { result.getAnAnnotation().(RemoteHomeAnnotation).getANamedType() = this }
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
/** Gets a remote interface associated with this legacy remote home interface. */
Interface getAnAssociatedRemoteInterface() { result = this.getACreateMethod().getReturnType() }
}
@@ -494,9 +467,6 @@ class XmlSpecifiedRemoteHomeInterface extends LegacyEjbRemoteHomeInterface {
result.getQualifiedName() = se.getAnEjbClassElement().getACharactersSet().getCharacters()
)
}
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
}
/** A legacy local interface. */
@@ -522,9 +492,6 @@ class XmlSpecifiedLocalInterface extends LegacyEjbLocalInterface {
result.getQualifiedName() = se.getAnEjbClassElement().getACharactersSet().getCharacters()
)
}
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
}
/** A legacy local home interface. */
@@ -543,9 +510,6 @@ class AnnotatedLocalHomeInterface extends LegacyEjbLocalHomeInterface {
/** Gets an EJB to which this interface belongs. */
SessionEjb getAnEjb() { result.getAnAnnotation().(LocalHomeAnnotation).getANamedType() = this }
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
/** Gets a local interface associated with this legacy local home interface. */
Interface getAnAssociatedLocalInterface() { result = this.getACreateMethod().getReturnType() }
}
@@ -567,9 +531,6 @@ class XmlSpecifiedLocalHomeInterface extends LegacyEjbLocalHomeInterface {
result.getQualifiedName() = se.getAnEjbClassElement().getACharactersSet().getCharacters()
)
}
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
}
/**
@@ -593,9 +554,6 @@ class RemoteInterface extends Interface {
result.getARemoteInterface() = this
}
/** DEPRECATED: Alias for getAnEjb */
deprecated SessionEJB getAnEJB() { result = this.getAnEjb() }
/**
* A "remote method" is a method that is available on the remote
* interface (either because it's declared or inherited).
@@ -860,9 +818,6 @@ class EjbAnnotation extends Annotation {
EjbAnnotation() { this.getType().hasQualifiedName("javax.ejb", "EJB") }
}
/** DEPRECATED: Alias for EjbAnnotation */
deprecated class EJBAnnotation = EjbAnnotation;
/**
* A `@javax.ejb.EJBs` annotation.
*/

View File

@@ -479,7 +479,7 @@ abstract class RegexString extends StringLiteral {
private predicate flagGroupStartNoModes(int start, int end) {
this.isGroupStart(start) and
this.getChar(start + 1) = "?" and
this.getChar(start + 2) in ["i", "m", "s", "u", "x", "U"] and
this.getChar(start + 2) in ["-", "i", "d", "m", "s", "u", "x", "U"] and
end = start + 2
}
@@ -491,7 +491,7 @@ abstract class RegexString extends StringLiteral {
this.flagGroupStartNoModes(start, pos)
or
this.modeCharacter(start, pos - 1) and
this.getChar(pos) in ["i", "m", "s", "u", "x", "U"]
this.getChar(pos) in ["-", "i", "d", "m", "s", "u", "x", "U"]
}
/**
@@ -499,7 +499,10 @@ abstract class RegexString extends StringLiteral {
*/
private predicate flagGroupStart(int start, int end) {
this.flagGroupStartNoModes(start, _) and
end = max(int i | this.modeCharacter(start, i) | i + 1)
// Check if this is a capturing group with flags, and therefore the `:` should be excluded
exists(int maybeEnd | maybeEnd = max(int i | this.modeCharacter(start, i) | i + 1) |
if this.getChar(maybeEnd) = ":" then end = maybeEnd + 1 else end = maybeEnd
)
}
/**
@@ -510,9 +513,15 @@ abstract class RegexString extends StringLiteral {
* ```
*/
private predicate flag(string c) {
exists(int pos |
this.modeCharacter(_, pos) and
this.getChar(pos) = c
exists(int start, int pos |
this.modeCharacter(start, pos) and
this.getChar(pos) = c and
// Ignore if flag is disabled; use `<=` to also exclude `-` itself
// This does not properly handle the (contrived) case where a flag is both enabled and
// disabled, e.g. `(?i-i)a+`, in which case the flag seems to acts as if it was disabled
not exists(int minusPos |
this.modeCharacter(start, minusPos) and this.getChar(minusPos) = "-" and minusPos <= pos
)
)
}
@@ -524,6 +533,8 @@ abstract class RegexString extends StringLiteral {
exists(string c | this.flag(c) |
c = "i" and result = "IGNORECASE"
or
c = "d" and result = "UNIXLINES"
or
c = "m" and result = "MULTILINE"
or
c = "s" and result = "DOTALL"
@@ -930,13 +941,13 @@ class Regex extends RegexString {
/**
* Gets a mode (if any) of this regular expression. Can be any of:
* DEBUG
* IGNORECASE
* MULTILINE
* DOTALL
* UNICODE
* VERBOSE
* UNICODECLASS
* - IGNORECASE
* - UNIXLINES
* - MULTILINE
* - DOTALL
* - UNICODE
* - VERBOSE
* - UNICODECLASS
*/
string getAMode() {
result != "None" and
@@ -946,7 +957,7 @@ class Regex extends RegexString {
}
/**
* Holds if this regex is used to match against a full string,
* Holds if this regex is used to match against a full string,
* as though it was implicitly surrounded by ^ and $.
*/
predicate matchesFullString() { matches_full_string = true }

View File

@@ -3,6 +3,7 @@
import java
private import semmle.code.java.security.Encryption
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.security.Sanitizers
private class ShortStringLiteral extends StringLiteral {
ShortStringLiteral() { this.getValue().length() < 100 }
@@ -27,9 +28,7 @@ module InsecureCryptoConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
}
/**

View File

@@ -12,6 +12,7 @@ private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.security.CommandArguments
private import semmle.code.java.security.ExternalProcess
private import semmle.code.java.security.Sanitizers
/** A sink for command injection vulnerabilities. */
abstract class CommandInjectionSink extends DataFlow::Node { }
@@ -38,11 +39,7 @@ private class DefaultCommandInjectionSink extends CommandInjectionSink {
private class DefaultCommandInjectionSanitizer extends CommandInjectionSanitizer {
DefaultCommandInjectionSanitizer() {
this.getType() instanceof PrimitiveType
or
this.getType() instanceof BoxedType
or
this.getType() instanceof NumberType
this instanceof SimpleTypeSanitizer
or
isSafeCommandArgument(this.asExpr())
}

View File

@@ -0,0 +1,32 @@
/** Provides definitions to reason about HTTP cookies. */
import java
private import semmle.code.java.frameworks.Netty
private import semmle.code.java.frameworks.Servlets
/** An expression setting the value of a cookie. */
abstract class SetCookieValue extends Expr { }
private class ServletSetCookieValue extends SetCookieValue {
ServletSetCookieValue() {
exists(Call c |
c.(ClassInstanceExpr).getConstructedType() instanceof TypeCookie and
this = c.getArgument(1)
or
c.(MethodCall).getMethod() instanceof CookieSetValueMethod and
this = c.getArgument(0)
)
}
}
private class NettySetCookieValue extends SetCookieValue {
NettySetCookieValue() {
exists(Call c |
c.(ClassInstanceExpr).getConstructedType() instanceof NettyDefaultCookie and
this = c.getArgument(1)
or
c.(MethodCall).getMethod() instanceof NettySetCookieValueMethod and
this = c.getArgument(0)
)
}
}

View File

@@ -13,9 +13,6 @@ class SslClass extends RefType {
}
}
/** DEPRECATED: Alias for SslClass */
deprecated class SSLClass = SslClass;
class X509TrustManager extends RefType {
X509TrustManager() { this.hasQualifiedName("javax.net.ssl", "X509TrustManager") }
}
@@ -29,48 +26,30 @@ class SslSocketFactory extends RefType {
SslSocketFactory() { this.hasQualifiedName("javax.net.ssl", "SSLSocketFactory") }
}
/** DEPRECATED: Alias for SslSocketFactory */
deprecated class SSLSocketFactory = SslSocketFactory;
class SslContext extends RefType {
SslContext() { this.hasQualifiedName("javax.net.ssl", "SSLContext") }
}
/** DEPRECATED: Alias for SslContext */
deprecated class SSLContext = SslContext;
/** The `javax.net.ssl.SslSession` class. */
class SslSession extends RefType {
SslSession() { this.hasQualifiedName("javax.net.ssl", "SSLSession") }
}
/** DEPRECATED: Alias for SslSession */
deprecated class SSLSession = SslSession;
/** The `javax.net.ssl.SslEngine` class. */
class SslEngine extends RefType {
SslEngine() { this.hasQualifiedName("javax.net.ssl", "SSLEngine") }
}
/** DEPRECATED: Alias for SslEngine */
deprecated class SSLEngine = SslEngine;
/** The `javax.net.ssl.SslSocket` class. */
class SslSocket extends RefType {
SslSocket() { this.hasQualifiedName("javax.net.ssl", "SSLSocket") }
}
/** DEPRECATED: Alias for SslSocket */
deprecated class SSLSocket = SslSocket;
/** The `javax.net.ssl.SslParameters` class. */
class SslParameters extends RefType {
SslParameters() { this.hasQualifiedName("javax.net.ssl", "SSLParameters") }
}
/** DEPRECATED: Alias for SslParameters */
deprecated class SSLParameters = SslParameters;
class HostnameVerifier extends RefType {
HostnameVerifier() { this.hasQualifiedName("javax.net.ssl", "HostnameVerifier") }
}

View File

@@ -4,6 +4,7 @@ import java
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.ExternalProcess
private import semmle.code.java.security.CommandArguments
private import semmle.code.java.security.Sanitizers
/** A taint-tracking configuration to reason about use of externally controlled strings to make command line commands. */
module ExecTaintedLocalConfig implements DataFlow::ConfigSig {
@@ -12,9 +13,7 @@ module ExecTaintedLocalConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ArgumentToExec }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
node instanceof SimpleTypeSanitizer
or
isSafeCommandArgument(node.asExpr())
}

View File

@@ -4,6 +4,7 @@ import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.Networking
import semmle.code.java.security.HttpsUrls
private import semmle.code.java.security.Sanitizers
/**
* DEPRECATED: Use `HttpsStringToUrlOpenMethodFlow` instead.
@@ -38,9 +39,7 @@ module HttpStringToUrlOpenMethodFlowConfig implements DataFlow::ConfigSig {
any(HttpUrlsAdditionalTaintStep c).step(node1, node2)
}
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
}
/**

View File

@@ -1,12 +1,14 @@
/** Provides classes and predicates for reasoning about insecure randomness. */
import java
private import semmle.code.java.frameworks.OpenSaml
private import semmle.code.java.frameworks.Servlets
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.security.Cookies
private import semmle.code.java.security.RandomQuery
private import semmle.code.java.security.SensitiveActions
private import semmle.code.java.security.SensitiveApi
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.security.RandomQuery
/**
* A node representing a source of insecure randomness.
@@ -18,7 +20,7 @@ abstract class InsecureRandomnessSource extends DataFlow::Node { }
private class RandomMethodSource extends InsecureRandomnessSource {
RandomMethodSource() {
exists(RandomDataSource s | this.asExpr() = s.getOutput() |
not s.getQualifier().getType() instanceof SafeRandomImplementation
not s.getSourceOfRandomness() instanceof SafeRandomImplementation
)
}
}
@@ -40,7 +42,7 @@ private class TypeHadoopOsSecureRandom extends SafeRandomImplementation {
}
/**
* A node representing an operation which should not use a Insecurely random value.
* A node representing an operation which should not use an insecurely random value.
*/
abstract class InsecureRandomnessSink extends DataFlow::Node { }
@@ -48,16 +50,7 @@ abstract class InsecureRandomnessSink extends DataFlow::Node { }
* A node which sets the value of a cookie.
*/
private class CookieSink extends InsecureRandomnessSink {
CookieSink() {
exists(Call c |
c.(ClassInstanceExpr).getConstructedType() instanceof TypeCookie and
this.asExpr() = c.getArgument(1)
or
c.(MethodCall).getMethod().getDeclaringType() instanceof TypeCookie and
c.(MethodCall).getMethod().hasName("setValue") and
this.asExpr() = c.getArgument(0)
)
}
CookieSink() { this.asExpr() instanceof SetCookieValue }
}
private class SensitiveActionSink extends InsecureRandomnessSink {
@@ -76,6 +69,8 @@ module InsecureRandomnessConfig implements DataFlow::ConfigSig {
predicate isBarrierIn(DataFlow::Node n) { isSource(n) }
predicate isBarrierOut(DataFlow::Node n) { isSink(n) }
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
n1.asExpr() = n2.asExpr().(BinaryExpr).getAnOperand()
or
@@ -88,6 +83,17 @@ module InsecureRandomnessConfig implements DataFlow::ConfigSig {
n1.asExpr() = mc.getArgument(0) and
n2.asExpr() = mc
)
or
// TODO: Once we have a default sanitizer for UUIDs, we can convert these to global summaries.
exists(Call c |
c.(ClassInstanceExpr).getConstructedType().hasQualifiedName("java.util", "UUID") and
n1.asExpr() = c.getAnArgument() and
n2.asExpr() = c
or
c.(MethodCall).getMethod().hasQualifiedName("java.util", "UUID", "toString") and
n1.asExpr() = c.getQualifier() and
n2.asExpr() = c
)
}
}

View File

@@ -5,6 +5,7 @@ import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.Jndi
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.security.JndiInjection
private import semmle.code.java.security.Sanitizers
/**
* DEPRECATED: Use `JndiInjectionFlow` instead.
@@ -19,8 +20,7 @@ deprecated class JndiInjectionFlowConfig extends TaintTracking::Configuration {
override predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node instanceof SimpleTypeSanitizer or
node instanceof JndiInjectionSanitizer
}
@@ -38,8 +38,7 @@ module JndiInjectionFlowConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof JndiInjectionSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node instanceof SimpleTypeSanitizer or
node instanceof JndiInjectionSanitizer
}

View File

@@ -7,6 +7,7 @@ import semmle.code.java.frameworks.UnboundId
import semmle.code.java.frameworks.SpringLdap
import semmle.code.java.frameworks.ApacheLdap
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.security.Sanitizers
/** A data flow sink for unvalidated user input that is used to construct LDAP queries. */
abstract class LdapInjectionSink extends DataFlow::Node { }
@@ -33,12 +34,7 @@ private class DefaultLdapInjectionSink extends LdapInjectionSink {
}
/** A sanitizer that clears the taint on (boxed) primitive types. */
private class DefaultLdapSanitizer extends LdapInjectionSanitizer {
DefaultLdapSanitizer() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType
}
}
private class DefaultLdapSanitizer extends LdapInjectionSanitizer instanceof SimpleTypeSanitizer { }
/**
* Holds if `n1` to `n2` is a dataflow step that converts between `String` and `LdapName`,

View File

@@ -4,6 +4,7 @@ import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.security.Sanitizers
/** A data flow sink for unvalidated user input that is used to log messages. */
abstract class LogInjectionSink extends DataFlow::Node { }
@@ -30,13 +31,8 @@ private class DefaultLogInjectionSink extends LogInjectionSink {
DefaultLogInjectionSink() { sinkNode(this, "log-injection") }
}
private class DefaultLogInjectionSanitizer extends LogInjectionSanitizer {
DefaultLogInjectionSanitizer() {
this.getType() instanceof BoxedType or
this.getType() instanceof PrimitiveType or
this.getType() instanceof NumericType
}
}
private class DefaultLogInjectionSanitizer extends LogInjectionSanitizer instanceof SimpleTypeSanitizer
{ }
private class LineBreaksLogInjectionSanitizer extends LogInjectionSanitizer {
LineBreaksLogInjectionSanitizer() {

View File

@@ -3,6 +3,7 @@
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.OgnlInjection
private import semmle.code.java.security.Sanitizers
/**
* DEPRECATED: Use `OgnlInjectionFlow` instead.
@@ -33,9 +34,7 @@ module OgnlInjectionFlowConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof OgnlInjectionSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(OgnlInjectionAdditionalTaintStep c).step(node1, node2)

View File

@@ -1,8 +0,0 @@
/**
* Classes and predicates for working with suspicious character ranges.
*/
private import semmle.code.java.regex.RegexTreeView::RegexTreeView as TreeView
// OverlyLargeRangeQuery should be used directly from the shared pack, and not from this file.
deprecated import codeql.regex.OverlyLargeRangeQuery::Make<TreeView> as Dep
import Dep

View File

@@ -3,6 +3,7 @@
*/
import java
private import semmle.code.java.dataflow.TypeFlow
/**
* A method access that returns random data or writes random data to an argument.
@@ -43,6 +44,9 @@ abstract class RandomDataSource extends MethodCall {
* in the case where it writes random data to that argument.
*/
abstract Expr getOutput();
/** Gets the type of the source of randomness used by this call. */
RefType getSourceOfRandomness() { boundOrStaticType(this.getQualifier(), result) }
}
/**
@@ -167,4 +171,18 @@ class ApacheCommonsRandomStringSource extends RandomDataSource {
}
override Expr getOutput() { result = this }
override RefType getSourceOfRandomness() {
if
this.getMethod().hasStringSignature("random(int, int, int, boolean, boolean, char[], Random)")
then boundOrStaticType(this.getArgument(6), result)
else result.hasQualifiedName("java.util", "Random")
}
}
/** Holds if `t` is the static type of `e`, or an upper bound of the runtime type of `e`. */
private predicate boundOrStaticType(Expr e, RefType t) {
exprTypeFlow(e, t, false)
or
t = e.getType()
}

View File

@@ -10,6 +10,7 @@ import semmle.code.java.dataflow.DataFlow
import semmle.code.java.frameworks.Properties
private import semmle.code.java.dataflow.StringPrefixes
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.security.Sanitizers
/**
* A unit class for adding additional taint steps that are specific to server-side request forgery (SSRF) attacks.
@@ -59,13 +60,7 @@ private class DefaultRequestForgerySink extends RequestForgerySink {
/** A sanitizer for request forgery vulnerabilities. */
abstract class RequestForgerySanitizer extends DataFlow::Node { }
private class PrimitiveSanitizer extends RequestForgerySanitizer {
PrimitiveSanitizer() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType or
this.getType() instanceof NumberType
}
}
private class PrimitiveSanitizer extends RequestForgerySanitizer instanceof SimpleTypeSanitizer { }
private class HostnameSanitizingPrefix extends InterestingPrefix {
int offset;

View File

@@ -2,6 +2,7 @@
import java
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.Sanitizers
import semmle.code.java.security.ResponseSplitting
/**
@@ -16,9 +17,7 @@ module ResponseSplittingConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType
or
node.getType() instanceof BoxedType
node instanceof SimpleTypeSanitizer
or
exists(MethodCall ma, string methodName, CompileTimeConstantExpr target |
node.asExpr() = ma and

View File

@@ -0,0 +1,15 @@
/** Classes to represent sanitizers commonly used in dataflow and taint tracking configurations. */
import java
private import semmle.code.java.dataflow.DataFlow
/**
* A node whose type is a simple type unlikely to carry taint, such as primitives or their boxed counterparts.
*/
class SimpleTypeSanitizer extends DataFlow::Node {
SimpleTypeSanitizer() {
this.getType() instanceof PrimitiveType or
this.getType() instanceof BoxedType or
this.getType() instanceof NumberType
}
}

View File

@@ -5,6 +5,7 @@ private import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.security.SensitiveActions
import semmle.code.java.frameworks.android.Compose
private import semmle.code.java.security.Sanitizers
/** A variable that may hold sensitive information, judging by its name. */
class CredentialExpr extends Expr {
@@ -55,9 +56,7 @@ module SensitiveLoggerConfig implements DataFlow::ConfigSig {
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.asExpr() instanceof LiveLiteral or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof NumberType or
sanitizer instanceof SimpleTypeSanitizer or
sanitizer.getType() instanceof TypeType
}

View File

@@ -4,6 +4,7 @@ import java
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.security.SqlConcatenatedLib
private import semmle.code.java.security.SqlInjectionQuery
private import semmle.code.java.security.Sanitizers
private class UncontrolledStringBuilderSource extends DataFlow::ExprNode {
UncontrolledStringBuilderSource() {
@@ -22,9 +23,7 @@ module UncontrolledStringBuilderSourceFlowConfig implements DataFlow::ConfigSig
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
}
/**

View File

@@ -8,6 +8,7 @@
import java
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.Sanitizers
import semmle.code.java.security.QueryInjection
/**
@@ -41,11 +42,7 @@ module QueryInjectionFlowConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node.getType() instanceof NumberType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)

View File

@@ -6,6 +6,7 @@
import java
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.SqlInjectionQuery
private import semmle.code.java.security.Sanitizers
/**
* A taint-tracking configuration for reasoning about local user input that is
@@ -16,11 +17,7 @@ module LocalUserInputToQueryInjectionFlowConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType or
node.getType() instanceof NumberType
}
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
any(AdditionalQueryInjectionTaintStep s).step(node1, node2)

View File

@@ -0,0 +1,46 @@
/** Modules to reason about the tainting of environment variables */
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.Maps
private import semmle.code.java.JDK
private module ProcessBuilderEnvironmentConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(MethodCall mc | mc = source.asExpr() |
mc.getMethod().hasQualifiedName("java.lang", "ProcessBuilder", "environment")
)
}
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(MapMutation mm).getQualifier() }
}
private module ProcessBuilderEnvironmentFlow = DataFlow::Global<ProcessBuilderEnvironmentConfig>;
/**
* A node that acts as a sanitizer in configurations related to environment variable injection.
*/
abstract class ExecTaintedEnvironmentSanitizer extends DataFlow::Node { }
/**
* A taint-tracking configuration that tracks flow from unvalidated data to an environment variable for a subprocess.
*/
module ExecTaintedEnvironmentConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelFlowSource }
predicate isBarrier(DataFlow::Node barrier) { barrier instanceof ExecTaintedEnvironmentSanitizer }
predicate isSink(DataFlow::Node sink) {
sinkNode(sink, "environment-injection")
or
// sink is a key or value added to a `ProcessBuilder::environment` map.
exists(MapMutation mm | mm.getAnArgument() = sink.asExpr() |
ProcessBuilderEnvironmentFlow::flowToExpr(mm.getQualifier())
)
}
}
/**
* Taint-tracking flow for unvalidated data to an environment variable for a subprocess.
*/
module ExecTaintedEnvironmentFlow = TaintTracking::Global<ExecTaintedEnvironmentConfig>;

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