Merge branch 'main' into redsun82/just2

This commit is contained in:
Paolo Tranquilli
2025-08-11 14:06:16 +02:00
479 changed files with 23475 additions and 7452 deletions

View File

@@ -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

Binary file not shown.

Binary file not shown.

BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.2.20-Beta2.jar (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -27,7 +27,7 @@ import shutil
import io
import os
DEFAULT_VERSION = "2.1.20"
DEFAULT_VERSION = "2.2.0"
def options():

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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):

View File

@@ -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()

View File

@@ -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()

View 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)})

View 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)})

View File

@@ -1,5 +1,5 @@
{
"markdownMessage": "The Kotlin version installed (`999.999.999`) is too recent for this version of CodeQL. Install a version lower than 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",

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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`.

View File

@@ -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.

View File

@@ -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.

View 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`.

View 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`.

View File

@@ -0,0 +1,5 @@
## 7.5.0
### New Features
* Kotlin versions up to 2.2.2\ *x* are now supported.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 7.3.3
lastReleaseVersion: 7.5.0

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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

View File

@@ -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() }

View File

@@ -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)

View File

@@ -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() }
}
/**

View File

@@ -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()))
}
}
/**

View File

@@ -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. */

View File

@@ -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
)
}
}
/**

View File

@@ -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
}
}
/**

View File

@@ -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)
)
}
}
/**

View File

@@ -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)
)
}
}
/**

View File

@@ -14,6 +14,8 @@ module BoundedFlowSourceConfig implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) {
exists(CheckableArrayAccess arrayAccess | arrayAccess.canThrowOutOfBounds(sink.asExpr()))
}
predicate observeDiffInformedIncrementalMode() { any() }
}
/**

View File

@@ -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() }
}
/**

View File

@@ -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. */

View File

@@ -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>;

View File

@@ -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`.
}
}
/**

View File

@@ -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())
}
}
/**

View File

@@ -53,6 +53,8 @@ module SensitiveLoggerConfig implements DataFlow::ConfigSig {
}
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
predicate observeDiffInformedIncrementalMode() { any() }
}
module SensitiveLoggerFlow = TaintTracking::Global<SensitiveLoggerConfig>;

View File

@@ -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())
)
}
}
/**

View File

@@ -38,6 +38,10 @@ module ExecTaintedEnvironmentConfig implements DataFlow::ConfigSig {
ProcessBuilderEnvironmentFlow::flowToExpr(mm.getQualifier())
)
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSourceLocation(DataFlow::Node source) { none() }
}
/**

View File

@@ -145,6 +145,10 @@ module TempDirSystemGetPropertyToCreateConfig implements DataFlow::ConfigSig {
or
sanitizer instanceof WindowsOsSanitizer
}
predicate observeDiffInformedIncrementalMode() { any() }
Location getASelectedSinkLocation(DataFlow::Node sink) { none() }
}
/**

View File

@@ -62,6 +62,8 @@ module TrustBoundaryConfig implements DataFlow::ConfigSig {
}
predicate isSink(DataFlow::Node sink) { sink instanceof TrustBoundaryViolationSink }
predicate observeDiffInformedIncrementalMode() { any() }
}
/**

View File

@@ -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() }
}
/**

View File

@@ -1,3 +1,7 @@
## 1.6.2
No user-facing changes.
## 1.6.1
### Minor Analysis Improvements

View File

@@ -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

View File

@@ -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
)
)
}

View File

@@ -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)
)
}

View File

@@ -97,6 +97,10 @@ module WebViewDisallowContentAccessConfig implements DataFlow::StateConfigSig {
state instanceof IsSettings and
node instanceof WebSettingsDisallowContentAccessSink
}
predicate observeDiffInformedIncrementalMode() {
none() // only used negatively
}
}
module WebViewDisallowContentAccessFlow =

View File

@@ -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 &amp; 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:

View File

@@ -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

View File

@@ -1,5 +1,5 @@
extensions:
- addsTo:
pack: codeql/java-queries
pack: codeql/java-all
extensible: extractorInformationSkipKey
data: []

View File

@@ -1,3 +1,3 @@
## 7.3.3
## 1.6.2
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.6.1
lastReleaseVersion: 1.6.2

View File

@@ -1,5 +1,5 @@
name: codeql/java-queries
version: 1.6.2-dev
version: 1.6.3-dev
groups:
- java
- queries

View File

@@ -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 | { ... } |

View File

@@ -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(...)

View File

@@ -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

View File

@@ -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 | { ... } |

View File

@@ -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

View File

@@ -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 |

View File

@@ -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(...)

View File

@@ -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 |

View File

@@ -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 | |

View File

@@ -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 |

View File

@@ -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'
}
}

View File

@@ -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' |

View File

@@ -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
}
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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 |

View File

@@ -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
}
}

View File

@@ -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("'");
// ...
}
}

View File

@@ -0,0 +1 @@
| javax.servlet.http.HttpServletResponse.sendError(int,java.lang.String) [param 1] | 1 | 1 |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-020/ExternalAPIsUsedWithUntrustedData.ql

View File

@@ -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

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-020/UntrustedDataToExternalAPI.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -1,4 +0,0 @@
import java
import semmle.code.java.security.LogInjectionQuery
import utils.test.InlineFlowTest
import TaintFlowTest<LogInjectionConfig>

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-117/LogInjection.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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. |

View File

@@ -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
}
}

View File

@@ -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>

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-273/UnsafeCertTrust.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -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");

View File

@@ -1,4 +0,0 @@
import java
import semmle.code.java.security.TrustBoundaryViolationQuery
import utils.test.InlineFlowTest
import TaintFlowTest<TrustBoundaryConfig>

View File

@@ -0,0 +1,4 @@
query: Security/CWE/CWE-501/TrustBoundaryViolation.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -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

View File

@@ -1,4 +0,0 @@
import java
import utils.test.InlineFlowTest
import semmle.code.java.security.SensitiveLoggingQuery
import TaintFlowTest<SensitiveLoggerConfig>

View File

@@ -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