10000 Java: Promote experimental XXE sinks by atorralba · Pull Request #12932 · github/codeql · GitHub
[go: up one dir, main page]

Skip to content

Java: Promote experimental XXE sinks #12932

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions java/ql/lib/semmle/code/java/dataflow/RangeUtils.qll
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ private predicate constantBooleanExpr(Expr e, boolean val) {
CalcConstants::calculateBooleanValue(e) = val
}

pragma[nomagic]
private predicate constantStringExpr(Expr e, string val) {
e.(CompileTimeConstantExpr).getStringValue() = val
or
exists(SsaExplicitUpdate v, Expr src |
e = v.getAUse() and
src = v.getDefiningExpr().(VariableAssign).getSource() and
constantStringExpr(src, val)
)
}

private boolean getBoolValue(Expr e) { constantBooleanExpr(e, result) }

private int getIntValue(Expr e) { constantIntegerExpr(e, result) }
Expand All @@ -126,6 +137,14 @@ class ConstantBooleanExpr extends Expr {
boolean getBooleanValue() { constantBooleanExpr(this, result) }
}

/** An expression that always has the same string value. */
class ConstantStringExpr extends Expr {
ConstantStringExpr() { constantStringExpr(this, _) }

/** Get the string value of this expression. */
string getStringValue() { constantStringExpr(this, result) }
}

/**
* Gets an expression that equals `v - d`.
*/
Expand Down
90 changes: 90 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/apache/CommonsXml.qll
A935
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/** Provides XML definitions related to the `org.apache.commons` package. */

import java
private import semmle.code.java.dataflow.RangeUtils
private import semmle.code.java.security.XmlParsers

/**
* The classes `org.apache.commons.digester3.Digester`, `org.apache.commons.digester.Digester` or `org.apache.tomcat.util.digester.Digester`.
*/
private class Digester extends RefType {
Digester() {
this.hasQualifiedName([
"org.apache.commons.digester3", "org.apache.commons.digester",
"org.apache.tomcat.util.digester"
], "Digester")
}
}

/** A call to `Digester.parse`. */
private class DigesterParse extends XmlParserCall {
DigesterParse() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof Digester and
m.hasName("parse")
)
}

override Expr getSink() { result = this.getArgument(0) }

override predicate isSafe() { SafeDigesterFlow::flowToExpr(this.getQualifier()) }
}

/** A `ParserConfig` that is specific to `Digester`. */
private class DigesterConfig extends ParserConfig {
DigesterConfig() {
exists(Method m |
m = this.getMethod() and
m.getDeclaringType() instanceof Digester and
m.hasName("setFeature")
)
}
}

/**
* A safely configured `Digester`.
*/
private class SafeDigester extends VarAccess {
SafeDigester() {
exists(Variable v | v = this.getVariable() |
exists(DigesterConfig config | config.getQualifier() = v.getAnAccess() |
config.enables(singleSafeConfig())
)
or
exists(DigesterConfig config | config.getQualifier() = v.getAnAccess() |
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
))
) and
exists(DigesterConfig config | config.getQualifier() = v.getAnAccess() |
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
))
) and
exists(DigesterConfig config | config.getQualifier() = v.getAnAccess() |
config
.disables(any(ConstantStringExpr s |
s.getStringValue() =
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
))
)
)
}
}

private module SafeDigesterFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDigester }

predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof Digester
)
}

int fieldFlowBranchLimit() { result = 0 }
}

private module SafeDigesterFlow = DataFlow::Global<SafeDigesterFlowConfig>;
64 changes: 64 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/javaee/Xml.qll
F438
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/** Provides definitions related to the `javax.xml` package. */

import java
private import semmle.code.java.security.XmlParsers

/** A call to `Validator.validate`. */
private class ValidatorValidate extends XmlParserCall {
ValidatorValidate() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof Validator and
m.hasName("validate")
)
}

override Expr getSink() { result = this.getArgument(0) }

override predicate isSafe() { SafeValidatorFlow::flowToExpr(this.getQualifier()) }
}

/** A `TransformerConfig` specific to `Validator`. */
private class ValidatorConfig extends TransformerConfig {
ValidatorConfig() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof Validator and
m.hasName("setProperty")
)
}
}

/** The class `javax.xml.validation.Validator`. */
private class Validator extends RefType {
Validator() { this.hasQualifiedName("javax.xml.validation", "Validator") }
}

/** A safely configured `Validator`. */
private class SafeValidator extends VarAccess {
SafeValidator() {
exists(Variable v | v = this.getVariable() |
exists(ValidatorConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(configAccessExternalDtd())
) and
exists(ValidatorConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(configAccessExternalSchema())
)
)
}
}

private module SafeValidatorFlowConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeValidator }

predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
ma.getMethod().getDeclaringType() instanceof Validator
)
}

int fieldFlowBranchLimit() { result = 0 }
}

private module SafeValidatorFlow = DataFlow::Global<SafeValidatorFlowConfig>;
24 changes: 24 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/javase/Beans.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/** Provides definitions related to the `java.beans` package. */

import java
private import semmle.code.java.security.XmlParsers

/** The class `java.beans.XMLDecoder`. */
private class XmlDecoder extends RefType {
XmlDecoder() { this.hasQualifiedName("java.beans", "XMLDecoder") }
}

/** A call to `XMLDecoder.readObject`. */
private class XmlDecoderReadObject extends XmlParserCall {
XmlDecoderReadObject() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof XmlDecoder and
m.hasName("readObject")
)
}

override Expr getSink() { result = this.getQualifier() }

override predicate isSafe() { none() }
}
19 changes: 19 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/rundeck/RundeckXml.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/** Provides definitions related to XML parsing in Rundeck. */

import java
private import semmle.code.java.security.XmlParsers

/** A call to `ParserHelper.loadDocument`. */
private class ParserHelperLoadDocument extends XmlParserCall {
ParserHelperLoadDocument() {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType().hasQualifiedName("org.rundeck.api.parser", "ParserHelper") and
m.hasName("loadDocument")
)
}

override Expr getSink() { result = this.getArgument(0) }

override predicate isSafe() { none() }
}
36 changes: 8 additions & 28 deletions java/ql/lib/semmle/code/java/security/XmlParsers.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.DataFlow2
import semmle.code.java.dataflow.DataFlow3
import semmle.code.java.dataflow.DataFlow4
import semmle.code.java.dataflow.DataFlow5
private import semmle.code.java.dataflow.SSA
private import semmle.code.java.dataflow.RangeUtils

/*
* Various XML parsers in Java.
*/
private module Frameworks {
private import semmle.code.java.frameworks.apache.CommonsXml
private import semmle.code.java.frameworks.javaee.Xml
private import semmle.code.java.frameworks.javase.Beans
private import semmle.code.java.frameworks.rundeck.RundeckXml
}

/**
* An abstract type representing a call to parse XML files.
Expand Down Expand Up @@ -130,26 +130,6 @@ class DocumentBuilderFactoryConfig extends ParserConfig {
}
}

private predicate constantStringExpr(Expr e, string val) {
e.(CompileTimeConstantExpr).getStringValue() = val
or
exists(SsaExplicitUpdate v, Expr src |
e = v.getAUse() and
src = v.getDefiningExpr().(VariableAssign).getSource() and
constantStringExpr(src, val)
)
}

/** An expression that always has the same string value. */
private class ConstantStringExpr extends Expr {
string value;

ConstantStringExpr() { constantStringExpr(this, value) }

/** Get the string value of this expression. */
string getStringValue() { result = value }
}

/**
* A general configuration that is safe when enabled.
*/
Expand Down Expand Up @@ -973,7 +953,7 @@ class TransformerFactorySource extends XmlParserCall {
exists(Method m |
this.getMethod() = m and
m.getDeclaringType() instanceof TransformerFactory and
m.hasName("newTransformer")
m.hasName(["newTransformer", "newTransformerHandler"])
)
}

Expand Down
4 changes: 4 additions & 0 deletions java/ql/src/change-notes/2023-04-26-xxe-sinks-promotion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Experimental sinks for the query "Resolving XML external entity in user-controlled data" (`java/xxe`) have been promoted to the main query pack. These sinks were originally [submitted as part of an experimental query by @haby0](https://github.com/github/codeql/pull/6564).
85 changes: 0 additions & 85 deletions java/ql/src/experimental/Security/CWE/CWE-611/XXE.java

This file was deleted.

Loading
0