mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #9176 from geoffw0/xxe9
C++: Clean up the XXE query QL.
This commit is contained in:
78
cpp/ql/src/Security/CWE/CWE-611/Libxml2.qll
Normal file
78
cpp/ql/src/Security/CWE/CWE-611/Libxml2.qll
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/**
|
||||||
|
* Models the libxml2 XML library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import XML
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A call to a `libxml2` function that parses XML.
|
||||||
|
*/
|
||||||
|
class Libxml2ParseCall extends FunctionCall {
|
||||||
|
int optionsArg;
|
||||||
|
|
||||||
|
Libxml2ParseCall() {
|
||||||
|
exists(string fname | this.getTarget().getName() = fname |
|
||||||
|
fname = "xmlCtxtUseOptions" and optionsArg = 1
|
||||||
|
or
|
||||||
|
fname = "xmlReadFile" and optionsArg = 2
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
|
||||||
|
optionsArg = 3
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
|
||||||
|
or
|
||||||
|
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
|
||||||
|
or
|
||||||
|
fname = "xmlCtxtReadIO" and optionsArg = 6
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the argument that specifies `xmlParserOption`s.
|
||||||
|
*/
|
||||||
|
Expr getOptions() { result = this.getArgument(optionsArg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `xmlParserOption` for `libxml2` that is considered unsafe.
|
||||||
|
*/
|
||||||
|
class Libxml2BadOption extends EnumConstant {
|
||||||
|
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The libxml2 XML library.
|
||||||
|
*/
|
||||||
|
class LibXml2Library extends XmlLibrary {
|
||||||
|
LibXml2Library() { this = "LibXml2Library" }
|
||||||
|
|
||||||
|
override predicate configurationSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is an `options` argument on a libxml2 parse call that specifies
|
||||||
|
// at least one unsafe option.
|
||||||
|
//
|
||||||
|
// note: we don't need to track an XML object for libxml2, so we don't
|
||||||
|
// really need data flow. Nevertheless we jam it into this configuration,
|
||||||
|
// with matching sources and sinks. This allows results to be presented by
|
||||||
|
// the same query, in a consistent way as other results with flow paths.
|
||||||
|
exists(Libxml2ParseCall call, Expr options |
|
||||||
|
options = call.getOptions() and
|
||||||
|
node.asExpr() = options and
|
||||||
|
flowstate = "libxml2" and
|
||||||
|
exists(Libxml2BadOption opt |
|
||||||
|
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate configurationSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the `options` argument on a `libxml2` parse call.
|
||||||
|
exists(Libxml2ParseCall call, Expr options |
|
||||||
|
options = call.getOptions() and
|
||||||
|
node.asExpr() = options and
|
||||||
|
flowstate = "libxml2"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
cpp/ql/src/Security/CWE/CWE-611/XML.qll
Normal file
55
cpp/ql/src/Security/CWE/CWE-611/XML.qll
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Provides a abstract classes for modeling XML libraries. This design is
|
||||||
|
* currently specialized for the purposes of the XXE query.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||||
|
import Xerces
|
||||||
|
import Libxml2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state representing a possible configuration of an XML object.
|
||||||
|
*/
|
||||||
|
abstract class XxeFlowState extends DataFlow::FlowState {
|
||||||
|
bindingset[this]
|
||||||
|
XxeFlowState() { any() } // required characteristic predicate
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An XML library or interface.
|
||||||
|
*/
|
||||||
|
abstract class XmlLibrary extends string {
|
||||||
|
bindingset[this]
|
||||||
|
XmlLibrary() { any() } // required characteristic predicate
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `node` is the source node for a potentially unsafe configuration
|
||||||
|
* object for this XML library, along with `flowstate` representing its
|
||||||
|
* initial state.
|
||||||
|
*/
|
||||||
|
abstract predicate configurationSource(DataFlow::Node node, string flowstate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `node` is the sink node where an unsafe configuration object is
|
||||||
|
* used to interpret XML.
|
||||||
|
*/
|
||||||
|
abstract predicate configurationSink(DataFlow::Node node, string flowstate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Expr` that changes the configuration of an XML object, transforming the
|
||||||
|
* `XxeFlowState` that flows through it.
|
||||||
|
*/
|
||||||
|
abstract class XxeFlowStateTransformer extends Expr {
|
||||||
|
/**
|
||||||
|
* Gets the flow state that `flowstate` is transformed into.
|
||||||
|
*
|
||||||
|
* Due to limitations of the implementation the transformation defined by this
|
||||||
|
* predicate must be idempotent, that is, for any input `x` it must be that:
|
||||||
|
* ```
|
||||||
|
* transform(transform(x)) = transform(x)
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
abstract XxeFlowState transform(XxeFlowState flowstate);
|
||||||
|
}
|
||||||
@@ -13,344 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import cpp
|
import cpp
|
||||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
import XML
|
||||||
import DataFlow::PathGraph
|
import DataFlow::PathGraph
|
||||||
import semmle.code.cpp.ir.IR
|
|
||||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state representing a possible configuration of an XML object.
|
|
||||||
*/
|
|
||||||
abstract class XXEFlowState extends DataFlow::FlowState {
|
|
||||||
bindingset[this]
|
|
||||||
XXEFlowState() { any() } // required characteristic predicate
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An `Expr` that changes the configuration of an XML object, transforming the
|
|
||||||
* `XXEFlowState` that flows through it.
|
|
||||||
*/
|
|
||||||
abstract class XXEFlowStateTransformer extends Expr {
|
|
||||||
/**
|
|
||||||
* Gets the flow state that `flowstate` is transformed into.
|
|
||||||
*
|
|
||||||
* Due to limitations of the implementation the transformation defined by this
|
|
||||||
* predicate must be idempotent, that is, for any input `x` it must be that:
|
|
||||||
* ```
|
|
||||||
* transform(transform(x)) = transform(x)
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
abstract XXEFlowState transform(XXEFlowState flowstate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `AbstractDOMParser` class.
|
|
||||||
*/
|
|
||||||
class AbstractDOMParserClass extends Class {
|
|
||||||
AbstractDOMParserClass() { this.hasName("AbstractDOMParser") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `XercesDOMParser` class.
|
|
||||||
*/
|
|
||||||
class XercesDOMParserClass extends Class {
|
|
||||||
XercesDOMParserClass() { this.hasName("XercesDOMParser") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `DOMLSParser` class.
|
|
||||||
*/
|
|
||||||
class DomLSParserClass extends Class {
|
|
||||||
DomLSParserClass() { this.hasName("DOMLSParser") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `SAXParser` class.
|
|
||||||
*/
|
|
||||||
class SaxParserClass extends Class {
|
|
||||||
SaxParserClass() { this.hasName("SAXParser") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `SAX2XMLReader` class.
|
|
||||||
*/
|
|
||||||
class Sax2XmlReader extends Class {
|
|
||||||
Sax2XmlReader() { this.hasName("SAX2XMLReader") }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow.
|
|
||||||
*
|
|
||||||
* These flow states take the form `Xerces-A-B`, where:
|
|
||||||
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
|
|
||||||
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
|
|
||||||
*/
|
|
||||||
predicate encodeXercesFlowState(
|
|
||||||
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
|
|
||||||
) {
|
|
||||||
flowstate = "Xerces-0-0" and
|
|
||||||
disabledDefaultEntityResolution = 0 and
|
|
||||||
createEntityReferenceNodes = 0
|
|
||||||
or
|
|
||||||
flowstate = "Xerces-0-1" and
|
|
||||||
disabledDefaultEntityResolution = 0 and
|
|
||||||
createEntityReferenceNodes = 1
|
|
||||||
or
|
|
||||||
flowstate = "Xerces-1-0" and
|
|
||||||
disabledDefaultEntityResolution = 1 and
|
|
||||||
createEntityReferenceNodes = 0
|
|
||||||
or
|
|
||||||
flowstate = "Xerces-1-1" and
|
|
||||||
disabledDefaultEntityResolution = 1 and
|
|
||||||
createEntityReferenceNodes = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state representing the configuration of an `AbstractDOMParser` or
|
|
||||||
* `SAXParser` object.
|
|
||||||
*/
|
|
||||||
class XercesFlowState extends XXEFlowState {
|
|
||||||
XercesFlowState() { encodeXercesFlowState(this, _, _) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state transformer for a call to
|
|
||||||
* `AbstractDOMParser.setDisableDefaultEntityResolution` or
|
|
||||||
* `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow
|
|
||||||
* state through the qualifier according to the setting in the parameter.
|
|
||||||
*/
|
|
||||||
class DisableDefaultEntityResolutionTransformer extends XXEFlowStateTransformer {
|
|
||||||
Expr newValue;
|
|
||||||
|
|
||||||
DisableDefaultEntityResolutionTransformer() {
|
|
||||||
exists(Call call, Function f |
|
|
||||||
call.getTarget() = f and
|
|
||||||
(
|
|
||||||
f.getDeclaringType() instanceof AbstractDOMParserClass or
|
|
||||||
f.getDeclaringType() instanceof SaxParserClass
|
|
||||||
) and
|
|
||||||
f.hasName("setDisableDefaultEntityResolution") and
|
|
||||||
this = call.getQualifier() and
|
|
||||||
newValue = call.getArgument(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
|
||||||
exists(int createEntityReferenceNodes |
|
|
||||||
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
|
||||||
(
|
|
||||||
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
|
||||||
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
|
||||||
or
|
|
||||||
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
|
||||||
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state transformer for a call to
|
|
||||||
* `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow
|
|
||||||
* state through the qualifier according to the setting in the parameter.
|
|
||||||
*/
|
|
||||||
class CreateEntityReferenceNodesTransformer extends XXEFlowStateTransformer {
|
|
||||||
Expr newValue;
|
|
||||||
|
|
||||||
CreateEntityReferenceNodesTransformer() {
|
|
||||||
exists(Call call, Function f |
|
|
||||||
call.getTarget() = f and
|
|
||||||
f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDOMParserClass and
|
|
||||||
this = call.getQualifier() and
|
|
||||||
newValue = call.getArgument(0)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
|
||||||
exists(int disabledDefaultEntityResolution |
|
|
||||||
encodeXercesFlowState(flowstate, disabledDefaultEntityResolution, _) and
|
|
||||||
(
|
|
||||||
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
|
||||||
encodeXercesFlowState(result, disabledDefaultEntityResolution, 1)
|
|
||||||
or
|
|
||||||
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
|
||||||
encodeXercesFlowState(result, disabledDefaultEntityResolution, 0)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `XMLUni.fgXercesDisableDefaultEntityResolution` constant.
|
|
||||||
*/
|
|
||||||
class FeatureDisableDefaultEntityResolution extends Variable {
|
|
||||||
FeatureDisableDefaultEntityResolution() {
|
|
||||||
this.getName() = "fgXercesDisableDefaultEntityResolution" and
|
|
||||||
this.getDeclaringType().getName() = "XMLUni"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state transformer for a call to `SAX2XMLReader.setFeature`
|
|
||||||
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
|
||||||
* Transforms the flow state through the qualifier according to this setting.
|
|
||||||
*/
|
|
||||||
class SetFeatureTransformer extends XXEFlowStateTransformer {
|
|
||||||
Expr newValue;
|
|
||||||
|
|
||||||
SetFeatureTransformer() {
|
|
||||||
exists(Call call, Function f |
|
|
||||||
call.getTarget() = f and
|
|
||||||
f.getClassAndName("setFeature") instanceof Sax2XmlReader and
|
|
||||||
this = call.getQualifier() and
|
|
||||||
globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof
|
|
||||||
FeatureDisableDefaultEntityResolution and
|
|
||||||
newValue = call.getArgument(1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
|
||||||
exists(int createEntityReferenceNodes |
|
|
||||||
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
|
||||||
(
|
|
||||||
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
|
||||||
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
|
||||||
or
|
|
||||||
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
|
||||||
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `DOMLSParser.getDomConfig` function.
|
|
||||||
*/
|
|
||||||
class GetDomConfig extends Function {
|
|
||||||
GetDomConfig() { this.getClassAndName("getDomConfig") instanceof DomLSParserClass }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `DOMConfiguration.setParameter` function.
|
|
||||||
*/
|
|
||||||
class DomConfigurationSetParameter extends Function {
|
|
||||||
DomConfigurationSetParameter() {
|
|
||||||
this.getClassAndName("setParameter").getName() = "DOMConfiguration"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A flow state transformer for a call to `DOMConfiguration.setParameter`
|
|
||||||
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
|
||||||
* This is a slightly more complex transformer because the qualifier is a
|
|
||||||
* `DOMConfiguration` pointer returned by `DOMLSParser.getDomConfig` - and it
|
|
||||||
* is *that* qualifier we want to transform the flow state of.
|
|
||||||
*/
|
|
||||||
class DomConfigurationSetParameterTransformer extends XXEFlowStateTransformer {
|
|
||||||
Expr newValue;
|
|
||||||
|
|
||||||
DomConfigurationSetParameterTransformer() {
|
|
||||||
exists(FunctionCall getDomConfigCall, FunctionCall setParameterCall |
|
|
||||||
// this is the qualifier of a call to `DOMLSParser.getDomConfig`.
|
|
||||||
getDomConfigCall.getTarget() instanceof GetDomConfig and
|
|
||||||
this = getDomConfigCall.getQualifier() and
|
|
||||||
// `setParameterCall` is a call to `setParameter` on the return value of
|
|
||||||
// the same call to `DOMLSParser.getDomConfig`.
|
|
||||||
setParameterCall.getTarget() instanceof DomConfigurationSetParameter and
|
|
||||||
globalValueNumber(setParameterCall.getQualifier()).getAnExpr() = getDomConfigCall and
|
|
||||||
// the parameter being set is
|
|
||||||
// `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
|
||||||
globalValueNumber(setParameterCall.getArgument(0)).getAnExpr().(VariableAccess).getTarget()
|
|
||||||
instanceof FeatureDisableDefaultEntityResolution and
|
|
||||||
// the value being set is `newValue`.
|
|
||||||
newValue = setParameterCall.getArgument(1)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
final override XXEFlowState transform(XXEFlowState flowstate) {
|
|
||||||
exists(int createEntityReferenceNodes |
|
|
||||||
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
|
||||||
(
|
|
||||||
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
|
||||||
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
|
||||||
or
|
|
||||||
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
|
||||||
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `AbstractDOMParser.parse`, `DOMLSParserClass.parse`, `SAXParser.parse`
|
|
||||||
* or `SAX2XMLReader.parse` method.
|
|
||||||
*/
|
|
||||||
class ParseFunction extends Function {
|
|
||||||
ParseFunction() {
|
|
||||||
this.getClassAndName("parse") instanceof AbstractDOMParserClass or
|
|
||||||
this.getClassAndName("parse") instanceof DomLSParserClass or
|
|
||||||
this.getClassAndName("parse") instanceof SaxParserClass or
|
|
||||||
this.getClassAndName("parse") instanceof Sax2XmlReader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `createLSParser` function that returns a newly created `DOMLSParser`
|
|
||||||
* object.
|
|
||||||
*/
|
|
||||||
class CreateLSParser extends Function {
|
|
||||||
CreateLSParser() {
|
|
||||||
this.hasName("createLSParser") and
|
|
||||||
this.getUnspecifiedType().(PointerType).getBaseType() instanceof DomLSParserClass // returns a `DOMLSParser *`.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The `createXMLReader` function that returns a newly created `SAX2XMLReader`
|
|
||||||
* object.
|
|
||||||
*/
|
|
||||||
class CreateXmlReader extends Function {
|
|
||||||
CreateXmlReader() {
|
|
||||||
this.hasName("createXMLReader") and
|
|
||||||
this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A call to a `libxml2` function that parses XML.
|
|
||||||
*/
|
|
||||||
class Libxml2ParseCall extends FunctionCall {
|
|
||||||
int optionsArg;
|
|
||||||
|
|
||||||
Libxml2ParseCall() {
|
|
||||||
exists(string fname | this.getTarget().getName() = fname |
|
|
||||||
fname = "xmlCtxtUseOptions" and optionsArg = 1
|
|
||||||
or
|
|
||||||
fname = "xmlReadFile" and optionsArg = 2
|
|
||||||
or
|
|
||||||
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
|
|
||||||
optionsArg = 3
|
|
||||||
or
|
|
||||||
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
|
|
||||||
or
|
|
||||||
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
|
|
||||||
or
|
|
||||||
fname = "xmlCtxtReadIO" and optionsArg = 6
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the argument that specifies `xmlParserOption`s.
|
|
||||||
*/
|
|
||||||
Expr getOptions() { result = this.getArgument(optionsArg) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An `xmlParserOption` for `libxml2` that is considered unsafe.
|
|
||||||
*/
|
|
||||||
class Libxml2BadOption extends EnumConstant {
|
|
||||||
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A configuration for tracking XML objects and their states.
|
* A configuration for tracking XML objects and their states.
|
||||||
@@ -359,85 +23,25 @@ class XXEConfiguration extends DataFlow::Configuration {
|
|||||||
XXEConfiguration() { this = "XXEConfiguration" }
|
XXEConfiguration() { this = "XXEConfiguration" }
|
||||||
|
|
||||||
override predicate isSource(DataFlow::Node node, string flowstate) {
|
override predicate isSource(DataFlow::Node node, string flowstate) {
|
||||||
// source is the write on `this` of a call to the `XercesDOMParser`
|
any(XmlLibrary l).configurationSource(node, flowstate)
|
||||||
// constructor.
|
|
||||||
exists(CallInstruction call |
|
|
||||||
call.getStaticCallTarget() = any(XercesDOMParserClass c).getAConstructor() and
|
|
||||||
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
|
||||||
call.getThisArgument() and
|
|
||||||
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// source is the result of a call to `createLSParser`.
|
|
||||||
exists(Call call |
|
|
||||||
call.getTarget() instanceof CreateLSParser and
|
|
||||||
call = node.asExpr() and
|
|
||||||
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// source is the write on `this` of a call to the `SAXParser`
|
|
||||||
// constructor.
|
|
||||||
exists(CallInstruction call |
|
|
||||||
call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and
|
|
||||||
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
|
||||||
call.getThisArgument() and
|
|
||||||
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// source is the result of a call to `createXMLReader`.
|
|
||||||
exists(Call call |
|
|
||||||
call.getTarget() instanceof CreateXmlReader and
|
|
||||||
call = node.asExpr() and
|
|
||||||
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// source is an `options` argument on a `libxml2` parse call that specifies
|
|
||||||
// at least one unsafe option.
|
|
||||||
//
|
|
||||||
// note: we don't need to track an XML object for `libxml2`, so we don't
|
|
||||||
// really need data flow. Nevertheless we jam it into this configuration,
|
|
||||||
// with matching sources and sinks. This allows results to be presented by
|
|
||||||
// the same query, in a consistent way as other results with flow paths.
|
|
||||||
exists(Libxml2ParseCall call, Expr options |
|
|
||||||
options = call.getOptions() and
|
|
||||||
node.asExpr() = options and
|
|
||||||
flowstate = "libxml2" and
|
|
||||||
exists(Libxml2BadOption opt |
|
|
||||||
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
|
|
||||||
0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node, string flowstate) {
|
override predicate isSink(DataFlow::Node node, string flowstate) {
|
||||||
// sink is the read of the qualifier of a call to `parse`.
|
any(XmlLibrary l).configurationSink(node, flowstate)
|
||||||
exists(Call call |
|
|
||||||
call.getTarget() instanceof ParseFunction and
|
|
||||||
call.getQualifier() = node.asConvertedExpr()
|
|
||||||
) and
|
|
||||||
flowstate instanceof XercesFlowState and
|
|
||||||
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
|
||||||
or
|
|
||||||
// sink is the `options` argument on a `libxml2` parse call.
|
|
||||||
exists(Libxml2ParseCall call, Expr options |
|
|
||||||
options = call.getOptions() and
|
|
||||||
node.asExpr() = options and
|
|
||||||
flowstate = "libxml2"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isAdditionalFlowStep(
|
override predicate isAdditionalFlowStep(
|
||||||
DataFlow::Node node1, string state1, DataFlow::Node node2, string state2
|
DataFlow::Node node1, string state1, DataFlow::Node node2, string state2
|
||||||
) {
|
) {
|
||||||
// create additional flow steps for `XXEFlowStateTransformer`s
|
// create additional flow steps for `XxeFlowStateTransformer`s
|
||||||
state2 = node2.asConvertedExpr().(XXEFlowStateTransformer).transform(state1) and
|
state2 = node2.asConvertedExpr().(XxeFlowStateTransformer).transform(state1) and
|
||||||
DataFlow::simpleLocalFlowStep(node1, node2)
|
DataFlow::simpleLocalFlowStep(node1, node2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override predicate isBarrier(DataFlow::Node node, string flowstate) {
|
override predicate isBarrier(DataFlow::Node node, string flowstate) {
|
||||||
// when the flowstate is transformed at a call node, block the original
|
// when the flowstate is transformed at a call node, block the original
|
||||||
// flowstate value.
|
// flowstate value.
|
||||||
node.asConvertedExpr().(XXEFlowStateTransformer).transform(flowstate) != flowstate
|
node.asConvertedExpr().(XxeFlowStateTransformer).transform(flowstate) != flowstate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
376
cpp/ql/src/Security/CWE/CWE-611/Xerces.qll
Normal file
376
cpp/ql/src/Security/CWE/CWE-611/Xerces.qll
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
/**
|
||||||
|
* Models the Xerces XML library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import cpp
|
||||||
|
import XML
|
||||||
|
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||||
|
import semmle.code.cpp.ir.IR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a valid flow state for `AbstractDOMParser` or `SAXParser` flow.
|
||||||
|
*
|
||||||
|
* These flow states take the form `Xerces-A-B`, where:
|
||||||
|
* - A is 1 if `setDisableDefaultEntityResolution` is `true`, 0 otherwise.
|
||||||
|
* - B is 1 if `setCreateEntityReferenceNodes` is `true`, 0 otherwise.
|
||||||
|
*/
|
||||||
|
predicate encodeXercesFlowState(
|
||||||
|
string flowstate, int disabledDefaultEntityResolution, int createEntityReferenceNodes
|
||||||
|
) {
|
||||||
|
flowstate = "Xerces-0-0" and
|
||||||
|
disabledDefaultEntityResolution = 0 and
|
||||||
|
createEntityReferenceNodes = 0
|
||||||
|
or
|
||||||
|
flowstate = "Xerces-0-1" and
|
||||||
|
disabledDefaultEntityResolution = 0 and
|
||||||
|
createEntityReferenceNodes = 1
|
||||||
|
or
|
||||||
|
flowstate = "Xerces-1-0" and
|
||||||
|
disabledDefaultEntityResolution = 1 and
|
||||||
|
createEntityReferenceNodes = 0
|
||||||
|
or
|
||||||
|
flowstate = "Xerces-1-1" and
|
||||||
|
disabledDefaultEntityResolution = 1 and
|
||||||
|
createEntityReferenceNodes = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state representing the configuration of an `AbstractDOMParser` or
|
||||||
|
* `SAXParser` object.
|
||||||
|
*/
|
||||||
|
class XercesFlowState extends XxeFlowState {
|
||||||
|
XercesFlowState() { encodeXercesFlowState(this, _, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `AbstractDOMParser` class.
|
||||||
|
*/
|
||||||
|
class AbstractDomParserClass extends Class {
|
||||||
|
AbstractDomParserClass() { this.hasName("AbstractDOMParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `XercesDOMParser` class.
|
||||||
|
*/
|
||||||
|
class XercesDomParserClass extends Class {
|
||||||
|
XercesDomParserClass() { this.hasName("XercesDOMParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `XercesDOMParser` interface for the Xerces XML library.
|
||||||
|
*/
|
||||||
|
class XercesDomParserLibrary extends XmlLibrary {
|
||||||
|
XercesDomParserLibrary() { this = "XercesDomParserLibrary" }
|
||||||
|
|
||||||
|
override predicate configurationSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is the write on `this` of a call to the `XercesDOMParser`
|
||||||
|
// constructor.
|
||||||
|
exists(CallInstruction call |
|
||||||
|
call.getStaticCallTarget() = any(XercesDomParserClass c).getAConstructor() and
|
||||||
|
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
|
call.getThisArgument() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate configurationSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the read of the qualifier of a call to `AbstractDOMParser.parse`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().getClassAndName("parse") instanceof AbstractDomParserClass and
|
||||||
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
|
) and
|
||||||
|
flowstate instanceof XercesFlowState and
|
||||||
|
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `DOMLSParser` class.
|
||||||
|
*/
|
||||||
|
class DomLSParserClass extends Class {
|
||||||
|
DomLSParserClass() { this.hasName("DOMLSParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `createLSParser` function that returns a newly created `DOMLSParser`
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
class CreateLSParser extends Function {
|
||||||
|
CreateLSParser() {
|
||||||
|
this.hasName("createLSParser") and
|
||||||
|
this.getUnspecifiedType().(PointerType).getBaseType() instanceof DomLSParserClass // returns a `DOMLSParser *`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The createLSParser interface for the Xerces XML library.
|
||||||
|
*/
|
||||||
|
class CreateLSParserLibrary extends XmlLibrary {
|
||||||
|
CreateLSParserLibrary() { this = "CreateLSParserLibrary" }
|
||||||
|
|
||||||
|
override predicate configurationSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is the result of a call to `createLSParser`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget() instanceof CreateLSParser and
|
||||||
|
call = node.asExpr() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate configurationSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the read of the qualifier of a call to `DOMLSParserClass.parse`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().getClassAndName("parse") instanceof DomLSParserClass and
|
||||||
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
|
) and
|
||||||
|
flowstate instanceof XercesFlowState and
|
||||||
|
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `SAXParser` class.
|
||||||
|
*/
|
||||||
|
class SaxParserClass extends Class {
|
||||||
|
SaxParserClass() { this.hasName("SAXParser") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `SAX2XMLReader` class.
|
||||||
|
*/
|
||||||
|
class Sax2XmlReader extends Class {
|
||||||
|
Sax2XmlReader() { this.hasName("SAX2XMLReader") }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SAXParser interface for the Xerces XML library.
|
||||||
|
*/
|
||||||
|
class SaxParserLibrary extends XmlLibrary {
|
||||||
|
SaxParserLibrary() { this = "SaxParserLibrary" }
|
||||||
|
|
||||||
|
override predicate configurationSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is the write on `this` of a call to the `SAXParser`
|
||||||
|
// constructor.
|
||||||
|
exists(CallInstruction call |
|
||||||
|
call.getStaticCallTarget() = any(SaxParserClass c).getAConstructor() and
|
||||||
|
node.asInstruction().(WriteSideEffectInstruction).getDestinationAddress() =
|
||||||
|
call.getThisArgument() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate configurationSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the read of the qualifier of a call to `SAXParser.parse`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().getClassAndName("parse") instanceof SaxParserClass and
|
||||||
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
|
) and
|
||||||
|
flowstate instanceof XercesFlowState and
|
||||||
|
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `createXMLReader` function that returns a newly created `SAX2XMLReader`
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
class CreateXmlReader extends Function {
|
||||||
|
CreateXmlReader() {
|
||||||
|
this.hasName("createXMLReader") and
|
||||||
|
this.getUnspecifiedType().(PointerType).getBaseType() instanceof Sax2XmlReader // returns a `SAX2XMLReader *`.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SAX2XMLReader interface for the Xerces XML library.
|
||||||
|
*/
|
||||||
|
class Sax2XmlReaderLibrary extends XmlLibrary {
|
||||||
|
Sax2XmlReaderLibrary() { this = "Sax2XmlReaderLibrary" }
|
||||||
|
|
||||||
|
override predicate configurationSource(DataFlow::Node node, string flowstate) {
|
||||||
|
// source is the result of a call to `createXMLReader`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget() instanceof CreateXmlReader and
|
||||||
|
call = node.asExpr() and
|
||||||
|
encodeXercesFlowState(flowstate, 0, 1) // default configuration
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate configurationSink(DataFlow::Node node, string flowstate) {
|
||||||
|
// sink is the read of the qualifier of a call to `SAX2XMLReader.parse`.
|
||||||
|
exists(Call call |
|
||||||
|
call.getTarget().getClassAndName("parse") instanceof Sax2XmlReader and
|
||||||
|
call.getQualifier() = node.asConvertedExpr()
|
||||||
|
) and
|
||||||
|
flowstate instanceof XercesFlowState and
|
||||||
|
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to
|
||||||
|
* `AbstractDOMParser.setDisableDefaultEntityResolution` or
|
||||||
|
* `SAXParser.setDisableDefaultEntityResolution`. Transforms the flow
|
||||||
|
* state through the qualifier according to the setting in the parameter.
|
||||||
|
*/
|
||||||
|
class DisableDefaultEntityResolutionTransformer extends XxeFlowStateTransformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
DisableDefaultEntityResolutionTransformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
(
|
||||||
|
f.getDeclaringType() instanceof AbstractDomParserClass or
|
||||||
|
f.getDeclaringType() instanceof SaxParserClass
|
||||||
|
) and
|
||||||
|
f.hasName("setDisableDefaultEntityResolution") and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
newValue = call.getArgument(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XxeFlowState transform(XxeFlowState flowstate) {
|
||||||
|
exists(int createEntityReferenceNodes |
|
||||||
|
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
|
(
|
||||||
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
||||||
|
or
|
||||||
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to
|
||||||
|
* `AbstractDOMParser.setCreateEntityReferenceNodes`. Transforms the flow
|
||||||
|
* state through the qualifier according to the setting in the parameter.
|
||||||
|
*/
|
||||||
|
class CreateEntityReferenceNodesTransformer extends XxeFlowStateTransformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
CreateEntityReferenceNodesTransformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
f.getClassAndName("setCreateEntityReferenceNodes") instanceof AbstractDomParserClass and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
newValue = call.getArgument(0)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XxeFlowState transform(XxeFlowState flowstate) {
|
||||||
|
exists(int disabledDefaultEntityResolution |
|
||||||
|
encodeXercesFlowState(flowstate, disabledDefaultEntityResolution, _) and
|
||||||
|
(
|
||||||
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesFlowState(result, disabledDefaultEntityResolution, 1)
|
||||||
|
or
|
||||||
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesFlowState(result, disabledDefaultEntityResolution, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `XMLUni.fgXercesDisableDefaultEntityResolution` constant.
|
||||||
|
*/
|
||||||
|
class FeatureDisableDefaultEntityResolution extends Variable {
|
||||||
|
FeatureDisableDefaultEntityResolution() {
|
||||||
|
this.getName() = "fgXercesDisableDefaultEntityResolution" and
|
||||||
|
this.getDeclaringType().getName() = "XMLUni"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to `SAX2XMLReader.setFeature`
|
||||||
|
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
||||||
|
* Transforms the flow state through the qualifier according to this setting.
|
||||||
|
*/
|
||||||
|
class SetFeatureTransformer extends XxeFlowStateTransformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
SetFeatureTransformer() {
|
||||||
|
exists(Call call, Function f |
|
||||||
|
call.getTarget() = f and
|
||||||
|
f.getClassAndName("setFeature") instanceof Sax2XmlReader and
|
||||||
|
this = call.getQualifier() and
|
||||||
|
globalValueNumber(call.getArgument(0)).getAnExpr().(VariableAccess).getTarget() instanceof
|
||||||
|
FeatureDisableDefaultEntityResolution and
|
||||||
|
newValue = call.getArgument(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XxeFlowState transform(XxeFlowState flowstate) {
|
||||||
|
exists(int createEntityReferenceNodes |
|
||||||
|
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
|
(
|
||||||
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
||||||
|
or
|
||||||
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `DOMLSParser.getDomConfig` function.
|
||||||
|
*/
|
||||||
|
class GetDomConfig extends Function {
|
||||||
|
GetDomConfig() { this.getClassAndName("getDomConfig") instanceof DomLSParserClass }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `DOMConfiguration.setParameter` function.
|
||||||
|
*/
|
||||||
|
class DomConfigurationSetParameter extends Function {
|
||||||
|
DomConfigurationSetParameter() {
|
||||||
|
this.getClassAndName("setParameter").getName() = "DOMConfiguration"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flow state transformer for a call to `DOMConfiguration.setParameter`
|
||||||
|
* specifying the feature `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
||||||
|
* This is a slightly more complex transformer because the qualifier is a
|
||||||
|
* `DOMConfiguration` pointer returned by `DOMLSParser.getDomConfig` - and it
|
||||||
|
* is *that* qualifier we want to transform the flow state of.
|
||||||
|
*/
|
||||||
|
class DomConfigurationSetParameterTransformer extends XxeFlowStateTransformer {
|
||||||
|
Expr newValue;
|
||||||
|
|
||||||
|
DomConfigurationSetParameterTransformer() {
|
||||||
|
exists(FunctionCall getDomConfigCall, FunctionCall setParameterCall |
|
||||||
|
// this is the qualifier of a call to `DOMLSParser.getDomConfig`.
|
||||||
|
getDomConfigCall.getTarget() instanceof GetDomConfig and
|
||||||
|
this = getDomConfigCall.getQualifier() and
|
||||||
|
// `setParameterCall` is a call to `setParameter` on the return value of
|
||||||
|
// the same call to `DOMLSParser.getDomConfig`.
|
||||||
|
setParameterCall.getTarget() instanceof DomConfigurationSetParameter and
|
||||||
|
globalValueNumber(setParameterCall.getQualifier()).getAnExpr() = getDomConfigCall and
|
||||||
|
// the parameter being set is
|
||||||
|
// `XMLUni::fgXercesDisableDefaultEntityResolution`.
|
||||||
|
globalValueNumber(setParameterCall.getArgument(0)).getAnExpr().(VariableAccess).getTarget()
|
||||||
|
instanceof FeatureDisableDefaultEntityResolution and
|
||||||
|
// the value being set is `newValue`.
|
||||||
|
newValue = setParameterCall.getArgument(1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
final override XxeFlowState transform(XxeFlowState flowstate) {
|
||||||
|
exists(int createEntityReferenceNodes |
|
||||||
|
encodeXercesFlowState(flowstate, _, createEntityReferenceNodes) and
|
||||||
|
(
|
||||||
|
globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // true
|
||||||
|
encodeXercesFlowState(result, 1, createEntityReferenceNodes)
|
||||||
|
or
|
||||||
|
not globalValueNumber(newValue).getAnExpr().getValue().toInt() = 1 and // false or unknown
|
||||||
|
encodeXercesFlowState(result, 0, createEntityReferenceNodes)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user