Skip to content

Commit 629e90f

Browse files
authored
Merge pull request #9176 from geoffw0/xxe9
C++: Clean up the XXE query QL.
2 parents fcb3b82 + 246093d commit 629e90f

File tree

4 files changed

+515
-402
lines changed

4 files changed

+515
-402
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* Models the libxml2 XML library.
3+
*/
4+
5+
import cpp
6+
import XML
7+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
8+
9+
/**
10+
* A call to a `libxml2` function that parses XML.
11+
*/
12+
class Libxml2ParseCall extends FunctionCall {
13+
int optionsArg;
14+
15+
Libxml2ParseCall() {
16+
exists(string fname | this.getTarget().getName() = fname |
17+
fname = "xmlCtxtUseOptions" and optionsArg = 1
18+
or
19+
fname = "xmlReadFile" and optionsArg = 2
20+
or
21+
fname = ["xmlCtxtReadFile", "xmlParseInNodeContext", "xmlReadDoc", "xmlReadFd"] and
22+
optionsArg = 3
23+
or
24+
fname = ["xmlCtxtReadDoc", "xmlCtxtReadFd", "xmlReadMemory"] and optionsArg = 4
25+
or
26+
fname = ["xmlCtxtReadMemory", "xmlReadIO"] and optionsArg = 5
27+
or
28+
fname = "xmlCtxtReadIO" and optionsArg = 6
29+
)
30+
}
31+
32+
/**
33+
* Gets the argument that specifies `xmlParserOption`s.
34+
*/
35+
Expr getOptions() { result = this.getArgument(optionsArg) }
36+
}
37+
38+
/**
39+
* An `xmlParserOption` for `libxml2` that is considered unsafe.
40+
*/
41+
class Libxml2BadOption extends EnumConstant {
42+
Libxml2BadOption() { this.getName() = ["XML_PARSE_NOENT", "XML_PARSE_DTDLOAD"] }
43+
}
44+
45+
/**
46+
* The libxml2 XML library.
47+
*/
48+
class LibXml2Library extends XmlLibrary {
49+
LibXml2Library() { this = "LibXml2Library" }
50+
51+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
52+
// source is an `options` argument on a libxml2 parse call that specifies
53+
// at least one unsafe option.
54+
//
55+
// note: we don't need to track an XML object for libxml2, so we don't
56+
// really need data flow. Nevertheless we jam it into this configuration,
57+
// with matching sources and sinks. This allows results to be presented by
58+
// the same query, in a consistent way as other results with flow paths.
59+
exists(Libxml2ParseCall call, Expr options |
60+
options = call.getOptions() and
61+
node.asExpr() = options and
62+
flowstate = "libxml2" and
63+
exists(Libxml2BadOption opt |
64+
globalValueNumber(options).getAnExpr().getValue().toInt().bitAnd(opt.getValue().toInt()) !=
65+
0
66+
)
67+
)
68+
}
69+
70+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
71+
// sink is the `options` argument on a `libxml2` parse call.
72+
exists(Libxml2ParseCall call, Expr options |
73+
options = call.getOptions() and
74+
node.asExpr() = options and
75+
flowstate = "libxml2"
76+
)
77+
}
78+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Provides a abstract classes for modeling XML libraries. This design is
3+
* currently specialized for the purposes of the XXE query.
4+
*/
5+
6+
import cpp
7+
import semmle.code.cpp.ir.dataflow.DataFlow
8+
import Xerces
9+
import Libxml2
10+
11+
/**
12+
* A flow state representing a possible configuration of an XML object.
13+
*/
14+
abstract class XxeFlowState extends DataFlow::FlowState {
15+
bindingset[this]
16+
XxeFlowState() { any() } // required characteristic predicate
17+
}
18+
19+
/**
20+
* An XML library or interface.
21+
*/
22+
abstract class XmlLibrary extends string {
23+
bindingset[this]
24+
XmlLibrary() { any() } // required characteristic predicate
25+
26+
/**
27+
* Holds if `node` is the source node for a potentially unsafe configuration
28+
* object for this XML library, along with `flowstate` representing its
29+
* initial state.
30+
*/
31+
abstract predicate configurationSource(DataFlow::Node node, string flowstate);
32+
33+
/**
34+
* Holds if `node` is the sink node where an unsafe configuration object is
35+
* used to interpret XML.
36+
*/
37+
abstract predicate configurationSink(DataFlow::Node node, string flowstate);
38+
}
39+
40+
/**
41+
* An `Expr` that changes the configuration of an XML object, transforming the
42+
* `XxeFlowState` that flows through it.
43+
*/
44+
abstract class XxeFlowStateTransformer extends Expr {
45+
/**
46+
* Gets the flow state that `flowstate` is transformed into.
47+
*
48+
* Due to limitations of the implementation the transformation defined by this
49+
* predicate must be idempotent, that is, for any input `x` it must be that:
50+
* ```
51+
* transform(transform(x)) = transform(x)
52+
* ```
53+
*/
54+
abstract XxeFlowState transform(XxeFlowState flowstate);
55+
}

0 commit comments

Comments
 (0)