mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge remote-tracking branch 'origin/codeql-cli-2.16.1' into henrymercer/2.16.0-mergeback
This commit is contained in:
@@ -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"
|
||||
@@ -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.
|
||||
|
||||
@@ -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", //
|
||||
|
||||
@@ -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: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
|
||||
@@ -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: $@, $@, $@, $@, $@, $@, $@, $@, $@.", //
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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", //
|
||||
|
||||
@@ -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", //
|
||||
|
||||
@@ -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", //
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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, _) }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.0.13
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.0.12
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
java/ql/automodel/src/change-notes/released/0.0.13.md
Normal file
3
java/ql/automodel/src/change-notes/released/0.0.13.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.13
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.12
|
||||
lastReleaseVersion: 0.0.13
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-automodel-queries
|
||||
version: 0.0.12
|
||||
version: 0.0.13
|
||||
groups:
|
||||
- java
|
||||
- automodel
|
||||
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelApplicationModeExtractCandidates.ql
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelApplicationModeExtractNegativeExamples.ql
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelApplicationModeExtractPositiveExamples.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
testFailures
|
||||
failures
|
||||
@@ -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>>
|
||||
@@ -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]
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
77
java/ql/automodel/test/AutomodelExtractionTests.qll
Normal file
77
java/ql/automodel/test/AutomodelExtractionTests.qll
Normal 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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelFrameworkModeExtractCandidates.ql
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelFrameworkModeExtractNegativeExamples.ql
|
||||
@@ -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 |
|
||||
@@ -1 +0,0 @@
|
||||
AutomodelFrameworkModeExtractPositiveExamples.ql
|
||||
@@ -0,0 +1,2 @@
|
||||
testFailures
|
||||
failures
|
||||
@@ -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>>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ groups:
|
||||
dependencies:
|
||||
codeql/java-all: ${workspace}
|
||||
codeql/java-automodel-queries: ${workspace}
|
||||
codeql/java-tests: ${workspace}
|
||||
extractor: java
|
||||
tests: .
|
||||
warnOnImplicitThis: true
|
||||
@@ -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
|
||||
|
||||
25
java/ql/lib/change-notes/released/0.8.7.md
Normal file
25
java/ql/lib/change-notes/released/0.8.7.md
Normal 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.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.8.6
|
||||
lastReleaseVersion: 0.8.7
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"]
|
||||
@@ -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"]
|
||||
@@ -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"]
|
||||
|
||||
@@ -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"]
|
||||
9
java/ql/lib/ext/org.pac4j.jwt.config.signature.model.yml
Normal file
9
java/ql/lib/ext/org.pac4j.jwt.config.signature.model.yml
Normal 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"]
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-all
|
||||
version: 0.8.6
|
||||
version: 0.8.7
|
||||
groups: java
|
||||
dbscheme: config/semmlecode.dbscheme
|
||||
extractor: java
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(), _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -302,8 +302,3 @@ private module Dispatch {
|
||||
}
|
||||
|
||||
import Dispatch
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `TypeFlow` instead.
|
||||
*/
|
||||
deprecated Expr variableTrack(Expr use) { result = use }
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
23
java/ql/lib/semmle/code/java/frameworks/Netty.qll
Normal file
23
java/ql/lib/semmle/code/java/frameworks/Netty.qll
Normal 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")
|
||||
}
|
||||
}
|
||||
29
java/ql/lib/semmle/code/java/frameworks/OpenSaml.qll
Normal file
29
java/ql/lib/semmle/code/java/frameworks/OpenSaml.qll
Normal 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()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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`.
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
32
java/ql/lib/semmle/code/java/security/Cookies.qll
Normal file
32
java/ql/lib/semmle/code/java/security/Cookies.qll
Normal 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)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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") }
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
15
java/ql/lib/semmle/code/java/security/Sanitizers.qll
Normal file
15
java/ql/lib/semmle/code/java/security/Sanitizers.qll
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user