From 3a8551e70630c399c5da63dc26bf6bfc5b326cd0 Mon Sep 17 00:00:00 2001 From: "Benjamin A. Beasley" Date: Wed, 8 Mar 2023 09:09:29 -0500 Subject: [PATCH] =?UTF-8?q?Backport=20upstream=20PR#863=20(=E2=80=9Cuse=20?= =?UTF-8?q?only=20lxml=20for=20XML=20handling=E2=80=9D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fixes CVE-2023-27476 https://nvd.nist.gov/vuln/detail/CVE-2023-27476 - Fixes GHSA-8h9c-r582-mggc https://github.com/geopython/OWSLib/security/advisories/GHSA-8h9c-r582-mggc - Fixes RHBZ#2176417 https://bugzilla.redhat.com/show_bug.cgi?id=2176417 --- 0001-use-only-lxml-for-XML-handling.patch | 232 ++++++++++++++++++++++ python-OWSLib.spec | 13 +- 2 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 0001-use-only-lxml-for-XML-handling.patch diff --git a/0001-use-only-lxml-for-XML-handling.patch b/0001-use-only-lxml-for-XML-handling.patch new file mode 100644 index 0000000..0e5e450 --- /dev/null +++ b/0001-use-only-lxml-for-XML-handling.patch @@ -0,0 +1,232 @@ +From 2f81f2b36c01b2a32e8dcf6b2c695b36b1eb0b8f Mon Sep 17 00:00:00 2001 +From: Tom Kralidis +Date: Fri, 24 Feb 2023 10:15:35 -0500 +Subject: [PATCH] use only lxml for XML handling + +Backport of PR#863 (https://github.com/geopython/OWSLib/pull/863) to 0.9.2 +--- + owslib/etree.py | 58 ++++++++--------------------- + owslib/util.py | 96 ++++++++++++++++++------------------------------ + requirements.txt | 1 + + 3 files changed, 52 insertions(+), 103 deletions(-) + +diff --git a/owslib/etree.py b/owslib/etree.py +index b8babe8..88ae7ab 100644 +--- a/owslib/etree.py ++++ b/owslib/etree.py +@@ -6,9 +6,15 @@ + + from __future__ import (absolute_import, division, print_function) + import six +-import inspect + +-def patch_well_known_namespaces(etree_module): ++from lxml import etree ++from lxml.etree import ParseError ++ElementType = etree._Element ++ ++from owslib.namespaces import Namespaces ++ ++def patch_well_known_namespaces(): ++ """Monkey patches lxml.etree to add some well-known namespaces.""" + + import warnings + from owslib.namespaces import Namespaces +@@ -17,50 +23,18 @@ def patch_well_known_namespaces(etree_module): + """Monkey patches the etree module to add some well-known namespaces.""" + + try: +- register_namespace = etree_module.register_namespace ++ register_namespace = etree.register_namespace + except AttributeError: +- try: +- etree_module._namespace_map ++ etree._namespace_map + +- def register_namespace(prefix, uri): +- etree_module._namespace_map[uri] = prefix +- except AttributeError: +- def register_namespace(prefix, uri): +- pass +- warnings.warn("Only 'lxml.etree' >= 2.3 and 'xml.etree.ElementTree' >= 1.3 are fully supported!") ++ def register_namespace(prefix, uri): ++ etree._namespace_map[uri] = prefix + + for k, v in six.iteritems(ns.get_namespaces()): + register_namespace(k, v) + +-# try to find lxml or elementtree +-try: +- from lxml import etree +- from lxml.etree import ParseError +- ElementType = etree._Element +-except ImportError: +- try: +- # Python 2.x/3.x with ElementTree included +- import xml.etree.ElementTree as etree +- +- try: +- from xml.etree.ElementTree import ParseError +- except ImportError: +- from xml.parsers.expat import ExpatError as ParseError +- +- if hasattr(etree, 'Element') and inspect.isclass(etree.Element): +- # python 3.4, 3.3, 2.7 +- ElementType = etree.Element +- else: +- # python 2.6 +- ElementType = etree._ElementInterface +- +- except ImportError: +- try: +- # Python < 2.5 with ElementTree installed +- import elementtree.ElementTree as etree +- ParseError = StandardError # i can't find a ParseError related item in elementtree docs! +- ElementType = etree.Element +- except ImportError: +- raise RuntimeError('You need either lxml or ElementTree to use OWSLib!') ++ etree.set_default_parser( ++ parser=etree.XMLParser(resolve_entities=False) ++ ) + +-patch_well_known_namespaces(etree) ++patch_well_known_namespaces() +diff --git a/owslib/util.py b/owslib/util.py +index 22bcaa7..51ce6d0 100644 +--- a/owslib/util.py ++++ b/owslib/util.py +@@ -239,11 +239,8 @@ def nspath_eval(xpath, namespaces): + + def cleanup_namespaces(element): + """ Remove unused namespaces from an element """ +- if etree.__name__ == 'lxml.etree': +- etree.cleanup_namespaces(element) +- return element +- else: +- return etree.fromstring(etree.tostring(element)) ++ etree.cleanup_namespaces(element) ++ return element + + + def add_namespaces(root, ns_keys): +@@ -254,35 +251,34 @@ def add_namespaces(root, ns_keys): + + ns_keys = [(x, namespaces.get_namespace(x)) for x in ns_keys] + +- if etree.__name__ != 'lxml.etree': +- # We can just add more namespaces when not using lxml. +- # We can't re-add an existing namespaces. Get a list of current +- # namespaces in use +- existing_namespaces = set() +- for elem in root.getiterator(): +- if elem.tag[0] == "{": +- uri, tag = elem.tag[1:].split("}") +- existing_namespaces.add(namespaces.get_namespace_from_url(uri)) +- for key, link in ns_keys: +- if link is not None and key not in existing_namespaces: +- root.set("xmlns:%s" % key, link) +- return root +- else: +- # lxml does not support setting xmlns attributes +- # Update the elements nsmap with new namespaces +- new_map = root.nsmap +- for key, link in ns_keys: +- if link is not None: +- new_map[key] = link +- # Recreate the root element with updated nsmap +- new_root = etree.Element(root.tag, nsmap=new_map) +- # Carry over attributes +- for a, v in list(root.items()): +- new_root.set(a, v) +- # Carry over children +- for child in root: +- new_root.append(deepcopy(child)) +- return new_root ++ # lxml does not support setting xmlns attributes ++ # Update the elements nsmap with new namespaces ++ new_map = root.nsmap ++ for key, link in ns_keys: ++ if link is not None: ++ new_map[key] = link ++ # Recreate the root element with updated nsmap ++ new_root = etree.Element(root.tag, nsmap=new_map) ++ # Carry over attributes ++ for a, v in list(root.items()): ++ new_root.set(a, v) ++ # Carry over children ++ for child in root: ++ new_root.append(deepcopy(child)) ++ return new_root ++ ++ # We can just add more namespaces when not using lxml. ++ # We can't re-add an existing namespaces. Get a list of current ++ # namespaces in use ++ existing_namespaces = set() ++ for elem in root.iter(): ++ if elem.tag[0] == "{": ++ uri, tag = elem.tag[1:].split("}") ++ existing_namespaces.add(namespaces.get_namespace_from_url(uri)) ++ for key, link in ns_keys: ++ if link is not None and key not in existing_namespaces: ++ root.set("xmlns:%s" % key, link) ++ return root + + + def getXMLInteger(elem, tag): +@@ -401,20 +397,13 @@ def element_to_string(element, encoding=None, xml_declaration=False): + if encoding is None: + encoding = "ISO-8859-1" + +- if etree.__name__ == 'lxml.etree': +- if xml_declaration: +- if encoding in ['unicode', 'utf-8']: +- output = '\n%s' % \ +- etree.tostring(element, encoding='unicode') +- else: +- output = etree.tostring(element, encoding=encoding, xml_declaration=True) ++ if xml_declaration: ++ if encoding in ['unicode', 'utf-8']: ++ output = '\n%s' % \ ++ etree.tostring(element, encoding='unicode') + else: +- output = etree.tostring(element) ++ output = etree.tostring(element, encoding=encoding, xml_declaration=True) + else: +- if xml_declaration: +- output = '\n%s' % (encoding, +- etree.tostring(element, encoding=encoding)) +- else: + output = etree.tostring(element) + + return output +@@ -581,18 +570,3 @@ try: # 2.7 + from collections import OrderedDict + except: # 2.6 + from ordereddict import OrderedDict +- +- +-def which_etree(): +- """decipher which etree library is being used by OWSLib""" +- +- which_etree = None +- +- if 'lxml' in etree.__file__: +- which_etree = 'lxml.etree' +- elif 'xml/etree' in etree.__file__: +- which_etree = 'xml.etree' +- elif 'elementree' in etree.__file__: +- which_etree = 'elementtree.ElementTree' +- +- return which_etree +diff --git a/requirements.txt b/requirements.txt +index 7689a61..10ad5db 100644 +--- a/requirements.txt ++++ b/requirements.txt +@@ -1,3 +1,4 @@ ++lxml + python-dateutil>=1.5 + pytz + requests>=1.0 +-- +2.39.2 + diff --git a/python-OWSLib.spec b/python-OWSLib.spec index 5c69cf3..e058d1f 100644 --- a/python-OWSLib.spec +++ b/python-OWSLib.spec @@ -13,6 +13,13 @@ URL: http://geopython.github.io/OWSLib %global forgeurl https://github.com/geopython/OWSLib Source0: %{forgeurl}/archive/%{version}/OWSLib-%{version}.tar.gz +# use only lxml for XML handling +# Backport of PR#863 (https://github.com/geopython/OWSLib/pull/863) to 0.9.2 +# Fixes: CVE-2023-27476 https://nvd.nist.gov/vuln/detail/CVE-2023-27476 +# GHSA-8h9c-r582-mggc https://github.com/geopython/OWSLib/security/advisories/GHSA-8h9c-r582-mggc +# RHBZ#2176417 https://bugzilla.redhat.com/show_bug.cgi?id=2176417 +Patch0: 0001-use-only-lxml-for-XML-handling.patch + BuildArch: noarch %global common_description %{expand: @@ -35,11 +42,13 @@ BuildRequires: python2-dateutil >= 1.5 BuildRequires: python2-requests >= 1.0 BuildRequires: python2-pytz BuildRequires: pyproj +BuildRequires: python-lxml Requires: python2-dateutil >= 1.5 Requires: python2-requests >= 1.0 Requires: python2-pytz Requires: python2-pyproj +Requires: python-lxml %description -n python2-OWSLib %{common_description} @@ -58,18 +67,20 @@ BuildRequires: python%{python3_pkgversion}-dateutil >= 1.5 BuildRequires: python%{python3_pkgversion}-requests >= 1.0 BuildRequires: python%{python3_pkgversion}-pytz BuildRequires: python%{python3_pkgversion}-pyproj +BuildRequires: python%{python3_pkgversion}-lxml Requires: python%{python3_pkgversion}-dateutil >= 1.5 Requires: python%{python3_pkgversion}-requests >= 1.0 Requires: python%{python3_pkgversion}-pytz Requires: python%{python3_pkgversion}-pyproj +Requires: python%{python3_pkgversion}-lxml %description -n python%{python3_pkgversion}-OWSLib %{common_description} %endif %prep -%autosetup -n OWSLib-%{version} +%autosetup -n OWSLib-%{version} -p1 rm -rf OWSLib.egg-info # Remove shebangs from non-script sources. The find-then-modify pattern