mirror of
https://github.com/github/codeql.git
synced 2026-05-22 07:07:09 +02:00
Merge branch 'main' into redsun82/just2
This commit is contained in:
@@ -83,7 +83,7 @@ kt_javac_options(
|
||||
"kotlin.RequiresOptIn",
|
||||
"org.jetbrains.kotlin.ir.symbols.%s" %
|
||||
("IrSymbolInternals" if version_less(v, "2.0.0") else "UnsafeDuringIrConstructionAPI"),
|
||||
],
|
||||
] + ([] if version_less(v, "2.2.20") else ["org.jetbrains.kotlin.DeprecatedForRemovalCompilerApi"]),
|
||||
x_suppress_version_warnings = True,
|
||||
),
|
||||
# * extractor.name is different for each version, so we need to put it in different output dirs
|
||||
|
||||
BIN
java/kotlin-extractor/deps/kotlin-compiler-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-compiler-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.2.20-Beta2.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -27,7 +27,7 @@ import shutil
|
||||
import io
|
||||
import os
|
||||
|
||||
DEFAULT_VERSION = "2.1.20"
|
||||
DEFAULT_VERSION = "2.2.0"
|
||||
|
||||
|
||||
def options():
|
||||
|
||||
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
|
||||
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.NameUtils
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
|
||||
|
||||
fun getJvmModuleNameForDeserializedDescriptor(descriptor: CallableMemberDescriptor): String? {
|
||||
return org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor(descriptor)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
|
||||
import org.jetbrains.kotlin.metadata.deserialization.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.*
|
||||
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.*
|
||||
|
||||
fun getJvmModuleNameForDeserializedDescriptor(descriptor: CallableMemberDescriptor): String? {
|
||||
val parent = getParentOfType(descriptor, ClassOrPackageFragmentDescriptor::class.java, false)
|
||||
|
||||
when {
|
||||
parent is DeserializedClassDescriptor -> {
|
||||
val classProto = parent.classProto
|
||||
val nameResolver = parent.c.nameResolver
|
||||
return classProto.getExtensionOrNull(JvmProtoBuf.classModuleName)
|
||||
?.let(nameResolver::getString)
|
||||
?: JvmProtoBufUtil.DEFAULT_MODULE_NAME
|
||||
}
|
||||
descriptor is DeserializedMemberDescriptor -> {
|
||||
val source = descriptor.containerSource
|
||||
if (source is JvmPackagePartSource) {
|
||||
return source.moduleName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ VERSIONS = [
|
||||
"2.1.0-Beta1",
|
||||
"2.1.20-Beta1",
|
||||
"2.2.0-Beta1",
|
||||
"2.2.20-Beta2",
|
||||
]
|
||||
|
||||
def _version_to_tuple(v):
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
def test(codeql, use_java_11, java, android_sdk):
|
||||
def test(codeql, use_java_17, java, android_sdk):
|
||||
codeql.database.create()
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
def test(codeql, use_java_11, java, android_sdk):
|
||||
def test(codeql, use_java_17, java, android_sdk):
|
||||
codeql.database.create()
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
def test(codeql, use_java_11, java, android_sdk, actions_toolchains_file):
|
||||
def test(codeql, use_java_17, java, android_sdk, actions_toolchains_file):
|
||||
codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)})
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
def test(codeql, use_java_11, java, android_sdk, actions_toolchains_file):
|
||||
def test(codeql, use_java_17, java, android_sdk, actions_toolchains_file):
|
||||
codeql.database.create(_env={"LGTM_INDEX_MAVEN_TOOLCHAINS_FILE": str(actions_toolchains_file)})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.2.10.",
|
||||
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 2.2.30.",
|
||||
"severity": "error",
|
||||
"source": {
|
||||
"extractorName": "java",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-queries
|
||||
pack: codeql/java-all
|
||||
extensible: extractorInformationSkipKey
|
||||
data:
|
||||
# These will have unstable values, as they are dependent on the
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-queries
|
||||
pack: codeql/java-all
|
||||
extensible: extractorInformationSkipKey
|
||||
data:
|
||||
# These will have unstable values, as they are dependent on the
|
||||
|
||||
@@ -3,6 +3,8 @@ import runs_on
|
||||
import commands
|
||||
|
||||
|
||||
# This test is temporarily disabled until it is updated to work with Kotlin 2.2
|
||||
|
||||
@runs_on.linux
|
||||
def test(codeql, java_full, cwd, semmle_code_dir, test_dir):
|
||||
build_dir = cwd / "build"
|
||||
@@ -1,6 +1,26 @@
|
||||
## 7.3.3
|
||||
## 7.5.0
|
||||
|
||||
No user-facing changes.
|
||||
### New Features
|
||||
|
||||
* Kotlin versions up to 2.2.2\ *x* are now supported.
|
||||
|
||||
## 7.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The module `semmle.code.java.frameworks.Castor` has been deprecated and will be removed in a future release.
|
||||
* The module `semmle.code.java.frameworks.JYaml` has been deprecated and will be removed in a future release.
|
||||
* The classes `UnsafeHessianInputReadObjectMethod` and `BurlapInputReadObjectMethod` in the module `semmle.code.java.frameworks.HessianBurlap` have been deprecated and will be removed in a future release.
|
||||
* The class `YamlBeansReaderReadMethod` in the module `semmle.code.java.frameworks.YamlBeans` has been deprecated and will be removed in a future release.
|
||||
* The class `MethodApacheSerializationUtilsDeserialize` in the module `semmle.code.java.frameworks.apache.Lang` has been deprecated and will be removed in a future release.
|
||||
|
||||
### New Features
|
||||
|
||||
* You can now add sinks for the query "Deserialization of user-controlled data" (`java/unsafe-deserialization`) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/#extensible-predicates-used-to-create-custom-models-in-java-and-kotlin) by extending `sinkModel` and using the kind "unsafe-deserialization". The existing sinks that do not require extra logic to determine if they are unsafe are now defined in this way.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The qualifiers of a calls to `readObject` on any classes that implement `java.io.ObjectInput` are now recognised as sinks for `java/unsafe-deserialization`. Previously this was only the case for classes which extend `java.io.ObjectInputStream`.
|
||||
|
||||
## 7.3.2
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The qualifiers of a calls to `readObject` on any classes that implement `java.io.ObjectInput` are now recognised as sinks for `java/unsafe-deserialization`. Previously this was only the case for classes which extend `java.io.ObjectInputStream`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* You can now add sinks for the query "Deserialization of user-controlled data" (`java/unsafe-deserialization`) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/#extensible-predicates-used-to-create-custom-models-in-java-and-kotlin) by extending `sinkModel` and using the kind "unsafe-deserialization". The existing sinks which do not require extra logic to determine if they are unsafe are now defined in this way.
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The module `semmle.code.java.frameworks.Castor` has been deprecated and will be removed in a future release.
|
||||
* The module `semmle.code.java.frameworks.JYaml` has been deprecated and will be removed in a future release.
|
||||
* The classes `UnsafeHessianInputReadObjectMethod` and `BurlapInputReadObjectMethod` in the module `semmle.code.java.frameworks.HessianBurlap` have been deprecated and will be removed in a future release.
|
||||
* The class `YamlBeansReaderReadMethod` in the module `semmle.code.java.frameworks.YamlBeans` has been deprecated and will be removed in a future release.
|
||||
* The class `MethodApacheSerializationUtilsDeserialize` in the module `semmle.code.java.frameworks.apache.Lang` has been deprecated and will be removed in a future release.
|
||||
4
java/ql/lib/change-notes/2025-07-28-guardwrappers.md
Normal file
4
java/ql/lib/change-notes/2025-07-28-guardwrappers.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Guard implication logic involving wrapper methods has been improved. In particular, this means fewer false positives for `java/dereferenced-value-may-be-null`.
|
||||
17
java/ql/lib/change-notes/released/7.4.0.md
Normal file
17
java/ql/lib/change-notes/released/7.4.0.md
Normal file
@@ -0,0 +1,17 @@
|
||||
## 7.4.0
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* The module `semmle.code.java.frameworks.Castor` has been deprecated and will be removed in a future release.
|
||||
* The module `semmle.code.java.frameworks.JYaml` has been deprecated and will be removed in a future release.
|
||||
* The classes `UnsafeHessianInputReadObjectMethod` and `BurlapInputReadObjectMethod` in the module `semmle.code.java.frameworks.HessianBurlap` have been deprecated and will be removed in a future release.
|
||||
* The class `YamlBeansReaderReadMethod` in the module `semmle.code.java.frameworks.YamlBeans` has been deprecated and will be removed in a future release.
|
||||
* The class `MethodApacheSerializationUtilsDeserialize` in the module `semmle.code.java.frameworks.apache.Lang` has been deprecated and will be removed in a future release.
|
||||
|
||||
### New Features
|
||||
|
||||
* You can now add sinks for the query "Deserialization of user-controlled data" (`java/unsafe-deserialization`) using [data extensions](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/#extensible-predicates-used-to-create-custom-models-in-java-and-kotlin) by extending `sinkModel` and using the kind "unsafe-deserialization". The existing sinks that do not require extra logic to determine if they are unsafe are now defined in this way.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The qualifiers of a calls to `readObject` on any classes that implement `java.io.ObjectInput` are now recognised as sinks for `java/unsafe-deserialization`. Previously this was only the case for classes which extend `java.io.ObjectInputStream`.
|
||||
5
java/ql/lib/change-notes/released/7.5.0.md
Normal file
5
java/ql/lib/change-notes/released/7.5.0.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 7.5.0
|
||||
|
||||
### New Features
|
||||
|
||||
* Kotlin versions up to 2.2.2\ *x* are now supported.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 7.3.3
|
||||
lastReleaseVersion: 7.5.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-all
|
||||
version: 7.3.4-dev
|
||||
version: 7.5.1-dev
|
||||
groups: java
|
||||
dbscheme: config/semmlecode.dbscheme
|
||||
extractor: java
|
||||
|
||||
@@ -1621,7 +1621,8 @@ private module ControlFlowGraphImpl {
|
||||
result.(AssertThrowNode).getAstNode() = assertstmt
|
||||
)
|
||||
or
|
||||
last(assertstmt.getMessage(), n, NormalCompletion()) and
|
||||
last(assertstmt.getMessage(), n, completion) and
|
||||
completion = NormalCompletion() and
|
||||
result.(AssertThrowNode).getAstNode() = assertstmt
|
||||
)
|
||||
or
|
||||
|
||||
@@ -61,3 +61,9 @@ class Diagnostic extends @diagnostic {
|
||||
/** Gets a textual representation of this diagnostic. */
|
||||
string toString() { result = this.getMessage() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds for extraction information keys that should be skipped from telemetry reports.
|
||||
* This predicate can be extended by other packs to filter out specific telemetry keys.
|
||||
*/
|
||||
extensible predicate extractorInformationSkipKey(string key);
|
||||
|
||||
@@ -57,7 +57,7 @@ private module Input implements BB::InputSig<Location> {
|
||||
* Holds if `node` represents an exit node to be used when calculating
|
||||
* post dominance.
|
||||
*/
|
||||
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::ExitNode }
|
||||
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::NormalExitNode }
|
||||
}
|
||||
|
||||
private module BbImpl = BB::Make<Location, Input>;
|
||||
|
||||
@@ -146,6 +146,8 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
class NormalExitNode = ControlFlow::NormalExitNode;
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { J::dominatingEdge(bb1, bb2) }
|
||||
@@ -322,6 +324,55 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
|
||||
|
||||
Expr getElse() { result = super.getFalseExpr() }
|
||||
}
|
||||
|
||||
class Parameter = J::Parameter;
|
||||
|
||||
private int parameterPosition() { result in [-1, any(Parameter p).getPosition()] }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { this = parameterPosition() }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { this = parameterPosition() }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
overlay[caller?]
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
final private class FinalMethod = Method;
|
||||
|
||||
class NonOverridableMethod extends FinalMethod {
|
||||
NonOverridableMethod() { not super.isOverridable() }
|
||||
|
||||
Parameter getParameter(ParameterPosition ppos) {
|
||||
super.getParameter(ppos) = result and
|
||||
not result.isVarargs()
|
||||
}
|
||||
|
||||
GuardsInput::Expr getAReturnExpr() {
|
||||
exists(ReturnStmt ret |
|
||||
this = ret.getEnclosingCallable() and
|
||||
ret.getResult() = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate nonOverridableMethodCall(MethodCall call, NonOverridableMethod m) {
|
||||
call.getMethod().getSourceDeclaration() = m
|
||||
}
|
||||
|
||||
class NonOverridableMethodCall extends GuardsInput::Expr instanceof MethodCall {
|
||||
NonOverridableMethodCall() { nonOverridableMethodCall(this, _) }
|
||||
|
||||
NonOverridableMethod getMethod() { nonOverridableMethodCall(this, result) }
|
||||
|
||||
GuardsInput::Expr getArgument(ArgumentPosition apos) { result = super.getArgument(apos) }
|
||||
}
|
||||
}
|
||||
|
||||
private module GuardsImpl = SharedGuards::Make<Location, GuardsInput>;
|
||||
@@ -340,6 +391,17 @@ private module LogicInputCommon {
|
||||
NullGuards::nullCheckMethod(call.getMethod(), val.asBooleanValue(), isNull)
|
||||
)
|
||||
}
|
||||
|
||||
predicate additionalImpliesStep(
|
||||
GuardsImpl::PreGuard g1, GuardValue v1, GuardsImpl::PreGuard g2, GuardValue v2
|
||||
) {
|
||||
exists(MethodCall check, int argIndex |
|
||||
g1 = check and
|
||||
v1.getDualValue().isThrowsException() and
|
||||
conditionCheckArgument(check, argIndex, v2.asBooleanValue()) and
|
||||
g2 = check.getArgument(argIndex)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module LogicInput_v1 implements GuardsImpl::LogicInputSig {
|
||||
@@ -364,18 +426,13 @@ private module LogicInput_v1 implements GuardsImpl::LogicInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
predicate parameterDefinition(Parameter p, SsaDefinition def) {
|
||||
def.(BaseSsaImplicitInit).isParameterDefinition(p)
|
||||
}
|
||||
|
||||
predicate additionalNullCheck = LogicInputCommon::additionalNullCheck/4;
|
||||
|
||||
predicate additionalImpliesStep(
|
||||
GuardsImpl::PreGuard g1, GuardValue v1, GuardsImpl::PreGuard g2, GuardValue v2
|
||||
) {
|
||||
exists(MethodCall check, int argIndex |
|
||||
g1 = check and
|
||||
v1.getDualValue().isThrowsException() and
|
||||
conditionCheckArgument(check, argIndex, v2.asBooleanValue()) and
|
||||
g2 = check.getArgument(argIndex)
|
||||
)
|
||||
}
|
||||
predicate additionalImpliesStep = LogicInputCommon::additionalImpliesStep/4;
|
||||
}
|
||||
|
||||
private module LogicInput_v2 implements GuardsImpl::LogicInputSig {
|
||||
@@ -400,15 +457,13 @@ private module LogicInput_v2 implements GuardsImpl::LogicInputSig {
|
||||
}
|
||||
}
|
||||
|
||||
predicate parameterDefinition(Parameter p, SsaDefinition def) {
|
||||
def.(SSA::SsaImplicitInit).isParameterDefinition(p)
|
||||
}
|
||||
|
||||
predicate additionalNullCheck = LogicInputCommon::additionalNullCheck/4;
|
||||
|
||||
predicate additionalImpliesStep(
|
||||
GuardsImpl::PreGuard g1, GuardValue v1, GuardsImpl::PreGuard g2, GuardValue v2
|
||||
) {
|
||||
LogicInput_v1::additionalImpliesStep(g1, v1, g2, v2)
|
||||
or
|
||||
CustomGuard::additionalImpliesStep(g1, v1, g2, v2)
|
||||
}
|
||||
predicate additionalImpliesStep = LogicInputCommon::additionalImpliesStep/4;
|
||||
}
|
||||
|
||||
private module LogicInput_v3 implements GuardsImpl::LogicInputSig {
|
||||
@@ -421,70 +476,11 @@ private module LogicInput_v3 implements GuardsImpl::LogicInputSig {
|
||||
|
||||
predicate additionalNullCheck = LogicInputCommon::additionalNullCheck/4;
|
||||
|
||||
predicate additionalImpliesStep = LogicInput_v2::additionalImpliesStep/4;
|
||||
}
|
||||
|
||||
private module CustomGuardInput implements Guards_v2::CustomGuardInputSig {
|
||||
private import semmle.code.java.dataflow.SSA
|
||||
|
||||
private int parameterPosition() { result in [-1, any(Parameter p).getPosition()] }
|
||||
|
||||
/** A parameter position represented by an integer. */
|
||||
class ParameterPosition extends int {
|
||||
ParameterPosition() { this = parameterPosition() }
|
||||
}
|
||||
|
||||
/** An argument position represented by an integer. */
|
||||
class ArgumentPosition extends int {
|
||||
ArgumentPosition() { this = parameterPosition() }
|
||||
}
|
||||
|
||||
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
|
||||
overlay[caller?]
|
||||
pragma[inline]
|
||||
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
|
||||
|
||||
final private class FinalMethod = Method;
|
||||
|
||||
class BooleanMethod extends FinalMethod {
|
||||
BooleanMethod() {
|
||||
super.getReturnType().(PrimitiveType).hasName("boolean") and
|
||||
not super.isOverridable()
|
||||
}
|
||||
|
||||
LogicInput_v2::SsaDefinition getParameter(ParameterPosition ppos) {
|
||||
exists(Parameter p |
|
||||
super.getParameter(ppos) = p and
|
||||
not p.isVarargs() and
|
||||
result.(SsaImplicitInit).isParameterDefinition(p)
|
||||
)
|
||||
}
|
||||
|
||||
GuardsInput::Expr getAReturnExpr() {
|
||||
exists(ReturnStmt ret |
|
||||
this = ret.getEnclosingCallable() and
|
||||
ret.getResult() = result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate booleanMethodCall(MethodCall call, BooleanMethod m) {
|
||||
call.getMethod().getSourceDeclaration() = m
|
||||
}
|
||||
|
||||
class BooleanMethodCall extends GuardsInput::Expr instanceof MethodCall {
|
||||
BooleanMethodCall() { booleanMethodCall(this, _) }
|
||||
|
||||
BooleanMethod getMethod() { booleanMethodCall(this, result) }
|
||||
|
||||
GuardsInput::Expr getArgument(ArgumentPosition apos) { result = super.getArgument(apos) }
|
||||
}
|
||||
predicate additionalImpliesStep = LogicInputCommon::additionalImpliesStep/4;
|
||||
}
|
||||
|
||||
class GuardValue = GuardsImpl::GuardValue;
|
||||
|
||||
private module CustomGuard = Guards_v2::CustomGuard<CustomGuardInput>;
|
||||
|
||||
/** INTERNAL: Don't use. */
|
||||
module Guards_v1 = GuardsImpl::Logic<LogicInput_v1>;
|
||||
|
||||
|
||||
@@ -348,6 +348,16 @@ predicate expectsContent(Node n, ContentSet c) {
|
||||
FlowSummaryImpl::Private::Steps::summaryExpectsContent(n.(FlowSummaryNode).getSummaryNode(), c)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate numericRepresentative(RefType t) {
|
||||
t.(BoxedType).getPrimitiveType().getName() = "double"
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate booleanRepresentative(RefType t) {
|
||||
t.(BoxedType).getPrimitiveType().getName() = "boolean"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a representative (boxed) type for `t` for the purpose of pruning
|
||||
* possible flow. A single type is used for all numeric types to account for
|
||||
@@ -356,10 +366,10 @@ predicate expectsContent(Node n, ContentSet c) {
|
||||
RefType getErasedRepr(Type t) {
|
||||
exists(Type e | e = t.getErasure() |
|
||||
if e instanceof NumericOrCharType
|
||||
then result.(BoxedType).getPrimitiveType().getName() = "double"
|
||||
then numericRepresentative(result)
|
||||
else
|
||||
if e instanceof BooleanType
|
||||
then result.(BoxedType).getPrimitiveType().getName() = "boolean"
|
||||
then booleanRepresentative(result)
|
||||
else result = e
|
||||
)
|
||||
or
|
||||
|
||||
@@ -563,9 +563,9 @@ private module Cached {
|
||||
cached // nothing is actually cached
|
||||
module BarrierGuard<guardChecksSig/3 guardChecks> {
|
||||
private predicate guardChecksAdjTypes(
|
||||
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, boolean branch
|
||||
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e, Guards::GuardValue val
|
||||
) {
|
||||
guardChecks(g, e, branch)
|
||||
guardChecks(g, e, val.asBooleanValue())
|
||||
}
|
||||
|
||||
private Node getABarrierNodeImpl() {
|
||||
@@ -657,16 +657,18 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
def instanceof SsaUncertainImplicitUpdate
|
||||
}
|
||||
|
||||
class GuardValue = Guards::GuardValue;
|
||||
|
||||
class Guard = Guards::Guard;
|
||||
|
||||
/** Holds if the guard `guard` directly controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, boolean branch) {
|
||||
guard.directlyControls(bb, branch)
|
||||
/** Holds if the guard `guard` directly controls block `bb` upon evaluating to `val`. */
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue val) {
|
||||
guard.directlyValueControls(bb, val)
|
||||
}
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardControlsBlock(Guard guard, BasicBlock bb, boolean branch) {
|
||||
guard.controls(bb, branch)
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `val`. */
|
||||
predicate guardControlsBlock(Guard guard, BasicBlock bb, GuardValue val) {
|
||||
guard.valueControls(bb, val)
|
||||
}
|
||||
|
||||
predicate includeWriteDefsInFlowStep() { none() }
|
||||
|
||||
@@ -214,24 +214,35 @@ private predicate relevantNode(ObjNode n) {
|
||||
exists(ObjNode mid | relevantNode(mid) and objStep(mid, n) and relevantNodeBack(n))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate objStepPruned(ObjNode n1, ObjNode n2) {
|
||||
objStep(n1, n2) and relevantNode(n1) and relevantNode(n2)
|
||||
private newtype TObjFlowNode =
|
||||
TObjNode(ObjNode n) { relevantNode(n) } or
|
||||
TObjType(RefType t) { source(t, _) }
|
||||
|
||||
private predicate objStepPruned(TObjFlowNode node1, TObjFlowNode node2) {
|
||||
exists(ObjNode n1, ObjNode n2 |
|
||||
node1 = TObjNode(n1) and
|
||||
node2 = TObjNode(n2) and
|
||||
objStep(n1, n2)
|
||||
)
|
||||
or
|
||||
exists(RefType t, ObjNode n |
|
||||
node1 = TObjType(t) and
|
||||
node2 = TObjNode(n) and
|
||||
source(t, n)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stepPlus(Node n1, Node n2) = fastTC(objStepPruned/2)(n1, n2)
|
||||
private predicate flowSrc(TObjFlowNode src) { src instanceof TObjType }
|
||||
|
||||
private predicate flowSink(TObjFlowNode sink) { exists(ObjNode n | sink = TObjNode(n) and sink(n)) }
|
||||
|
||||
private predicate stepPlus(TObjFlowNode n1, TObjFlowNode n2) =
|
||||
doublyBoundedFastTC(objStepPruned/2, flowSrc/1, flowSink/1)(n1, n2)
|
||||
|
||||
/**
|
||||
* Holds if the qualifier `n` of an `Object.toString()` call might have type `t`.
|
||||
*/
|
||||
pragma[noopt]
|
||||
private predicate objType(ObjNode n, RefType t) {
|
||||
exists(ObjNode n2 |
|
||||
sink(n) and
|
||||
(stepPlus(n2, n) or n2 = n) and
|
||||
source(t, n2)
|
||||
)
|
||||
}
|
||||
private predicate objType(ObjNode n, RefType t) { stepPlus(TObjType(t), TObjNode(n)) }
|
||||
|
||||
private VirtualMethodCall objectToString(ObjNode n) {
|
||||
result.getQualifier() = n.asExpr() and sink(n)
|
||||
|
||||
@@ -149,6 +149,8 @@ module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
|
||||
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
isSink(node) and exists(c)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,14 @@ module ArithmeticOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
any() // merged with ArithmeticUnderflow in ArithmeticTainted.ql
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArithExpr exp | result = exp.getLocation() | overflowSink(exp, sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,6 +37,14 @@ module ArithmeticUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
any() // merged with ArithmeticOverflow in ArithmeticTainted.ql
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArithExpr exp | result = exp.getLocation() | underflowSink(exp, sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,14 @@ module ArithmeticUncontrolledOverflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
any() // merged with ArithmeticUncontrolledUnderflow in ArithmeticUncontrolled.ql
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArithExpr exp | result = exp.getLocation() | overflowSink(exp, sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint-tracking flow to reason about overflow from arithmetic with uncontrolled values. */
|
||||
@@ -32,6 +40,14 @@ module ArithmeticUncontrolledUnderflowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
any() // merged with ArithmeticUncontrolledOverflow in ArithmeticUncontrolled.ql
|
||||
}
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArithExpr exp | result = exp.getLocation() | underflowSink(exp, sink.asExpr()))
|
||||
}
|
||||
}
|
||||
|
||||
/** Taint-tracking flow to reason about underflow from arithmetic with uncontrolled values. */
|
||||
|
||||
@@ -47,6 +47,15 @@ module ConditionalBypassFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
endsWithStep(node1, node2)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(MethodCall m, Expr e | result = [m, e].getLocation() |
|
||||
conditionControlsMethod(m, e) and
|
||||
sink.asExpr() = e
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -101,6 +101,10 @@ module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
any() // Simple use in UntrustedDataToExternalAPI.ql; also used through ExternalApiUsedWithUntrustedData in ExternalAPIsUsedWithUntrustedData.ql
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,15 @@ module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArrayCreationExpr arrayCreation, CheckableArrayAccess arrayAccess |
|
||||
result = [arrayCreation, arrayAccess.getIndexExpr()].getLocation() and
|
||||
arrayAccess.canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), arrayCreation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,15 @@ module ImproperValidationOfArrayConstructionConfig implements DataFlow::ConfigSi
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
any(CheckableArrayAccess caa).canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), _)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(ArrayCreationExpr arrayCreation, CheckableArrayAccess arrayAccess |
|
||||
result = [arrayCreation, arrayAccess.getIndexExpr()].getLocation() and
|
||||
arrayAccess.canThrowOutOfBoundsDueToEmptyArray(sink.asExpr(), arrayCreation)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,8 @@ module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
exists(CheckableArrayAccess arrayAccess | arrayAccess.canThrowOutOfBounds(sink.asExpr()))
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,8 @@ module ImproperValidationOfArrayIndexConfig implements DataFlow::ConfigSig {
|
||||
predicate isBarrier(DataFlow::Node node) { node.getType() instanceof BooleanType }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,6 +35,10 @@ module SecureCookieConfig implements DataFlow::ConfigSig {
|
||||
sink.asExpr() =
|
||||
any(MethodCall add | add.getMethod() instanceof ResponseAddCookieMethod).getArgument(0)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively in InsecureCookie.ql
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow to reason about the failure to use secure cookies. */
|
||||
|
||||
@@ -40,6 +40,10 @@ private module BasicAuthConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureLdapUrlSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // used as secondary flow to InsecureLdapUrlFlow in InsecureLdapAuth.ql
|
||||
}
|
||||
}
|
||||
|
||||
module BasicAuthFlow = DataFlow::Global<BasicAuthConfig>;
|
||||
@@ -56,6 +60,10 @@ private module RequiresSslConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof InsecureLdapUrlSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively in InsecureLdapAuth.ql
|
||||
}
|
||||
}
|
||||
|
||||
module RequiresSslFlow = DataFlow::Global<RequiresSslConfig>;
|
||||
|
||||
@@ -19,6 +19,10 @@ module LogInjectionConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // straightforward case; but the large test source is causing OOMs under `--check-diff-informed`.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,6 +77,12 @@ module InsecureCryptoConfig implements DataFlow::ConfigSig {
|
||||
objectToString(n.asExpr()) or
|
||||
n.getType().getErasure() instanceof TypeObject
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
exists(CryptoAlgoSpec c | result = c.getLocation() | sink.asExpr() = c.getAlgoSpec())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,6 +53,8 @@ module SensitiveLoggerConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
module SensitiveLoggerFlow = TaintTracking::Global<SensitiveLoggerConfig>;
|
||||
|
||||
@@ -24,6 +24,15 @@ module UncontrolledStringBuilderSourceFlowConfig implements DataFlow::ConfigSig
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof SimpleTypeSanitizer }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) {
|
||||
exists(Expr uncontrolled, StringBuilderVar sbv | result = uncontrolled.getLocation() |
|
||||
uncontrolledStringBuilderQuery(sbv, uncontrolled) and
|
||||
source = DataFlow::exprNode(sbv.getToStringCall())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,10 @@ module ExecTaintedEnvironmentConfig implements DataFlow::ConfigSig {
|
||||
ProcessBuilderEnvironmentFlow::flowToExpr(mm.getQualifier())
|
||||
)
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -145,6 +145,10 @@ module TempDirSystemGetPropertyToCreateConfig implements DataFlow::ConfigSig {
|
||||
or
|
||||
sanitizer instanceof WindowsOsSanitizer
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,6 +62,8 @@ module TrustBoundaryConfig implements DataFlow::ConfigSig {
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof TrustBoundaryViolationSink }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,10 @@ module SslEndpointIdentificationFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof SslConnectionCreation }
|
||||
|
||||
predicate isBarrier(DataFlow::Node sanitizer) { sanitizer instanceof SslUnsafeCertTrustSanitizer }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.6.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.6.1
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -18,6 +18,15 @@ import semmle.code.java.dataflow.SSA
|
||||
import semmle.code.java.dataflow.RangeUtils
|
||||
import semmle.code.java.dataflow.RangeAnalysis
|
||||
|
||||
pragma[nomagic]
|
||||
predicate ssaArrayLengthBound(SsaVariable arr, Bound b) {
|
||||
exists(FieldAccess len |
|
||||
len.getField() instanceof ArrayLengthField and
|
||||
len.getQualifier() = arr.getAUse() and
|
||||
b.getExpr() = len
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the index expression of `aa` is less than or equal to the array length plus `k`.
|
||||
*/
|
||||
@@ -27,12 +36,8 @@ predicate boundedArrayAccess(ArrayAccess aa, int k) {
|
||||
aa.getArray() = arr.getAUse() and
|
||||
bounded(index, b, delta, true, _)
|
||||
|
|
||||
exists(FieldAccess len |
|
||||
len.getField() instanceof ArrayLengthField and
|
||||
len.getQualifier() = arr.getAUse() and
|
||||
b.getExpr() = len and
|
||||
k = delta
|
||||
)
|
||||
ssaArrayLengthBound(arr, b) and
|
||||
k = delta
|
||||
or
|
||||
exists(ArrayCreationExpr arraycreation | arraycreation = getArrayDef(arr) |
|
||||
k = delta and
|
||||
|
||||
@@ -212,33 +212,35 @@ private LocalVariableDecl getCloseableVariable(CloseableInitExpr cie) {
|
||||
/**
|
||||
* A variable on which a "close" method is called, implicitly or explicitly, directly or indirectly.
|
||||
*/
|
||||
private predicate closeCalled(Variable v) {
|
||||
private predicate closeCalled(LocalScopeVariable v) {
|
||||
// `close()` is implicitly called on variables declared or referenced
|
||||
// in the resources clause of try-with-resource statements.
|
||||
exists(TryStmt try | try.getAResourceVariable() = v)
|
||||
or
|
||||
// Otherwise, there should be an explicit call to a method whose name contains "close".
|
||||
exists(MethodCall e |
|
||||
v = getCloseableVariable(_) or v instanceof Parameter or v instanceof LocalVariableDecl
|
||||
|
|
||||
e.getMethod().getName().toLowerCase().matches("%close%") and
|
||||
exists(VarAccess va | va = v.getAnAccess() |
|
||||
e.getQualifier() = va or
|
||||
e.getAnArgument() = va
|
||||
)
|
||||
or
|
||||
// The "close" call could happen indirectly inside a helper method of unknown name.
|
||||
exists(int i | e.getArgument(i) = v.getAnAccess() |
|
||||
exists(Parameter p, int j | p.getPosition() = j and p.getCallable() = e.getMethod() |
|
||||
closeCalled(p) and i = j
|
||||
or
|
||||
// The helper method could be iterating over a varargs parameter.
|
||||
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
|
||||
closeCalled(for.getVariable().getVariable())
|
||||
) and
|
||||
p.isVarargs() and
|
||||
j <= i
|
||||
)
|
||||
)
|
||||
or
|
||||
// The "close" call could happen indirectly inside a helper method of unknown name.
|
||||
exists(Parameter p |
|
||||
closeCalled(p) and p.getAnArgument() = v.getAnAccess() and p.getCallable() instanceof Method
|
||||
)
|
||||
or
|
||||
exists(MethodCall e, int i | e.getArgument(i) = v.getAnAccess() |
|
||||
exists(Parameter p, int j |
|
||||
p.getPosition() = j and p.getCallable() = e.getMethod().getSourceDeclaration()
|
||||
|
|
||||
// The helper method could be iterating over a varargs parameter.
|
||||
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
|
||||
closeCalled(for.getVariable().getVariable())
|
||||
) and
|
||||
p.isVarargs() and
|
||||
j <= i
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,14 +15,34 @@
|
||||
|
||||
import java
|
||||
|
||||
pragma[nomagic]
|
||||
predicate mayThrow(Stmt s, RefType rt) {
|
||||
s.(ThrowStmt).getExpr().getType() = rt
|
||||
or
|
||||
exists(Call call |
|
||||
call.getEnclosingStmt() = s and
|
||||
call.getCallee().getAnException().getType() = rt
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate caughtBy(TryStmt try, Stmt s, RefType rt) {
|
||||
mayThrow(s, rt) and
|
||||
s.getEnclosingStmt+() = try.getBlock() and
|
||||
caughtType(try, _).hasSubtype*(rt)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate nestedTry(TryStmt outer, TryStmt inner) { inner.getEnclosingStmt+() = outer.getBlock() }
|
||||
|
||||
/**
|
||||
* Exceptions of type `rt` thrown from within statement `s` are caught by an inner try block
|
||||
* and are therefore not propagated to the outer try block `t`.
|
||||
*/
|
||||
private predicate caughtInside(TryStmt t, Stmt s, RefType rt) {
|
||||
exists(TryStmt innerTry | innerTry.getEnclosingStmt+() = t.getBlock() |
|
||||
s.getEnclosingStmt+() = innerTry.getBlock() and
|
||||
caughtType(innerTry, _).hasSubtype*(rt)
|
||||
exists(TryStmt innerTry |
|
||||
nestedTry(t, innerTry) and
|
||||
caughtBy(innerTry, s, rt)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,10 @@ module WebViewDisallowContentAccessConfig implements DataFlow::StateConfigSig {
|
||||
state instanceof IsSettings and
|
||||
node instanceof WebSettingsDisallowContentAccessSink
|
||||
}
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() {
|
||||
none() // only used negatively
|
||||
}
|
||||
}
|
||||
|
||||
module WebViewDisallowContentAccessFlow =
|
||||
|
||||
@@ -64,8 +64,8 @@ Recommendations specific to particular frameworks supported by this query:
|
||||
<p></p>
|
||||
<p><b>SnakeYAML</b> - <code>org.yaml:snakeyaml</code></p>
|
||||
<ul>
|
||||
<li><b>Secure by Default</b>: No</li>
|
||||
<li><b>Recommendation</b>: Pass an instance of <code>org.yaml.snakeyaml.constructor.SafeConstructor</code> to <code>org.yaml.snakeyaml.Yaml</code>'s constructor before using it to deserialize untrusted data.</li>
|
||||
<li><b>Secure by Default</b>: As of version 2.0.</li>
|
||||
<li><b>Recommendation</b>: For versions before 2.0, pass an instance of <code>org.yaml.snakeyaml.constructor.SafeConstructor</code> to <code>org.yaml.snakeyaml.Yaml</code>'s constructor before using it to deserialize untrusted data.</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
<p><b>XML Decoder</b> - <code>Standard Java Library</code></p>
|
||||
@@ -121,7 +121,7 @@ Alvaro Muñoz & Christian Schneider, RSAConference 2016:
|
||||
</li>
|
||||
<li>
|
||||
SnakeYaml documentation on deserialization:
|
||||
<a href="https://bitbucket.org/snakeyaml/snakeyaml/wiki/Documentation#markdown-header-loading-yaml">SnakeYaml deserialization</a>.
|
||||
<a href="https://bitbucket.org/snakeyaml/snakeyaml/wiki/Documentation#markdown-header-loading-yaml">SnakeYaml deserialization</a> (not updated for new behaviour in version 2.0).
|
||||
</li>
|
||||
<li>
|
||||
Hessian deserialization and related gadget chains:
|
||||
|
||||
@@ -10,8 +10,6 @@ import java
|
||||
import semmle.code.java.Diagnostics
|
||||
import DatabaseQuality
|
||||
|
||||
extensible predicate extractorInformationSkipKey(string key);
|
||||
|
||||
predicate compilationInfo(string key, int value) {
|
||||
exists(Compilation c, string infoKey |
|
||||
key = infoKey + ": " + c.getInfo(infoKey) and
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/java-queries
|
||||
pack: codeql/java-all
|
||||
extensible: extractorInformationSkipKey
|
||||
data: []
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
## 7.3.3
|
||||
## 1.6.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.6.1
|
||||
lastReleaseVersion: 1.6.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/java-queries
|
||||
version: 1.6.2-dev
|
||||
version: 1.6.3-dev
|
||||
groups:
|
||||
- java
|
||||
- queries
|
||||
|
||||
@@ -208,6 +208,12 @@
|
||||
| Test.kt:101:5:103:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:101:5:103:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:102:9:102:25 | throw ... | Test.kt:101:33:103:5 | { ... } |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | ... -> ... |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | ... -> ... |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:105:5:109:5 | <Expr>; |
|
||||
| Test.kt:106:9:106:29 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
|
||||
| Test.kt:108:9:108:29 | <Expr>; | Test.kt:107:27:109:5 | { ... } |
|
||||
|
||||
@@ -169,7 +169,18 @@ def.kt:
|
||||
# 33| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 33| 1: [BlockStmt] { ... }
|
||||
# 34| 5: [Class] Y
|
||||
# 34| 2: [Constructor] Y
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Y>
|
||||
# 0| 0: [TypeAccess] Y
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Y
|
||||
#-----| 4: (Parameters)
|
||||
# 34| 0: [Parameter] value
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Y[]
|
||||
# 0| 0: [TypeAccess] Y
|
||||
# 34| 5: [Constructor] Y
|
||||
# 34| 5: [BlockStmt] { ... }
|
||||
# 34| 0: [ExprStmt] <Expr>;
|
||||
# 34| 0: [ClassInstanceExpr] new Enum<Y>(...)
|
||||
@@ -178,17 +189,6 @@ def.kt:
|
||||
# 34| 0: [NullLiteral] null
|
||||
# 34| 1: [IntegerLiteral] 0
|
||||
# 34| 1: [BlockStmt] { ... }
|
||||
# 34| 3: [Method] getEntries
|
||||
# 34| 3: [TypeAccess] EnumEntries<Y>
|
||||
# 34| 0: [TypeAccess] Y
|
||||
# 34| 4: [Method] valueOf
|
||||
# 34| 3: [TypeAccess] Y
|
||||
#-----| 4: (Parameters)
|
||||
# 34| 0: [Parameter] value
|
||||
# 34| 0: [TypeAccess] String
|
||||
# 34| 5: [Method] values
|
||||
# 34| 3: [TypeAccess] Y[]
|
||||
# 34| 0: [TypeAccess] Y
|
||||
# 35| 6: [FieldDeclaration] Y A;
|
||||
# 35| -1: [TypeAccess] Y
|
||||
# 35| 0: [ClassInstanceExpr] new Y(...)
|
||||
|
||||
@@ -160,7 +160,18 @@ classes.kt:
|
||||
# 42| -1: [TypeAccess] int
|
||||
# 42| 0: [IntegerLiteral] 3
|
||||
# 49| 11: [Class] Direction
|
||||
# 49| 2: [Constructor] Direction
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Direction>
|
||||
# 0| 0: [TypeAccess] Direction
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Direction
|
||||
#-----| 4: (Parameters)
|
||||
# 49| 0: [Parameter] value
|
||||
# 49| 0: [TypeAccess] String
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Direction[]
|
||||
# 0| 0: [TypeAccess] Direction
|
||||
# 49| 5: [Constructor] Direction
|
||||
# 49| 5: [BlockStmt] { ... }
|
||||
# 49| 0: [ExprStmt] <Expr>;
|
||||
# 49| 0: [ClassInstanceExpr] new Enum<Direction>(...)
|
||||
@@ -169,17 +180,6 @@ classes.kt:
|
||||
# 49| 0: [NullLiteral] null
|
||||
# 49| 1: [IntegerLiteral] 0
|
||||
# 49| 1: [BlockStmt] { ... }
|
||||
# 49| 3: [Method] getEntries
|
||||
# 49| 3: [TypeAccess] EnumEntries<Direction>
|
||||
# 49| 0: [TypeAccess] Direction
|
||||
# 49| 4: [Method] valueOf
|
||||
# 49| 3: [TypeAccess] Direction
|
||||
#-----| 4: (Parameters)
|
||||
# 49| 0: [Parameter] value
|
||||
# 49| 0: [TypeAccess] String
|
||||
# 49| 5: [Method] values
|
||||
# 49| 3: [TypeAccess] Direction[]
|
||||
# 49| 0: [TypeAccess] Direction
|
||||
# 50| 6: [FieldDeclaration] Direction NORTH;
|
||||
# 50| -1: [TypeAccess] Direction
|
||||
# 50| 0: [ClassInstanceExpr] new Direction(...)
|
||||
@@ -197,17 +197,17 @@ classes.kt:
|
||||
# 50| 0: [ClassInstanceExpr] new Direction(...)
|
||||
# 50| -3: [TypeAccess] Direction
|
||||
# 53| 12: [Class] Color
|
||||
# 53| 2: [Method] getEntries
|
||||
# 53| 3: [TypeAccess] EnumEntries<Color>
|
||||
# 53| 0: [TypeAccess] Color
|
||||
# 53| 3: [Method] valueOf
|
||||
# 53| 3: [TypeAccess] Color
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Color>
|
||||
# 0| 0: [TypeAccess] Color
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Color
|
||||
#-----| 4: (Parameters)
|
||||
# 53| 0: [Parameter] value
|
||||
# 53| 0: [TypeAccess] String
|
||||
# 53| 4: [Method] values
|
||||
# 53| 3: [TypeAccess] Color[]
|
||||
# 53| 0: [TypeAccess] Color
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Color[]
|
||||
# 0| 0: [TypeAccess] Color
|
||||
# 53| 5: [Constructor] Color
|
||||
#-----| 4: (Parameters)
|
||||
# 53| 0: [Parameter] rgb
|
||||
|
||||
@@ -208,6 +208,12 @@
|
||||
| Test.kt:101:9:103:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:101:9:103:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:102:9:102:25 | throw ... | Test.kt:101:33:103:5 | { ... } |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:105:5:109:5 | <Expr>; | Test.kt:101:9:103:5 | ... -> ... |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:100:25:110:1 | { ... } |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:5:103:5 | <Expr>; |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:101:9:103:5 | ... -> ... |
|
||||
| Test.kt:105:9:107:5 | ... -> ... | Test.kt:105:5:109:5 | <Expr>; |
|
||||
| Test.kt:106:9:106:29 | <Expr>; | Test.kt:105:20:107:5 | { ... } |
|
||||
| Test.kt:108:9:108:29 | <Expr>; | Test.kt:107:27:109:5 | { ... } |
|
||||
|
||||
@@ -3340,7 +3340,18 @@ exprs.kt:
|
||||
# 154| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 154| 1: [BlockStmt] { ... }
|
||||
# 174| 6: [Class] Direction
|
||||
# 174| 2: [Constructor] Direction
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Direction>
|
||||
# 0| 0: [TypeAccess] Direction
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Direction
|
||||
#-----| 4: (Parameters)
|
||||
# 174| 0: [Parameter] value
|
||||
# 174| 0: [TypeAccess] String
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Direction[]
|
||||
# 0| 0: [TypeAccess] Direction
|
||||
# 174| 5: [Constructor] Direction
|
||||
# 174| 5: [BlockStmt] { ... }
|
||||
# 174| 0: [ExprStmt] <Expr>;
|
||||
# 174| 0: [ClassInstanceExpr] new Enum<Direction>(...)
|
||||
@@ -3349,17 +3360,6 @@ exprs.kt:
|
||||
# 174| 0: [NullLiteral] null
|
||||
# 174| 1: [IntegerLiteral] 0
|
||||
# 174| 1: [BlockStmt] { ... }
|
||||
# 174| 3: [Method] getEntries
|
||||
# 174| 3: [TypeAccess] EnumEntries<Direction>
|
||||
# 174| 0: [TypeAccess] Direction
|
||||
# 174| 4: [Method] valueOf
|
||||
# 174| 3: [TypeAccess] Direction
|
||||
#-----| 4: (Parameters)
|
||||
# 174| 0: [Parameter] value
|
||||
# 174| 0: [TypeAccess] String
|
||||
# 174| 5: [Method] values
|
||||
# 174| 3: [TypeAccess] Direction[]
|
||||
# 174| 0: [TypeAccess] Direction
|
||||
# 175| 6: [FieldDeclaration] Direction NORTH;
|
||||
# 175| -1: [TypeAccess] Direction
|
||||
# 175| 0: [ClassInstanceExpr] new Direction(...)
|
||||
@@ -3377,17 +3377,17 @@ exprs.kt:
|
||||
# 175| 0: [ClassInstanceExpr] new Direction(...)
|
||||
# 175| -3: [TypeAccess] Direction
|
||||
# 178| 7: [Class] Color
|
||||
# 178| 2: [Method] getEntries
|
||||
# 178| 3: [TypeAccess] EnumEntries<Color>
|
||||
# 178| 0: [TypeAccess] Color
|
||||
# 178| 3: [Method] valueOf
|
||||
# 178| 3: [TypeAccess] Color
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Color>
|
||||
# 0| 0: [TypeAccess] Color
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Color
|
||||
#-----| 4: (Parameters)
|
||||
# 178| 0: [Parameter] value
|
||||
# 178| 0: [TypeAccess] String
|
||||
# 178| 4: [Method] values
|
||||
# 178| 3: [TypeAccess] Color[]
|
||||
# 178| 0: [TypeAccess] Color
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Color[]
|
||||
# 0| 0: [TypeAccess] Color
|
||||
# 178| 5: [Constructor] Color
|
||||
#-----| 4: (Parameters)
|
||||
# 178| 0: [Parameter] rgb
|
||||
|
||||
@@ -883,6 +883,16 @@
|
||||
| delegatedProperties.kt:87:34:87:46 | this | delegatedProperties.kt:87:34:87:46 | invoke | ThisAccess |
|
||||
| delegatedProperties.kt:87:34:87:46 | this | delegatedProperties.kt:87:34:87:46 | invoke | ThisAccess |
|
||||
| delegatedProperties.kt:87:34:87:46 | this | delegatedProperties.kt:87:34:87:46 | invoke | ThisAccess |
|
||||
| exprs.kt:0:0:0:0 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Color[] | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | Direction[] | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | EnumEntries<Color> | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:0:0:0:0 | EnumEntries<Direction> | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:4:1:142:1 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:4:20:4:25 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:4:28:4:33 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
@@ -1461,12 +1471,7 @@
|
||||
| exprs.kt:170:21:170:21 | 3 | exprs.kt:165:1:172:1 | foo | IntegerLiteral |
|
||||
| exprs.kt:174:1:176:1 | 0 | exprs.kt:174:1:176:1 | Direction | IntegerLiteral |
|
||||
| exprs.kt:174:1:176:1 | Direction | exprs.kt:174:1:176:1 | Direction | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | Direction[] | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | Enum<Direction> | exprs.kt:174:1:176:1 | Direction | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | EnumEntries<Direction> | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | String | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:174:1:176:1 | new Enum<Direction>(...) | exprs.kt:174:1:176:1 | Direction | ClassInstanceExpr |
|
||||
| exprs.kt:174:1:176:1 | null | exprs.kt:174:1:176:1 | Direction | NullLiteral |
|
||||
@@ -1494,11 +1499,6 @@
|
||||
| exprs.kt:175:25:175:28 | Direction | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:175:25:175:28 | Direction.EAST | exprs.kt:0:0:0:0 | <clinit> | VarAccess |
|
||||
| exprs.kt:175:25:175:28 | new Direction(...) | exprs.kt:0:0:0:0 | <clinit> | ClassInstanceExpr |
|
||||
| exprs.kt:178:1:182:1 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:1:182:1 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:1:182:1 | Color | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:1:182:1 | Color[] | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:1:182:1 | EnumEntries<Color> | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:1:182:1 | String | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| exprs.kt:178:17:178:30 | 0 | exprs.kt:178:17:178:30 | Color | IntegerLiteral |
|
||||
| exprs.kt:178:17:178:30 | Color | exprs.kt:178:17:178:30 | Color | TypeAccess |
|
||||
|
||||
@@ -73,7 +73,18 @@ A.kt:
|
||||
# 20| 2: [ReturnStmt] return ...
|
||||
# 20| 0: [IntegerLiteral] 5
|
||||
# 23| 11: [Class] Enu
|
||||
# 23| 2: [Constructor] Enu
|
||||
# 0| 2: [Method] getEntries
|
||||
# 0| 3: [TypeAccess] EnumEntries<Enu>
|
||||
# 0| 0: [TypeAccess] Enu
|
||||
# 0| 3: [Method] valueOf
|
||||
# 0| 3: [TypeAccess] Enu
|
||||
#-----| 4: (Parameters)
|
||||
# 23| 0: [Parameter] value
|
||||
# 23| 0: [TypeAccess] String
|
||||
# 0| 4: [Method] values
|
||||
# 0| 3: [TypeAccess] Enu[]
|
||||
# 0| 0: [TypeAccess] Enu
|
||||
# 23| 5: [Constructor] Enu
|
||||
# 23| 5: [BlockStmt] { ... }
|
||||
# 23| 0: [ExprStmt] <Expr>;
|
||||
# 23| 0: [ClassInstanceExpr] new Enum<Enu>(...)
|
||||
@@ -82,17 +93,6 @@ A.kt:
|
||||
# 23| 0: [NullLiteral] null
|
||||
# 23| 1: [IntegerLiteral] 0
|
||||
# 23| 1: [BlockStmt] { ... }
|
||||
# 23| 3: [Method] getEntries
|
||||
# 23| 3: [TypeAccess] EnumEntries<Enu>
|
||||
# 23| 0: [TypeAccess] Enu
|
||||
# 23| 4: [Method] valueOf
|
||||
# 23| 3: [TypeAccess] Enu
|
||||
#-----| 4: (Parameters)
|
||||
# 23| 0: [Parameter] value
|
||||
# 23| 0: [TypeAccess] String
|
||||
# 23| 5: [Method] values
|
||||
# 23| 3: [TypeAccess] Enu[]
|
||||
# 23| 0: [TypeAccess] Enu
|
||||
# 24| 6: [FieldDeclaration] Enu A;
|
||||
# 24| -1: [TypeAccess] Enu
|
||||
# 24| 0: [ClassInstanceExpr] new Enu(...)
|
||||
|
||||
@@ -223,11 +223,16 @@
|
||||
| delegates.kt:10:23:10:25 | old | VarAccess |
|
||||
| delegates.kt:10:26:10:31 | ", now " | StringLiteral |
|
||||
| delegates.kt:10:33:10:35 | new | VarAccess |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass[] | TypeAccess |
|
||||
| enumClass.kt:1:1:4:1 | EnumEntries<EnumClass> | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumClass | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumClass[] | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumEntries<EnumClass> | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumEntries<EnumWithFunctions> | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:0:0:0:0 | EnumWithFunctions[] | TypeAccess |
|
||||
| enumClass.kt:1:1:4:1 | String | TypeAccess |
|
||||
| enumClass.kt:1:21:1:32 | 0 | IntegerLiteral |
|
||||
| enumClass.kt:1:21:1:32 | Enum<EnumClass> | TypeAccess |
|
||||
@@ -258,12 +263,7 @@
|
||||
| enumClass.kt:3:11:3:11 | 1 | IntegerLiteral |
|
||||
| enumClass.kt:6:1:16:1 | 0 | IntegerLiteral |
|
||||
| enumClass.kt:6:1:16:1 | Enum<EnumWithFunctions> | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumEntries<EnumWithFunctions> | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions[] | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | String | TypeAccess |
|
||||
| enumClass.kt:6:1:16:1 | new Enum<EnumWithFunctions>(...) | ClassInstanceExpr |
|
||||
| enumClass.kt:6:1:16:1 | null | NullLiteral |
|
||||
|
||||
@@ -26,14 +26,14 @@ methods
|
||||
| delegates.kt:8:35:11:5 | new KMutableProperty1<MyClass,String>(...) { ... } | delegates.kt:8:35:11:5 | set | set(MyClass,java.lang.String) | override, public | |
|
||||
| delegates.kt:8:66:11:5 | new Function3<KProperty<?>,String,String,Unit>(...) { ... } | delegates.kt:8:66:11:5 | invoke | invoke(kotlin.reflect.KProperty,java.lang.String,java.lang.String) | final, override, public | |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:0:0:0:0 | <clinit> | <clinit>() | static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:1:1:4:1 | getEntries | getEntries() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:1:1:4:1 | valueOf | valueOf(java.lang.String) | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:1:1:4:1 | values | values() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:0:0:0:0 | getEntries | getEntries() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:0:0:0:0 | valueOf | valueOf(java.lang.String) | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:0:0:0:0 | values | values() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:1:22:1:31 | getV | getV() | final, public | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:0:0:0:0 | <clinit> | <clinit>() | static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | getEntries | getEntries() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | valueOf | valueOf(java.lang.String) | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | values | values() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:0:0:0:0 | getEntries | getEntries() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:0:0:0:0 | valueOf | valueOf(java.lang.String) | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:0:0:0:0 | values | values() | final, public, static | Compiler generated |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:13:3:13:29 | f | f(int) | abstract, public | |
|
||||
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:14:3:14:29 | g | g(int) | abstract, public | |
|
||||
| enumClass.kt:8:3:11:4 | VAL | enumClass.kt:9:5:9:30 | f | f(int) | override, public | |
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
| delegates.kt:8:66:11:5 | invoke | delegates.kt:9:9:9:12 | prop | 0 |
|
||||
| delegates.kt:8:66:11:5 | invoke | delegates.kt:9:15:9:17 | old | 1 |
|
||||
| delegates.kt:8:66:11:5 | invoke | delegates.kt:9:20:9:22 | new | 2 |
|
||||
| enumClass.kt:1:1:4:1 | valueOf | enumClass.kt:1:1:4:1 | value | 0 |
|
||||
| enumClass.kt:6:1:16:1 | valueOf | enumClass.kt:6:1:16:1 | value | 0 |
|
||||
| enumClass.kt:0:0:0:0 | valueOf | enumClass.kt:1:1:4:1 | value | 0 |
|
||||
| enumClass.kt:0:0:0:0 | valueOf | enumClass.kt:6:1:16:1 | value | 0 |
|
||||
| enumClass.kt:9:5:9:30 | f | enumClass.kt:9:20:9:25 | i | 0 |
|
||||
| enumClass.kt:10:5:10:42 | g | enumClass.kt:10:20:10:25 | i | 0 |
|
||||
| enumClass.kt:13:3:13:29 | f | enumClass.kt:13:18:13:23 | i | 0 |
|
||||
|
||||
@@ -143,4 +143,73 @@ public class Guards {
|
||||
chk(); // $ guarded=found:true guarded='i < a.length:false'
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean testNotNull1(String input) {
|
||||
return input != null && input.length() > 0;
|
||||
}
|
||||
|
||||
public static boolean testNotNull2(String input) {
|
||||
if (input == null) return false;
|
||||
return input.length() > 0;
|
||||
}
|
||||
|
||||
public static int getNumOrDefault(Integer number) {
|
||||
return number == null ? 0 : number;
|
||||
}
|
||||
|
||||
public static String concatNonNull(String s1, String s2) {
|
||||
if (s1 == null || s2 == null) return null;
|
||||
return s1 + s2;
|
||||
}
|
||||
|
||||
public static Status testEnumWrapper(boolean flag) {
|
||||
return flag ? Status.SUCCESS : Status.FAILURE;
|
||||
}
|
||||
|
||||
enum Status { SUCCESS, FAILURE }
|
||||
|
||||
void testWrappers(String s, Integer i) {
|
||||
if (testNotNull1(s)) {
|
||||
chk(); // $ guarded='s:not null' guarded=testNotNull1(...):true
|
||||
} else {
|
||||
chk(); // $ guarded=testNotNull1(...):false
|
||||
}
|
||||
|
||||
if (testNotNull2(s)) {
|
||||
chk(); // $ guarded='s:not null' guarded=testNotNull2(...):true
|
||||
} else {
|
||||
chk(); // $ guarded=testNotNull2(...):false
|
||||
}
|
||||
|
||||
if (0 == getNumOrDefault(i)) {
|
||||
chk(); // $ guarded='0 == getNumOrDefault(...):true' guarded='getNumOrDefault(...):0'
|
||||
} else {
|
||||
chk(); // $ guarded='0 == getNumOrDefault(...):false' guarded='getNumOrDefault(...):not 0' guarded='i:not 0' guarded='i:not null'
|
||||
}
|
||||
|
||||
if (null == concatNonNull(s, "suffix")) {
|
||||
chk(); // $ guarded='concatNonNull(...):null' guarded='null == concatNonNull(...):true'
|
||||
} else {
|
||||
chk(); // $ guarded='concatNonNull(...):not null' guarded='null == concatNonNull(...):false' guarded='s:not null'
|
||||
}
|
||||
|
||||
switch (testEnumWrapper(g(1))) {
|
||||
case SUCCESS:
|
||||
chk(); // $ guarded='testEnumWrapper(...):SUCCESS' guarded='testEnumWrapper(...):match SUCCESS' guarded=g(1):true
|
||||
break;
|
||||
case FAILURE:
|
||||
chk(); // $ guarded='testEnumWrapper(...):FAILURE' guarded='testEnumWrapper(...):match FAILURE' guarded=g(1):false
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ensureNotNull(Object o) throws Exception {
|
||||
if (o == null) throw new Exception();
|
||||
}
|
||||
|
||||
void testExceptionWrapper(String s) throws Exception {
|
||||
chk(); // nothing guards here
|
||||
ensureNotNull(s);
|
||||
chk(); // $ guarded='ensureNotNull(...):no exception' guarded='s:not null'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,3 +89,28 @@
|
||||
| Guards.java:139:9:139:13 | chk(...) | found:true |
|
||||
| Guards.java:143:7:143:11 | chk(...) | 'i < a.length:false' |
|
||||
| Guards.java:143:7:143:11 | chk(...) | found:true |
|
||||
| Guards.java:173:7:173:11 | chk(...) | 's:not null' |
|
||||
| Guards.java:173:7:173:11 | chk(...) | testNotNull1(...):true |
|
||||
| Guards.java:175:7:175:11 | chk(...) | testNotNull1(...):false |
|
||||
| Guards.java:179:7:179:11 | chk(...) | 's:not null' |
|
||||
| Guards.java:179:7:179:11 | chk(...) | testNotNull2(...):true |
|
||||
| Guards.java:181:7:181:11 | chk(...) | testNotNull2(...):false |
|
||||
| Guards.java:185:7:185:11 | chk(...) | '0 == getNumOrDefault(...):true' |
|
||||
| Guards.java:185:7:185:11 | chk(...) | 'getNumOrDefault(...):0' |
|
||||
| Guards.java:187:7:187:11 | chk(...) | '0 == getNumOrDefault(...):false' |
|
||||
| Guards.java:187:7:187:11 | chk(...) | 'getNumOrDefault(...):not 0' |
|
||||
| Guards.java:187:7:187:11 | chk(...) | 'i:not 0' |
|
||||
| Guards.java:187:7:187:11 | chk(...) | 'i:not null' |
|
||||
| Guards.java:191:7:191:11 | chk(...) | 'concatNonNull(...):null' |
|
||||
| Guards.java:191:7:191:11 | chk(...) | 'null == concatNonNull(...):true' |
|
||||
| Guards.java:193:7:193:11 | chk(...) | 'concatNonNull(...):not null' |
|
||||
| Guards.java:193:7:193:11 | chk(...) | 'null == concatNonNull(...):false' |
|
||||
| Guards.java:193:7:193:11 | chk(...) | 's:not null' |
|
||||
| Guards.java:198:9:198:13 | chk(...) | 'testEnumWrapper(...):SUCCESS' |
|
||||
| Guards.java:198:9:198:13 | chk(...) | 'testEnumWrapper(...):match SUCCESS' |
|
||||
| Guards.java:198:9:198:13 | chk(...) | g(1):true |
|
||||
| Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):FAILURE' |
|
||||
| Guards.java:201:9:201:13 | chk(...) | 'testEnumWrapper(...):match FAILURE' |
|
||||
| Guards.java:201:9:201:13 | chk(...) | g(1):false |
|
||||
| Guards.java:213:5:213:9 | chk(...) | 'ensureNotNull(...):no exception' |
|
||||
| Guards.java:213:5:213:9 | chk(...) | 's:not null' |
|
||||
|
||||
@@ -408,4 +408,32 @@ public class B {
|
||||
x.hashCode(); // NPE
|
||||
}
|
||||
}
|
||||
|
||||
public void corrCondLoop1(boolean a[]) {
|
||||
Object x = new Object();
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
boolean b = a[i];
|
||||
if (b) {
|
||||
x = null;
|
||||
}
|
||||
if (!b) {
|
||||
x.hashCode(); // NPE - false negative
|
||||
}
|
||||
// flow can loop around from one iteration to the next
|
||||
}
|
||||
}
|
||||
|
||||
public void corrCondLoop2(boolean a[]) {
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
// x is local to the loop iteration and thus cannot loop around and reach the sink
|
||||
Object x = new Object();
|
||||
boolean b = a[i];
|
||||
if (b) {
|
||||
x = null;
|
||||
}
|
||||
if (!b) {
|
||||
x.hashCode(); // OK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ public class C {
|
||||
obj = new Object();
|
||||
} else if (a[i] == 2) {
|
||||
verifyNotNull(obj);
|
||||
obj.hashCode(); // NPE - false positive
|
||||
obj.hashCode(); // OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
| C.java:137:7:137:10 | obj2 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:131:5:131:23 | Object obj2 | obj2 | C.java:132:9:132:20 | ... != ... | this |
|
||||
| C.java:144:15:144:15 | a | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:141:20:141:26 | a | a | C.java:142:13:142:21 | ... == ... | this |
|
||||
| C.java:188:9:188:11 | obj | Variable $@ may be null at this access because of $@ assignment. | C.java:181:5:181:22 | Object obj | obj | C.java:181:12:181:21 | obj | this |
|
||||
| C.java:207:9:207:11 | obj | Variable $@ may be null at this access because of $@ assignment. | C.java:201:5:201:22 | Object obj | obj | C.java:201:12:201:21 | obj | this |
|
||||
| C.java:219:9:219:10 | o1 | Variable $@ may be null at this access as suggested by $@ null guard. | C.java:212:20:212:28 | o1 | o1 | C.java:213:9:213:18 | ... == ... | this |
|
||||
| C.java:233:7:233:8 | xs | Variable $@ may be null at this access because of $@ assignment. | C.java:231:5:231:56 | int[] xs | xs | C.java:231:11:231:55 | xs | this |
|
||||
| F.java:11:5:11:7 | obj | Variable $@ may be null at this access as suggested by $@ null guard. | F.java:8:18:8:27 | obj | obj | F.java:9:9:9:19 | ... == ... | this |
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ExternalAPISinkExample extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
// BAD: a request parameter is written directly to an error response page
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND,
|
||||
"The page \"" + request.getParameter("page") + "\" was not found."); // $ Alert
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ExternalAPITaintStepExample extends HttpServlet {
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
StringBuilder sqlQueryBuilder = new StringBuilder();
|
||||
sqlQueryBuilder.append("SELECT * FROM user WHERE user_id='");
|
||||
// BAD: a request parameter is concatenated directly into a SQL query
|
||||
sqlQueryBuilder.append(request.getParameter("user_id"));
|
||||
sqlQueryBuilder.append("'");
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
| javax.servlet.http.HttpServletResponse.sendError(int,java.lang.String) [param 1] | 1 | 1 |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-020/ExternalAPIsUsedWithUntrustedData.ql
|
||||
@@ -0,0 +1,11 @@
|
||||
#select
|
||||
| ExternalAPISinkExample.java:12:5:12:70 | ... + ... | ExternalAPISinkExample.java:12:21:12:48 | getParameter(...) : String | ExternalAPISinkExample.java:12:5:12:70 | ... + ... | Call to javax.servlet.http.HttpServletResponse.sendError with untrusted data from $@. | ExternalAPISinkExample.java:12:21:12:48 | getParameter(...) : String | getParameter(...) : String |
|
||||
edges
|
||||
| ExternalAPISinkExample.java:12:21:12:48 | getParameter(...) : String | ExternalAPISinkExample.java:12:5:12:70 | ... + ... | provenance | Src:MaD:2 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: javax.servlet.http; HttpServletResponse; false; sendError; (int,String); ; Argument[1]; information-leak; manual |
|
||||
| 2 | Source: javax.servlet; ServletRequest; false; getParameter; (String); ; ReturnValue; remote; manual |
|
||||
nodes
|
||||
| ExternalAPISinkExample.java:12:5:12:70 | ... + ... | semmle.label | ... + ... |
|
||||
| ExternalAPISinkExample.java:12:21:12:48 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
subpaths
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,4 +3,4 @@ extensions:
|
||||
pack: codeql/java-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["loginjection", "LogInjectionTest", False, "source", "()", "", "ReturnValue", "remote", "manual"]
|
||||
- ["loginjection", "LogInjectionTest", False, "source", "()", "", "ReturnValue", "remote", "manual"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.security.LogInjectionQuery
|
||||
import utils.test.InlineFlowTest
|
||||
import TaintFlowTest<LogInjectionConfig>
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-117/LogInjection.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,13 @@
|
||||
| UnsafeCertTrustTest.java:24:3:24:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:25:3:25:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:26:3:26:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:35:3:35:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:36:3:36:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:37:3:37:11 | sslEngine | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:64:3:64:8 | socket | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:74:3:74:8 | socket | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:84:3:84:8 | socket | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:91:3:91:8 | socket | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:141:3:141:8 | socket | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:153:4:153:60 | useSslProtocol(...) | Unsafe configuration of trusted certificates. |
|
||||
| UnsafeCertTrustTest.java:157:4:157:70 | setSslContextFactory(...) | Unsafe configuration of trusted certificates. |
|
||||
|
||||
@@ -21,9 +21,9 @@ public class UnsafeCertTrustTest {
|
||||
SSLParameters sslParameters = sslEngine.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm(null);
|
||||
sslEngine.setSSLParameters(sslParameters);
|
||||
sslEngine.beginHandshake(); // $hasUnsafeCertTrust
|
||||
sslEngine.wrap(new ByteBuffer[] {}, null); // $hasUnsafeCertTrust
|
||||
sslEngine.unwrap(null, null, 0, 0); // $hasUnsafeCertTrust
|
||||
sslEngine.beginHandshake(); // $ Alert
|
||||
sslEngine.wrap(new ByteBuffer[] {}, null); // $ Alert
|
||||
sslEngine.unwrap(null, null, 0, 0); // $ Alert
|
||||
}
|
||||
|
||||
public void testSSLEngineEndpointIdSetEmpty() throws Exception {
|
||||
@@ -32,9 +32,9 @@ public class UnsafeCertTrustTest {
|
||||
SSLParameters sslParameters = sslEngine.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm("");
|
||||
sslEngine.setSSLParameters(sslParameters);
|
||||
sslEngine.beginHandshake(); // $hasUnsafeCertTrust
|
||||
sslEngine.wrap(new ByteBuffer[] {}, null); // $hasUnsafeCertTrust
|
||||
sslEngine.unwrap(null, null, 0, 0); // $hasUnsafeCertTrust
|
||||
sslEngine.beginHandshake(); // $ Alert
|
||||
sslEngine.wrap(new ByteBuffer[] {}, null); // $ Alert
|
||||
sslEngine.unwrap(null, null, 0, 0); // $ Alert
|
||||
}
|
||||
|
||||
public void testSSLEngineEndpointIdSafe() throws Exception {
|
||||
@@ -61,7 +61,7 @@ public class UnsafeCertTrustTest {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
|
||||
SSLSocket socket = (SSLSocket) socketFactory.createSocket();
|
||||
socket.getOutputStream(); // $hasUnsafeCertTrust
|
||||
socket.getOutputStream(); // $ Alert
|
||||
}
|
||||
|
||||
public void testSSLSocketEndpointIdSetNull() throws Exception {
|
||||
@@ -71,7 +71,7 @@ public class UnsafeCertTrustTest {
|
||||
SSLParameters sslParameters = socket.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm(null);
|
||||
socket.setSSLParameters(sslParameters);
|
||||
socket.getOutputStream(); // $hasUnsafeCertTrust
|
||||
socket.getOutputStream(); // $ Alert
|
||||
}
|
||||
|
||||
public void testSSLSocketEndpointIdSetEmpty() throws Exception {
|
||||
@@ -81,14 +81,14 @@ public class UnsafeCertTrustTest {
|
||||
SSLParameters sslParameters = socket.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm("");
|
||||
socket.setSSLParameters(sslParameters);
|
||||
socket.getOutputStream(); // $hasUnsafeCertTrust
|
||||
socket.getOutputStream(); // $ Alert
|
||||
}
|
||||
|
||||
public void testSSLSocketEndpointIdAfterConnecting() throws Exception {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
|
||||
SSLSocket socket = (SSLSocket) socketFactory.createSocket();
|
||||
socket.getOutputStream(); // $hasUnsafeCertTrust
|
||||
socket.getOutputStream(); // $ Alert
|
||||
SSLParameters sslParameters = socket.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
socket.setSSLParameters(sslParameters);
|
||||
@@ -138,7 +138,7 @@ public class UnsafeCertTrustTest {
|
||||
SSLParameters sslParameters = sslSocket.getSSLParameters();
|
||||
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
sslSocket.setSSLParameters(sslParameters);
|
||||
socket.getOutputStream(); // $ SPURIOUS: hasUnsafeCertTrust
|
||||
socket.getOutputStream(); // $ SPURIOUS: Alert
|
||||
}
|
||||
|
||||
public void testSocketEndpointIdNotSet() throws Exception {
|
||||
@@ -150,11 +150,11 @@ public class UnsafeCertTrustTest {
|
||||
public void testRabbitMQFactoryEnableHostnameVerificationNotSet() throws Exception {
|
||||
{
|
||||
ConnectionFactory connectionFactory = new ConnectionFactory();
|
||||
connectionFactory.useSslProtocol(SSLContext.getDefault()); // $hasUnsafeCertTrust
|
||||
connectionFactory.useSslProtocol(SSLContext.getDefault()); // $ Alert
|
||||
}
|
||||
{
|
||||
ConnectionFactory connectionFactory = new ConnectionFactory();
|
||||
connectionFactory.setSslContextFactory(new TestSslContextFactory()); // $hasUnsafeCertTrust
|
||||
connectionFactory.setSslContextFactory(new TestSslContextFactory()); // $ Alert
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.security.UnsafeCertTrustQuery
|
||||
import utils.test.InlineExpectationsTest
|
||||
|
||||
module UnsafeCertTrustTest implements TestSig {
|
||||
string getARelevantTag() { result = "hasUnsafeCertTrust" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasUnsafeCertTrust" and
|
||||
exists(Expr unsafeTrust |
|
||||
unsafeTrust instanceof RabbitMQEnableHostnameVerificationNotSet
|
||||
or
|
||||
SslEndpointIdentificationFlow::flowTo(DataFlow::exprNode(unsafeTrust))
|
||||
|
|
||||
unsafeTrust.getLocation() = location and
|
||||
element = unsafeTrust.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<UnsafeCertTrustTest>
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-273/UnsafeCertTrust.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,11 @@
|
||||
#select
|
||||
| TrustBoundaryViolations.java:14:52:14:56 | input | TrustBoundaryViolations.java:11:24:11:52 | getParameter(...) : String | TrustBoundaryViolations.java:14:52:14:56 | input | This servlet reads data from a $@ and writes it to a session variable. | TrustBoundaryViolations.java:11:24:11:52 | getParameter(...) : String | remote source |
|
||||
edges
|
||||
| TrustBoundaryViolations.java:11:24:11:52 | getParameter(...) : String | TrustBoundaryViolations.java:14:52:14:56 | input | provenance | Src:MaD:2 Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: javax.servlet.http; HttpSession; true; setAttribute; ; ; Argument[0..1]; trust-boundary-violation; manual |
|
||||
| 2 | Source: javax.servlet; ServletRequest; false; getParameter; (String); ; ReturnValue; remote; manual |
|
||||
nodes
|
||||
| TrustBoundaryViolations.java:11:24:11:52 | getParameter(...) : String | semmle.label | getParameter(...) : String |
|
||||
| TrustBoundaryViolations.java:14:52:14:56 | input | semmle.label | input |
|
||||
subpaths
|
||||
|
||||
@@ -8,10 +8,10 @@ public class TrustBoundaryViolations extends HttpServlet {
|
||||
Validator validator;
|
||||
|
||||
public void doGet(HttpServletRequest request, HttpServletResponse response) {
|
||||
String input = request.getParameter("input");
|
||||
String input = request.getParameter("input"); // $ Source
|
||||
|
||||
// BAD: The input is written to the session without being sanitized.
|
||||
request.getSession().setAttribute("input", input); // $ hasTaintFlow
|
||||
request.getSession().setAttribute("input", input); // $ Alert
|
||||
|
||||
String input2 = request.getParameter("input2");
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import java
|
||||
import semmle.code.java.security.TrustBoundaryViolationQuery
|
||||
import utils.test.InlineFlowTest
|
||||
import TaintFlowTest<TrustBoundaryConfig>
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-501/TrustBoundaryViolation.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -0,0 +1,15 @@
|
||||
#select
|
||||
| Test.java:7:21:7:53 | ... + ... | Test.java:7:46:7:53 | password : String | Test.java:7:21:7:53 | ... + ... | This $@ is written to a log file. | Test.java:7:46:7:53 | password | potentially sensitive information |
|
||||
| Test.java:8:22:8:52 | ... + ... | Test.java:8:44:8:52 | authToken : String | Test.java:8:22:8:52 | ... + ... | This $@ is written to a log file. | Test.java:8:44:8:52 | authToken | potentially sensitive information |
|
||||
edges
|
||||
| Test.java:7:46:7:53 | password : String | Test.java:7:21:7:53 | ... + ... | provenance | Sink:MaD:2 |
|
||||
| Test.java:8:44:8:52 | authToken : String | Test.java:8:22:8:52 | ... + ... | provenance | Sink:MaD:1 |
|
||||
models
|
||||
| 1 | Sink: org.apache.logging.log4j; Logger; true; error; (String); ; Argument[0]; log-injection; manual |
|
||||
| 2 | Sink: org.apache.logging.log4j; Logger; true; info; (String); ; Argument[0]; log-injection; manual |
|
||||
nodes
|
||||
| Test.java:7:21:7:53 | ... + ... | semmle.label | ... + ... |
|
||||
| Test.java:7:46:7:53 | password : String | semmle.label | password : String |
|
||||
| Test.java:8:22:8:52 | ... + ... | semmle.label | ... + ... |
|
||||
| Test.java:8:44:8:52 | authToken : String | semmle.label | authToken : String |
|
||||
subpaths
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import java
|
||||
import utils.test.InlineFlowTest
|
||||
import semmle.code.java.security.SensitiveLoggingQuery
|
||||
import TaintFlowTest<SensitiveLoggerConfig>
|
||||
@@ -0,0 +1,4 @@
|
||||
query: Security/CWE/CWE-532/SensitiveInfoLog.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user