diff options
author | Dan Prince <dprince@redhat.com> | 2013-02-01 17:04:27 -0500 |
---|---|---|
committer | Dan Prince <dprince@redhat.com> | 2013-02-19 09:12:01 -0500 |
commit | 59933249054bf71ec963585198583fe78050c9d6 (patch) | |
tree | ebc4eb8b5f6cef1b3452a47985acaa480e40efc8 /nova/utils.py | |
parent | 1b9b66ba210c1dd886a95d79e5621e13fb64aa3a (diff) | |
download | nova-59933249054bf71ec963585198583fe78050c9d6.tar.gz nova-59933249054bf71ec963585198583fe78050c9d6.tar.xz nova-59933249054bf71ec963585198583fe78050c9d6.zip |
Add a safe_minidom_parse_string function.
Adds a new utils.safe_minidom_parse_string function and
updates external API facing Nova modules to use it.
This ensures we have safe defaults on our incoming API XML parsing.
Internally safe_minidom_parse_string uses a ProtectedExpatParser
class to disable DTDs and entities from being parsed when using
minidom.
Fixes LP Bug #1100282.
Change-Id: Ib90d6379320ff1d007f8a661f7ddaa286ba6918e
Diffstat (limited to 'nova/utils.py')
-rw-r--r-- | nova/utils.py | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/nova/utils.py b/nova/utils.py index 126e3c7e4..ac658cd5e 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -36,6 +36,10 @@ import struct import sys import tempfile import time +from xml.dom import minidom +from xml.parsers import expat +from xml import sax +from xml.sax import expatreader from xml.sax import saxutils from eventlet import event @@ -652,6 +656,46 @@ class DynamicLoopingCall(LoopingCallBase): return self.done +class ProtectedExpatParser(expatreader.ExpatParser): + """An expat parser which disables DTD's and entities by default.""" + + def __init__(self, forbid_dtd=True, forbid_entities=True, + *args, **kwargs): + # Python 2.x old style class + expatreader.ExpatParser.__init__(self, *args, **kwargs) + self.forbid_dtd = forbid_dtd + self.forbid_entities = forbid_entities + + def start_doctype_decl(self, name, sysid, pubid, has_internal_subset): + raise ValueError("Inline DTD forbidden") + + def entity_decl(self, entityName, is_parameter_entity, value, base, + systemId, publicId, notationName): + raise ValueError("<!ENTITY> forbidden") + + def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): + # expat 1.2 + raise ValueError("<!ENTITY> forbidden") + + def reset(self): + expatreader.ExpatParser.reset(self) + if self.forbid_dtd: + self._parser.StartDoctypeDeclHandler = self.start_doctype_decl + if self.forbid_entities: + self._parser.EntityDeclHandler = self.entity_decl + self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl + + +def safe_minidom_parse_string(xml_string): + """Parse an XML string using minidom safely. + + """ + try: + return minidom.parseString(xml_string, parser=ProtectedExpatParser()) + except sax.SAXParseException as se: + raise expat.ExpatError() + + def xhtml_escape(value): """Escapes a string so it is valid within XML or XHTML. |