Merge branch 'github:main' into couchdb

This commit is contained in:
Mauro Baluda
2025-12-22 20:25:41 +01:00
committed by GitHub
913 changed files with 33914 additions and 15179 deletions

View File

@@ -1,3 +1,7 @@
## 7.8.2
No user-facing changes.
## 7.8.1
No user-facing changes.

View File

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

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 7.8.1
lastReleaseVersion: 7.8.2

View File

@@ -13,6 +13,14 @@ extensions:
pack: codeql/java-all
extensible: summaryModel
data: []
- addsTo:
pack: codeql/java-all
extensible: barrierModel
data: []
- addsTo:
pack: codeql/java-all
extensible: barrierGuardModel
data: []
- addsTo:
pack: codeql/java-all
extensible: neutralModel

View File

@@ -50,6 +50,12 @@ extensions:
- ["hudson", "FilePath", False, "readToString", "", "", "ReturnValue", "file", "manual"]
- ["hudson", "Plugin", True, "configure", "", "", "Parameter", "remote", "manual"]
- ["hudson", "Plugin", True, "newInstance", "", "", "Parameter", "remote", "manual"]
- addsTo:
pack: codeql/java-all
extensible: barrierModel
data:
- ["hudson", "Util", True, "escape", "(String)", "", "ReturnValue", "html-injection", "manual"]
# Not including xmlEscape because it only accounts for >, <, and &. It does not account for ", or ', which makes it an incomplete XSS sanitizer.
- addsTo:
pack: codeql/java-all
extensible: summaryModel

View File

@@ -162,3 +162,8 @@ extensions:
extensible: sourceModel
data:
- ["java.io", "FileInputStream", True, "FileInputStream", "", "", "Argument[this]", "file", "manual"]
- addsTo:
pack: codeql/java-all
extensible: barrierModel
data:
- ["java.io", "File", True, "getName", "()", "", "ReturnValue", "path-injection", "manual"]

View File

@@ -34,6 +34,11 @@ extensions:
- ["java.net", "URLClassLoader", False, "URLClassLoader", "(URL[],ClassLoader)", "", "Argument[0]", "request-forgery", "manual"]
- ["java.net", "URLClassLoader", False, "URLClassLoader", "(URL[])", "", "Argument[0]", "request-forgery", "manual"]
- ["java.net", "PasswordAuthentication", False, "PasswordAuthentication", "(String,char[])", "", "Argument[0]", "credentials-username", "hq-generated"]
- addsTo:
pack: codeql/java-all
extensible: barrierGuardModel
data:
- ["java.net", "URI", True, "isAbsolute", "()", "", "Argument[this]", "false", "request-forgery", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel

View File

@@ -12,6 +12,11 @@ extensions:
- ["java.util.regex", "Pattern", False, "split", "(CharSequence)", "", "Argument[this]", "regex-use[0]", "manual"]
- ["java.util.regex", "Pattern", False, "split", "(CharSequence,int)", "", "Argument[this]", "regex-use[0]", "manual"]
- ["java.util.regex", "Pattern", False, "splitAsStream", "(CharSequence)", "", "Argument[this]", "regex-use[0]", "manual"]
- addsTo:
pack: codeql/java-all
extensible: barrierModel
data:
- ["java.util.regex", "Pattern", False, "quote", "(String)", "", "ReturnValue", "regex-use", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel

View File

@@ -1,6 +1,42 @@
extensions:
- addsTo:
pack: codeql/java-all
extensible: barrierGuardModel
data:
- ["org.owasp.esapi", "Validator", true, "isValidCreditCard", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidDate", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidDirectoryPath", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidDouble", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidFileContent", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidFileName", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidInput", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidInteger", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidListItem", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidNumber", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidPrintable", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidRedirectLocation", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidSafeHTML", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "isValidURI", "", "", "Argument[1]", "true", "trust-boundary-violation", "manual"]
- addsTo:
pack: codeql/java-all
extensible: barrierModel
data:
- ["org.owasp.esapi", "Validator", true, "getValidCreditCard", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidDate", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidDirectoryPath", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidDouble", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidFileContent", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidFileName", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidInput", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidInteger", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidListItem", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidNumber", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidPrintable", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidRedirectLocation", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidSafeHTML", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- ["org.owasp.esapi", "Validator", true, "getValidURI", "", "", "ReturnValue", "trust-boundary-violation", "manual"]
- addsTo:
pack: codeql/java-all
extensible: summaryModel
data:
- ["org.owasp.esapi", "Encoder", true, "encodeForHTML", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["org.owasp.esapi", "Encoder", true, "encodeForHTML", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]

View File

@@ -1,5 +1,5 @@
name: codeql/java-all
version: 7.8.2-dev
version: 7.8.3-dev
groups: java
dbscheme: config/semmlecode.dbscheme
extractor: java

View File

@@ -91,14 +91,60 @@ module;
import java
private import semmle.code.java.dataflow.DataFlow::DataFlow
private import semmle.code.java.controlflow.Guards
private import FlowSummary as FlowSummary
private import internal.DataFlowPrivate
private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External
private import internal.ExternalFlowExtensions as Extensions
private import internal.ExternalFlowExtensions::Extensions as Extensions
private import codeql.mad.ModelValidation as SharedModelVal
private import codeql.mad.static.ModelsAsData as SharedMaD
private module MadInput implements SharedMaD::InputSig {
/** Holds if a source model exists for the given parameters. */
predicate additionalSourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance, string model
) {
exists(QlBuiltins::ExtensionId madId |
any(ActiveExperimentalModelsInternal q)
.sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance,
madId) and
model = "MaD:" + madId.toString()
)
}
/** Holds if a sink model exists for the given parameters. */
predicate additionalSinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance, string model
) {
exists(QlBuiltins::ExtensionId madId |
any(ActiveExperimentalModelsInternal q)
.sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
model = "MaD:" + madId.toString()
)
}
/** Holds if a summary model exists for the given parameters. */
predicate additionalSummaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string model
) {
exists(QlBuiltins::ExtensionId madId |
any(ActiveExperimentalModelsInternal q)
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId) and
model = "MaD:" + madId.toString()
)
}
}
private module MaD = SharedMaD::ModelsAsData<Extensions, MadInput>;
import MaD
/**
* A class for activating additional model rows.
@@ -146,60 +192,18 @@ abstract private class ActiveExperimentalModelsInternal extends string {
deprecated class ActiveExperimentalModels = ActiveExperimentalModelsInternal;
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
(
Extensions::sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance,
madId)
or
any(ActiveExperimentalModelsInternal q)
.sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId)
)
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
(
Extensions::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance,
madId)
or
any(ActiveExperimentalModelsInternal q)
.sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId)
)
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
(
Extensions::summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId)
or
any(ActiveExperimentalModelsInternal q)
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId)
)
}
/**
* Holds if the given extension tuple `madId` should pretty-print as `model`.
*
* This predicate should only be used in tests.
*/
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
MaD::interpretModelForTest(madId, model)
or
exists(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
|
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId) or
Extensions::experimentalSourceModel(package, type, subtypes, name, signature, ext, output, kind,
provenance, _, madId)
|
@@ -212,7 +216,6 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
|
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId) or
Extensions::experimentalSinkModel(package, type, subtypes, name, signature, ext, input, kind,
provenance, _, madId)
|
@@ -225,8 +228,6 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
|
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance,
madId) or
Extensions::experimentalSummaryModel(package, type, subtypes, name, signature, ext, input,
output, kind, provenance, _, madId)
|
@@ -236,65 +237,6 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
)
}
/** Holds if a neutral model exists for the given parameters. */
predicate neutralModel = Extensions::neutralModel/6;
private predicate relevantPackage(string package) {
sourceModel(package, _, _, _, _, _, _, _, _, _) or
sinkModel(package, _, _, _, _, _, _, _, _, _) or
summaryModel(package, _, _, _, _, _, _, _, _, _, _)
}
private predicate packageLink(string shortpkg, string longpkg) {
relevantPackage(shortpkg) and
relevantPackage(longpkg) and
longpkg.prefix(longpkg.indexOf(".")) = shortpkg
}
private predicate canonicalPackage(string package) {
relevantPackage(package) and not packageLink(_, package)
}
private predicate canonicalPkgLink(string package, string subpkg) {
canonicalPackage(package) and
(subpkg = package or packageLink(package, subpkg))
}
/**
* Holds if MaD framework coverage of `package` is `n` api endpoints of the
* kind `(kind, part)`, and `pkgs` is the number of subpackages of `package`
* which have MaD framework coverage (including `package` itself).
*/
predicate modelCoverage(string package, int pkgs, string kind, string part, int n) {
pkgs = strictcount(string subpkg | canonicalPkgLink(package, subpkg)) and
(
part = "source" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string output, string provenance |
canonicalPkgLink(package, subpkg) and
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance, _)
)
or
part = "sink" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, string provenance |
canonicalPkgLink(package, subpkg) and
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance, _)
)
or
part = "summary" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, string output, string provenance |
canonicalPkgLink(package, subpkg) and
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance,
_)
)
)
}
/** Provides a query predicate to check the MaD models for validation errors. */
module ModelValidation {
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
@@ -303,7 +245,9 @@ module ModelValidation {
summaryModel(_, _, _, _, _, _, path, _, _, _, _) or
summaryModel(_, _, _, _, _, _, _, path, _, _, _) or
sinkModel(_, _, _, _, _, _, path, _, _, _) or
sourceModel(_, _, _, _, _, _, path, _, _, _)
sourceModel(_, _, _, _, _, _, path, _, _, _) or
barrierModel(_, _, _, _, _, _, path, _, _, _) or
barrierGuardModel(_, _, _, _, _, _, path, _, _, _, _)
}
private module MkAccessPath = AccessPathSyntax::AccessPath<getRelevantAccessPath/1>;
@@ -316,6 +260,8 @@ module ModelValidation {
exists(string pred, AccessPath input, AccessPathToken part |
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
or
barrierGuardModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "barrier guard"
or
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
|
(
@@ -338,6 +284,8 @@ module ModelValidation {
exists(string pred, AccessPath output, AccessPathToken part |
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
or
barrierModel(_, _, _, _, _, _, output, _, _, _) and pred = "barrier"
or
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
|
(
@@ -355,7 +303,13 @@ module ModelValidation {
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
predicate sinkKind(string kind) {
sinkModel(_, _, _, _, _, _, _, kind, _, _)
or
barrierModel(_, _, _, _, _, _, _, kind, _, _)
or
barrierGuardModel(_, _, _, _, _, _, _, _, kind, _, _)
}
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
@@ -373,6 +327,11 @@ module ModelValidation {
or
sinkModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "sink"
or
barrierModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "barrier"
or
barrierGuardModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
pred = "barrier guard"
or
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
pred = "summary"
or
@@ -398,6 +357,14 @@ module ModelValidation {
invalidProvenance(provenance) and
result = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
)
or
exists(string acceptingvalue |
barrierGuardModel(_, _, _, _, _, _, _, acceptingvalue, _, _, _) and
invalidAcceptingValue(acceptingvalue) and
result =
"Unrecognized accepting value description \"" + acceptingvalue +
"\" in barrier guard model."
)
}
/** Holds if some row in a MaD flow model appears to contain typos. */
@@ -418,6 +385,10 @@ private predicate elementSpec(
or
sinkModel(package, type, subtypes, name, signature, ext, _, _, _, _)
or
barrierModel(package, type, subtypes, name, signature, ext, _, _, _, _)
or
barrierGuardModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
or
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
or
neutralModel(package, type, name, signature, _, _) and ext = "" and subtypes = true
@@ -578,6 +549,53 @@ private module Cached {
isSinkNode(n, kind, model) and n.asNode() = node
)
}
private newtype TKindModelPair =
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
private GuardValue convertAcceptingValue(AcceptingValue av) {
av.isTrue() and result.asBooleanValue() = true
or
av.isFalse() and result.asBooleanValue() = false
or
av.isNoException() and result.getDualValue().isThrowsException()
or
av.isZero() and result.asIntValue() = 0
or
av.isNotZero() and result.getDualValue().asIntValue() = 0
or
av.isNull() and result.isNullValue()
or
av.isNotNull() and result.isNonNullValue()
}
private predicate barrierGuardChecks(Guard g, Expr e, GuardValue gv, TKindModelPair kmp) {
exists(
SourceSinkInterpretationInput::InterpretNode n, AcceptingValue acceptingvalue, string kind,
string model
|
isBarrierGuardNode(n, acceptingvalue, kind, model) and
n.asNode().asExpr() = e and
kmp = TMkPair(kind, model) and
gv = convertAcceptingValue(acceptingvalue)
|
g.(Call).getAnArgument() = e or g.(MethodCall).getQualifier() = e
)
}
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
cached
predicate barrierNode(Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isBarrierNode(n, kind, model) and n.asNode() = node
)
or
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
model)) = node
}
}
import Cached
@@ -594,6 +612,12 @@ predicate sourceNode(Node node, string kind) { sourceNode(node, kind, _) }
*/
predicate sinkNode(Node node, string kind) { sinkNode(node, kind, _) }
/**
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
* model.
*/
predicate barrierNode(Node node, string kind) { barrierNode(node, kind, _) }
// adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() { summaryElement(this, _, _, _, _, _, _) }

View File

@@ -60,7 +60,7 @@ private module DispatchImpl {
not (
// Only use summarized callables with generated summaries in case
// the static call target is not in the source code.
// Note that if applyGeneratedModel holds it implies that there doesn't
// Note that if `applyGeneratedModel` holds it implies that there doesn't
// exist a manual model.
exists(Callable staticTarget | staticTarget = call.getCallee().getSourceDeclaration() |
staticTarget.fromSource() and not staticTarget.isStub()

View File

@@ -374,6 +374,29 @@ class ContentSet instanceof Content {
}
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate valueGuardChecksSig(Guard g, Expr e, GuardValue gv);
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module BarrierGuardValue<valueGuardChecksSig/3 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
SsaFlow::asNode(result) =
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
}
}
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
*
@@ -390,9 +413,38 @@ signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
* in data flow and taint tracking.
*/
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecks0(Guard g, Expr e, GuardValue gv) {
guardChecks(g, e, gv.asBooleanValue())
}
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode() {
Node getABarrierNode() { result = BarrierGuardValue<guardChecks0/3>::getABarrierNode() }
}
bindingset[this]
private signature class ParamSig;
private module WithParam<ParamSig P> {
/**
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
*
* The expression `e` is expected to be a syntactic part of the guard `g`.
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
* the argument `x`.
*/
signature predicate guardChecksSig(Guard g, Expr e, GuardValue gv, P param);
}
/**
* Provides a set of barrier nodes for a guard that validates an expression.
*
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
* in data flow and taint tracking.
*/
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
/** Gets a node that is safely guarded by the given guard check. */
Node getABarrierNode(P param) {
SsaFlow::asNode(result) =
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
}
}

View File

@@ -4,6 +4,8 @@
overlay[local?]
module;
private import codeql.mad.static.ModelsAsData as SharedMaD
/**
* Holds if a source model exists for the given parameters.
*/
@@ -20,6 +22,22 @@ extensible predicate sinkModel(
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if a barrier model exists for the given parameters.
*/
extensible predicate barrierModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if a barrier guard model exists for the given parameters.
*/
extensible predicate barrierGuardModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
* Holds if a summary model exists for the given parameters.
*/
@@ -77,3 +95,9 @@ extensible predicate experimentalSummaryModel(
string input, string output, string kind, string provenance, string filter,
QlBuiltins::ExtensionId madId
);
module Extensions implements SharedMaD::ExtensionsSig {
import ExternalFlowExtensions
predicate namespaceGrouping(string group, string namespace) { none() }
}

View File

@@ -158,7 +158,9 @@ private predicate relatedArgSpec(Callable c, string spec) {
summaryModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, spec, _, _, _) or
sourceModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _)
sinkModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
barrierModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
barrierGuardModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _, _)
|
c = interpretElement(namespace, type, subtypes, name, signature, ext, _)
)
@@ -226,11 +228,10 @@ module SourceSinkInterpretationInput implements
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseSource, string originalOutput, QlBuiltins::ExtensionId madId
SourceOrSinkElement baseSource, string originalOutput
|
sourceModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind, provenance,
madId) and
model = "MaD:" + madId.toString() and
model) and
baseSource = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
(
e = baseSource and output = originalOutput
@@ -245,11 +246,10 @@ module SourceSinkInterpretationInput implements
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseSink, string originalInput, QlBuiltins::ExtensionId madId
SourceOrSinkElement baseSink, string originalInput
|
sinkModel(namespace, type, subtypes, name, signature, ext, originalInput, kind, provenance,
madId) and
model = "MaD:" + madId.toString() and
model) and
baseSink = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
(
e = baseSink and originalInput = input
@@ -259,6 +259,43 @@ module SourceSinkInterpretationInput implements
)
}
predicate barrierElement(
Element e, string output, string kind, Public::Provenance provenance, string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseBarrier, string originalOutput
|
barrierModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind,
provenance, model) and
baseBarrier = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
(
e = baseBarrier and output = originalOutput
or
correspondingKotlinParameterDefaultsArgSpec(baseBarrier, e, originalOutput, output)
)
)
}
predicate barrierGuardElement(
Element e, string input, Public::AcceptingValue acceptingvalue, string kind,
Public::Provenance provenance, string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseBarrier, string originalInput
|
barrierGuardModel(namespace, type, subtypes, name, signature, ext, originalInput,
acceptingvalue, kind, provenance, model) and
baseBarrier = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
(
e = baseBarrier and input = originalInput
or
correspondingKotlinParameterDefaultsArgSpec(baseBarrier, e, originalInput, input)
)
)
}
class SourceOrSinkElement = Element;
private newtype TInterpretNode =
@@ -343,12 +380,10 @@ module Private {
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string originalInput, string originalOutput, Callable baseCallable,
QlBuiltins::ExtensionId madId
string originalInput, string originalOutput, Callable baseCallable
|
summaryModel(namespace, type, subtypes, name, signature, ext, originalInput, originalOutput,
kind, provenance, madId) and
model = "MaD:" + madId.toString() and
kind, provenance, model) and
baseCallable = interpretElement(namespace, type, subtypes, name, signature, ext, isExact) and
(
c.asCallable() = baseCallable and input = originalInput and output = originalOutput

View File

@@ -564,12 +564,14 @@ private module Cached {
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
}
signature predicate guardChecksSig(Guards::Guard g, Expr e, boolean branch);
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::GuardValue gv);
cached // nothing is actually cached
module BarrierGuard<guardChecksSig/3 guardChecks> {
private predicate guardChecksAdjTypes(Guards::Guards_v3::Guard g, Expr e, boolean branch) {
guardChecks(g, e, branch)
private predicate guardChecksAdjTypes(
Guards::Guards_v3::Guard g, Expr e, Guards::GuardValue gv
) {
guardChecks(g, e, gv)
}
private predicate guardChecksWithWrappers(
@@ -586,6 +588,36 @@ private module Cached {
predicate getABarrierNode = getABarrierNodeImpl/0;
}
bindingset[this]
private signature class ParamSig;
private module WithParam<ParamSig P> {
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::GuardValue gv, P param);
}
cached // nothing is actually cached
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
private predicate guardChecksAdjTypes(
Guards::Guards_v3::Guard g, Expr e, Guards::GuardValue gv, P param
) {
guardChecks(g, e, gv, param)
}
private predicate guardChecksWithWrappers(
DataFlowIntegrationInput::Guard g, Definition def, Guards::GuardValue val, P param
) {
Guards::Guards_v3::ParameterizedValidationWrapper<P, guardChecksAdjTypes/4>::guardChecksDef(g,
def, val, param)
}
private Node getABarrierNodeImpl(P param) {
result =
DataFlowIntegrationImpl::BarrierGuardDefWithState<P, guardChecksWithWrappers/4>::getABarrierNode(param)
}
predicate getABarrierNode = getABarrierNodeImpl/1;
}
}
cached

View File

@@ -14,14 +14,3 @@ class HudsonWebMethod extends Method {
this.getDeclaringType().getASourceSupertype*().hasQualifiedName("hudson.model", "Descriptor")
}
}
private class HudsonUtilXssSanitizer extends XssSanitizer {
HudsonUtilXssSanitizer() {
this.asExpr()
.(MethodCall)
.getMethod()
// Not including xmlEscape because it only accounts for >, <, and &.
// It does not account for ", or ', which makes it an incomplete XSS sanitizer.
.hasQualifiedName("hudson", "Util", "escape")
}
}

View File

@@ -1,42 +0,0 @@
/** Classes and predicates for reasoning about the `owasp.easpi` package. */
overlay[local?]
module;
import java
/**
* The `org.owasp.esapi.Validator` interface.
*/
class EsapiValidator extends RefType {
EsapiValidator() { this.hasQualifiedName("org.owasp.esapi", "Validator") }
}
/**
* The methods of `org.owasp.esapi.Validator` which validate data.
*/
class EsapiIsValidMethod extends Method {
EsapiIsValidMethod() {
this.getDeclaringType() instanceof EsapiValidator and
this.hasName([
"isValidCreditCard", "isValidDate", "isValidDirectoryPath", "isValidDouble",
"isValidFileContent", "isValidFileName", "isValidInput", "isValidInteger",
"isValidListItem", "isValidNumber", "isValidPrintable", "isValidRedirectLocation",
"isValidSafeHTML", "isValidURI"
])
}
}
/**
* The methods of `org.owasp.esapi.Validator` which return validated data.
*/
class EsapiGetValidMethod extends Method {
EsapiGetValidMethod() {
this.getDeclaringType() instanceof EsapiValidator and
this.hasName([
"getValidCreditCard", "getValidDate", "getValidDirectoryPath", "getValidDouble",
"getValidFileContent", "getValidFileName", "getValidInput", "getValidInteger",
"getValidListItem", "getValidNumber", "getValidPrintable", "getValidRedirectLocation",
"getValidSafeHTML", "getValidURI"
])
}
}

View File

@@ -4,6 +4,7 @@ module;
import java
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.frameworks.kotlin.IO
@@ -288,19 +289,8 @@ private Method getSourceMethod(Method m) {
result = m
}
/**
* A sanitizer that protects against path injection vulnerabilities
* by extracting the final component of the user provided path.
*
* TODO: convert this class to models-as-data if sanitizer support is added
*/
private class FileGetNameSanitizer extends PathInjectionSanitizer {
FileGetNameSanitizer() {
exists(MethodCall mc |
mc.getMethod().hasQualifiedName("java.io", "File", "getName") and
this.asExpr() = mc
)
}
private class DefaultPathInjectionSanitizer extends PathInjectionSanitizer {
DefaultPathInjectionSanitizer() { barrierNode(this, "path-injection") }
}
/** Holds if `g` is a guard that checks for `..` components. */

View File

@@ -118,25 +118,8 @@ private class ContainsUrlSanitizer extends RequestForgerySanitizer {
}
}
/**
* A check that the URL is relative, and therefore safe for URL redirects.
*/
private predicate isRelativeUrlSanitizer(Guard guard, Expr e, boolean branch) {
guard =
any(MethodCall call |
call.getMethod().hasQualifiedName("java.net", "URI", "isAbsolute") and
e = call.getQualifier() and
branch = false
)
}
/**
* A check that the URL is relative, and therefore safe for URL redirects.
*/
private class RelativeUrlSanitizer extends RequestForgerySanitizer {
RelativeUrlSanitizer() {
this = DataFlow::BarrierGuard<isRelativeUrlSanitizer/3>::getABarrierNode()
}
private class DefaultRequestForgerySanitizer extends RequestForgerySanitizer {
DefaultRequestForgerySanitizer() { barrierNode(this, "request-forgery") }
}
/**

View File

@@ -5,7 +5,6 @@ private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.frameworks.owasp.Esapi
private import semmle.code.java.security.Sanitizers
/**
@@ -28,25 +27,8 @@ class TrustBoundaryViolationSink extends DataFlow::Node {
*/
abstract class TrustBoundaryValidationSanitizer extends DataFlow::Node { }
/**
* A node validated by an OWASP ESAPI validation method.
*/
private class EsapiValidatedInputSanitizer extends TrustBoundaryValidationSanitizer {
EsapiValidatedInputSanitizer() {
this = DataFlow::BarrierGuard<esapiIsValidData/3>::getABarrierNode() or
this.asExpr().(MethodCall).getMethod() instanceof EsapiGetValidMethod
}
}
/**
* Holds if `g` is a guard that checks that `e` is valid data according to an OWASP ESAPI validation method.
*/
private predicate esapiIsValidData(Guard g, Expr e, boolean branch) {
branch = true and
exists(MethodCall ma | ma.getMethod() instanceof EsapiIsValidMethod |
g = ma and
e = ma.getArgument(1)
)
private class DefaultTrustBoundaryValidationSanitizer extends TrustBoundaryValidationSanitizer {
DefaultTrustBoundaryValidationSanitizer() { barrierNode(this, "trust-boundary-violation") }
}
/**

View File

@@ -54,12 +54,24 @@ private class DefaultXssSink extends XssSink {
}
}
/** A default sanitizer that considers numeric and boolean typed data safe for writing to output. */
private class DefaultXssSanitizer extends XssSanitizer {
DefaultXssSanitizer() {
DefaultXssSanitizer() { barrierNode(this, ["html-injection", "js-injection"]) }
}
/** A sanitizer that considers numeric and boolean typed data safe for writing to output. */
private class PrimitiveSanitizer extends XssSanitizer {
PrimitiveSanitizer() {
this.getType() instanceof NumericType or
this.getType() instanceof BooleanType or
// Match `org.springframework.web.util.HtmlUtils.htmlEscape` and possibly other methods like it.
this.getType() instanceof BooleanType
}
}
/**
* A call to `org.springframework.web.util.HtmlUtils.htmlEscape`, or possibly
* other methods like it, considered as a sanitizer for XSS.
*/
private class HtmlEscapeXssSanitizer extends XssSanitizer {
HtmlEscapeXssSanitizer() {
this.asExpr().(MethodCall).getMethod().getName().regexpMatch("(?i)html_?escape.*")
}
}

View File

@@ -21,17 +21,8 @@ private class DefaultRegexInjectionSink extends RegexInjectionSink {
}
}
/**
* A call to the `Pattern.quote` method, which gives metacharacters or escape sequences
* no special meaning.
*/
private class PatternQuoteCall extends RegexInjectionSanitizer {
PatternQuoteCall() {
exists(MethodCall ma, Method m | m = ma.getMethod() |
ma.getArgument(0) = this.asExpr() and
m instanceof PatternQuoteMethod
)
}
private class DefaultRegexInjectionSanitizer extends RegexInjectionSanitizer {
DefaultRegexInjectionSanitizer() { barrierNode(this, "regex-use") }
}
/**

View File

@@ -1,3 +1,9 @@
## 1.10.3
### Minor Analysis Improvements
* Java analysis no longer forces `--source` and `--target` compiler flags for Maven builds. This allows Maven to use the project's own compiler configuration, improving build compatibility.
## 1.10.2
No user-facing changes.

View File

@@ -1,4 +1,5 @@
---
category: minorAnalysis
---
## 1.10.3
### Minor Analysis Improvements
* Java analysis no longer forces `--source` and `--target` compiler flags for Maven builds. This allows Maven to use the project's own compiler configuration, improving build compatibility.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 1.10.2
lastReleaseVersion: 1.10.3

View File

@@ -1,5 +1,5 @@
name: codeql/java-queries
version: 1.10.3-dev
version: 1.10.4-dev
groups:
- java
- queries

View File

@@ -4,7 +4,13 @@ public class A {
boolean isSafe(Object o) { return o == null; }
void foo() {
void assertSafe(Object o) { if (o != null) throw new RuntimeException(); }
private boolean wrapIsSafe(Object o) { return isSafe(o); }
private void wrapAssertSafe(Object o) { assertSafe(o); }
void test1() {
Object x = source();
if (!isSafe(x)) {
x = null;
@@ -21,4 +27,23 @@ public class A {
}
sink(x);
}
void test2() {
Object x = source();
assertSafe(x);
sink(x);
}
void test3() {
Object x = source();
if (wrapIsSafe(x)) {
sink(x);
}
}
void test4() {
Object x = source();
wrapAssertSafe(x);
sink(x);
}
}

View File

@@ -10,6 +10,14 @@ private predicate isSafe(Guard g, Expr checked, boolean branch) {
)
}
private predicate assertSafe(Guard g, Expr checked, GuardValue gv) {
exists(MethodCall mc | g = mc |
mc.getMethod().hasName("assertSafe") and
checked = mc.getAnArgument() and
gv.getDualValue().isThrowsException()
)
}
module TestConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(MethodCall).getMethod().hasName("source")
@@ -21,6 +29,8 @@ module TestConfig implements DataFlow::ConfigSig {
predicate isBarrier(DataFlow::Node node) {
node = DataFlow::BarrierGuard<isSafe/3>::getABarrierNode()
or
node = DataFlow::BarrierGuardValue<assertSafe/3>::getABarrierNode()
}
}