mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #9018 from geoffw0/xxe5
C++: Support libxml2 in the XXE query
This commit is contained in:
@@ -188,6 +188,42 @@ class CreateLSParser extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -219,6 +255,23 @@ class XXEConfiguration extends DataFlow::Configuration {
|
||||
call.getThisArgument() 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) {
|
||||
@@ -229,6 +282,13 @@ class XXEConfiguration extends DataFlow::Configuration {
|
||||
) 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(
|
||||
|
||||
@@ -33,6 +33,11 @@ nodes
|
||||
| tests2.cpp:22:2:22:2 | p | semmle.label | p |
|
||||
| tests2.cpp:33:17:33:31 | SAXParser output argument | semmle.label | SAXParser output argument |
|
||||
| tests2.cpp:37:2:37:2 | p | semmle.label | p |
|
||||
| tests4.cpp:26:34:26:48 | (int)... | semmle.label | (int)... |
|
||||
| tests4.cpp:36:34:36:50 | (int)... | semmle.label | (int)... |
|
||||
| tests4.cpp:46:34:46:68 | ... \| ... | semmle.label | ... \| ... |
|
||||
| tests4.cpp:77:34:77:38 | flags | semmle.label | flags |
|
||||
| tests4.cpp:130:39:130:55 | (int)... | semmle.label | (int)... |
|
||||
| tests.cpp:33:23:33:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||
| tests.cpp:35:2:35:2 | p | semmle.label | p |
|
||||
| tests.cpp:46:23:46:43 | XercesDOMParser output argument | semmle.label | XercesDOMParser output argument |
|
||||
@@ -74,6 +79,11 @@ subpaths
|
||||
#select
|
||||
| tests2.cpp:22:2:22:2 | p | tests2.cpp:20:17:20:31 | SAXParser output argument | tests2.cpp:22:2:22:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:20:17:20:31 | SAXParser output argument | XML parser |
|
||||
| tests2.cpp:37:2:37:2 | p | tests2.cpp:33:17:33:31 | SAXParser output argument | tests2.cpp:37:2:37:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests2.cpp:33:17:33:31 | SAXParser output argument | XML parser |
|
||||
| tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | tests4.cpp:26:34:26:48 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:26:34:26:48 | (int)... | XML parser |
|
||||
| tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | tests4.cpp:36:34:36:50 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:36:34:36:50 | (int)... | XML parser |
|
||||
| tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | tests4.cpp:46:34:46:68 | ... \| ... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:46:34:46:68 | ... \| ... | XML parser |
|
||||
| tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | tests4.cpp:77:34:77:38 | flags | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:77:34:77:38 | flags | XML parser |
|
||||
| tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | tests4.cpp:130:39:130:55 | (int)... | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests4.cpp:130:39:130:55 | (int)... | XML parser |
|
||||
| tests.cpp:35:2:35:2 | p | tests.cpp:33:23:33:43 | XercesDOMParser output argument | tests.cpp:35:2:35:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:33:23:33:43 | XercesDOMParser output argument | XML parser |
|
||||
| tests.cpp:49:2:49:2 | p | tests.cpp:46:23:46:43 | XercesDOMParser output argument | tests.cpp:49:2:49:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:46:23:46:43 | XercesDOMParser output argument | XML parser |
|
||||
| tests.cpp:57:2:57:2 | p | tests.cpp:53:23:53:43 | XercesDOMParser output argument | tests.cpp:57:2:57:2 | p | This $@ is not configured to prevent an XML external entity (XXE) attack. | tests.cpp:53:23:53:43 | XercesDOMParser output argument | XML parser |
|
||||
|
||||
@@ -2,3 +2,5 @@
|
||||
|
||||
class SecurityManager;
|
||||
class InputSource;
|
||||
|
||||
#define NULL (0)
|
||||
|
||||
135
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests4.cpp
Normal file
135
cpp/ql/test/query-tests/Security/CWE/CWE-611/tests4.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// test cases for rule CWE-611 (libxml2)
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
// ---
|
||||
|
||||
enum xmlParserOption
|
||||
{
|
||||
XML_PARSE_NOENT = 2,
|
||||
XML_PARSE_DTDLOAD = 4,
|
||||
XML_PARSE_OPTION_HARMLESS = 8
|
||||
};
|
||||
|
||||
class xmlDoc;
|
||||
|
||||
xmlDoc *xmlReadFile(const char *fileName, const char *encoding, int flags);
|
||||
xmlDoc *xmlReadMemory(const char *ptr, int sz, const char *url, const char *encoding, int flags);
|
||||
|
||||
void xmlFreeDoc(xmlDoc *ptr);
|
||||
|
||||
// ---
|
||||
|
||||
void test4_1(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, XML_PARSE_NOENT); // BAD (parser not correctly configured)
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_2(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_3(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_4(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, 0); // GOOD
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_5(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, XML_PARSE_OPTION_HARMLESS); // GOOD
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_6(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
int flags = XML_PARSE_NOENT;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, flags); // BAD (parser not correctly configured)
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_7(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
int flags = 0;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, flags); // GOOD
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_8(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
int flags = XML_PARSE_OPTION_HARMLESS;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, flags | XML_PARSE_NOENT); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_9(const char *fileName) {
|
||||
xmlDoc *p;
|
||||
int flags = XML_PARSE_NOENT;
|
||||
|
||||
p = xmlReadFile(fileName, NULL, flags | XML_PARSE_OPTION_HARMLESS); // BAD (parser not correctly configured) [NOT DETECTED]
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_10(const char *ptr, int sz) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadMemory(ptr, sz, "", NULL, 0); // GOOD
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
|
||||
void test4_11(const char *ptr, int sz) {
|
||||
xmlDoc *p;
|
||||
|
||||
p = xmlReadMemory(ptr, sz, "", NULL, XML_PARSE_DTDLOAD); // BAD (parser not correctly configured)
|
||||
if (p != NULL)
|
||||
{
|
||||
xmlFreeDoc(p);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user