Skip to content

Commit 0ffd0b2

Browse files
committed
C++: Create an XmlLibrary class to clean up the code in XXE.ql.
1 parent a9f6d20 commit 0ffd0b2

File tree

1 file changed

+104
-19
lines changed
  • cpp/ql/src/Security/CWE/CWE-611

1 file changed

+104
-19
lines changed

cpp/ql/src/Security/CWE/CWE-611/XXE.ql

Lines changed: 104 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,32 @@ class Libxml2BadOption extends EnumConstant {
353353
}
354354

355355
/**
356-
* A configuration for tracking XML objects and their states.
356+
* An XML library or interface.
357357
*/
358-
class XXEConfiguration extends DataFlow::Configuration {
359-
XXEConfiguration() { this = "XXEConfiguration" }
358+
abstract class XmlLibrary extends string {
359+
bindingset[this]
360+
XmlLibrary() { any() } // required characteristic predicate
360361

361-
override predicate isSource(DataFlow::Node node, string flowstate) {
362+
/**
363+
* The source node for a potentially unsafe configuration object for this XML
364+
* library, along with `flowstate` representing its initial state.
365+
*/
366+
abstract predicate configurationSource(DataFlow::Node node, string flowstate);
367+
368+
/**
369+
* The sink node where an unsafe configuration object is used to interpret
370+
* XML.
371+
*/
372+
abstract predicate configurationSink(DataFlow::Node node, string flowstate);
373+
}
374+
375+
/**
376+
* The `XercesDOMParser` interface for the Xerces XML library.
377+
*/
378+
class XercesDomParserLibrary extends XmlLibrary {
379+
XercesDomParserLibrary() { this = "XercesDomParserLibrary" }
380+
381+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
362382
// source is the write on `this` of a call to the `XercesDOMParser`
363383
// constructor.
364384
exists(CallInstruction call |
@@ -367,14 +387,46 @@ class XXEConfiguration extends DataFlow::Configuration {
367387
call.getThisArgument() and
368388
encodeXercesFlowState(flowstate, 0, 1) // default configuration
369389
)
370-
or
390+
}
391+
392+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
393+
// sink is the read of the qualifier of a call to `parse`.
394+
exists(Call call |
395+
call.getTarget() instanceof ParseFunction and
396+
call.getQualifier() = node.asConvertedExpr()
397+
) and
398+
flowstate instanceof XercesFlowState and
399+
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
400+
}
401+
}
402+
403+
/**
404+
* The createLSParser interface for the Xerces XML library.
405+
*/
406+
class CreateLSParserLibrary extends XmlLibrary {
407+
CreateLSParserLibrary() { this = "CreateLSParserLibrary" }
408+
409+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
371410
// source is the result of a call to `createLSParser`.
372411
exists(Call call |
373412
call.getTarget() instanceof CreateLSParser and
374413
call = node.asExpr() and
375414
encodeXercesFlowState(flowstate, 0, 1) // default configuration
376415
)
377-
or
416+
}
417+
418+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
419+
none() // uses the existing sinks from `XercesDomParserLibrary`
420+
}
421+
}
422+
423+
/**
424+
* The SAXParser interface for the Xerces XML library.
425+
*/
426+
class SaxParserLibrary extends XmlLibrary {
427+
SaxParserLibrary() { this = "SaxParserLibrary" }
428+
429+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
378430
// source is the write on `this` of a call to the `SAXParser`
379431
// constructor.
380432
exists(CallInstruction call |
@@ -383,18 +435,44 @@ class XXEConfiguration extends DataFlow::Configuration {
383435
call.getThisArgument() and
384436
encodeXercesFlowState(flowstate, 0, 1) // default configuration
385437
)
386-
or
438+
}
439+
440+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
441+
none() // uses the existing sinks from `XercesDomParserLibrary`
442+
}
443+
}
444+
445+
/**
446+
* The SAX2XMLReader interface for the Xerces XML library.
447+
*/
448+
class Sax2XmlReaderLibrary extends XmlLibrary {
449+
Sax2XmlReaderLibrary() { this = "Sax2XmlReaderLibrary" }
450+
451+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
387452
// source is the result of a call to `createXMLReader`.
388453
exists(Call call |
389454
call.getTarget() instanceof CreateXmlReader and
390455
call = node.asExpr() and
391456
encodeXercesFlowState(flowstate, 0, 1) // default configuration
392457
)
393-
or
394-
// source is an `options` argument on a `libxml2` parse call that specifies
458+
}
459+
460+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
461+
none() // uses the existing sinks from `XercesDomParserLibrary`
462+
}
463+
}
464+
465+
/**
466+
* The libxml2 XML library.
467+
*/
468+
class LibXml2Library extends XmlLibrary {
469+
LibXml2Library() { this = "LibXml2Library" }
470+
471+
override predicate configurationSource(DataFlow::Node node, string flowstate) {
472+
// source is an `options` argument on a libxml2 parse call that specifies
395473
// at least one unsafe option.
396474
//
397-
// note: we don't need to track an XML object for `libxml2`, so we don't
475+
// note: we don't need to track an XML object for libxml2, so we don't
398476
// really need data flow. Nevertheless we jam it into this configuration,
399477
// with matching sources and sinks. This allows results to be presented by
400478
// the same query, in a consistent way as other results with flow paths.
@@ -409,22 +487,29 @@ class XXEConfiguration extends DataFlow::Configuration {
409487
)
410488
}
411489

412-
override predicate isSink(DataFlow::Node node, string flowstate) {
413-
// sink is the read of the qualifier of a call to `parse`.
414-
exists(Call call |
415-
call.getTarget() instanceof ParseFunction and
416-
call.getQualifier() = node.asConvertedExpr()
417-
) and
418-
flowstate instanceof XercesFlowState and
419-
not encodeXercesFlowState(flowstate, 1, 1) // safe configuration
420-
or
490+
override predicate configurationSink(DataFlow::Node node, string flowstate) {
421491
// sink is the `options` argument on a `libxml2` parse call.
422492
exists(Libxml2ParseCall call, Expr options |
423493
options = call.getOptions() and
424494
node.asExpr() = options and
425495
flowstate = "libxml2"
426496
)
427497
}
498+
}
499+
500+
/**
501+
* A configuration for tracking XML objects and their states.
502+
*/
503+
class XXEConfiguration extends DataFlow::Configuration {
504+
XXEConfiguration() { this = "XXEConfiguration" }
505+
506+
override predicate isSource(DataFlow::Node node, string flowstate) {
507+
any(XmlLibrary l).configurationSource(node, flowstate)
508+
}
509+
510+
override predicate isSink(DataFlow::Node node, string flowstate) {
511+
any(XmlLibrary l).configurationSink(node, flowstate)
512+
}
428513

429514
override predicate isAdditionalFlowStep(
430515
DataFlow::Node node1, string state1, DataFlow::Node node2, string state2

0 commit comments

Comments
 (0)