From 05ee790f4d1cd8725a90b54268fc1dfe5b4d1fa2 Mon Sep 17 00:00:00 2001 From: Ronald Oussoren Date: Mon, 19 Oct 2020 20:13:49 +0200 Subject: [PATCH] bpo-42051: Reject XML entity declarations in plist files (#22760) --- Lib/plistlib.py | 7 +++++++ Lib/test/test_plistlib.py | 18 ++++++++++++++++++ .../2020-10-19-10-56-27.bpo-42051.EU_B7u.rst | 3 +++ 3 files changed, 28 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2020-10-19-10-56-27.bpo-42051.EU_B7u.rst Backport: * Drop Misc/NEWS.d * plistlib.py: * Handle cAmElCaSe vs under_scores * self.parser vs parser * Degrade InvalidFileException to ValueError * test_plistlib.py: * Update hunk context * Drop b"" prefix * Degrade InvalidFileException to ValueError * Adapt parser invocation to older API * Reimplement assertRaisesRegexp diff --git a/Lib/plistlib.py b/Lib/plistlib.py index aff5fe36ca..ba7ac19364 100644 --- a/Lib/plistlib.py +++ b/Lib/plistlib.py @@ -173,9 +173,16 @@ def parse(self, fileobj): parser.StartElementHandler = self.handleBeginElement parser.EndElementHandler = self.handleEndElement parser.CharacterDataHandler = self.handleData + parser.EntityDeclHandler = self.handleEntityDecl parser.ParseFile(fileobj) return self.root + def handleEntityDecl(self, entity_name, is_parameter_entity, value, base, system_id, public_id, notation_name): + # Reject plist files with entity declarations to avoid XML vulnerabilies in expat. + # Regular plist files don't contain those declerations, and Apple's plutil tool does not + # accept them either. + raise ValueError("XML entity declarations are not supported in plist files") + def handleBeginElement(self, element, attrs): self.data = [] handler = getattr(self, "begin_" + element, None) diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py index e5c9b5b6b2..cb071da1f3 100644 --- a/Lib/test/test_plistlib.py +++ b/Lib/test/test_plistlib.py @@ -106,6 +106,19 @@ """.replace(" " * 8, "\t") # Apple as well as plistlib.py output hard tabs +XML_PLIST_WITH_ENTITY='''\ + + + ]> + + + A + &entity; + + +''' + class TestPlistlib(unittest.TestCase): @@ -524,6 +537,15 @@ def test_modified_uid_huge(self): self.assertEqual(test1, result1) self.assertEqual(test2, result2) + def test_xml_plist_with_entity_decl(self): + try: + plistlib.readPlistFromString(XML_PLIST_WITH_ENTITY) + except ValueError as e: + self.assertIn("XML entity declarations are not supported", + e.message) + else: + self.fail("expected ValueError to be raised") + def test_main(): test_support.run_unittest(TestPlistlib) -- 2.40.1