From e439d705dcdb1f57449c1689bba7d938d95e84e8 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Feb 10 2024 16:57:28 +0000 Subject: Backport PR #459 to hopefully fix Python 3.12 compatibility --- diff --git a/0001-bottle-fix-for-Python-3.12-backport-CVE-2022-31799-f.patch b/0001-bottle-fix-for-Python-3.12-backport-CVE-2022-31799-f.patch new file mode 100644 index 0000000..5e3f2ed --- /dev/null +++ b/0001-bottle-fix-for-Python-3.12-backport-CVE-2022-31799-f.patch @@ -0,0 +1,69 @@ +From 6ad8f25dc9214a7236d0df8127bbc909f45e142e Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Sat, 10 Feb 2024 08:43:29 -0800 +Subject: [PATCH 1/2] bottle: fix for Python 3.12, backport CVE-2022-31799 fix + +This fixes bottle for the removal of imp (slightly different +in appearance from how upstream did it, as I wrote it first +without seeing the upstream commit, but the same in effect), +and backports the fix for CVE-2022-31799 . + +Signed-off-by: Adam Williamson +--- + imgfac/rest/bottle.py | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/imgfac/rest/bottle.py b/imgfac/rest/bottle.py +index 5887109..b706e90 100644 +--- a/imgfac/rest/bottle.py ++++ b/imgfac/rest/bottle.py +@@ -35,8 +35,8 @@ if __name__ == '__main__': + if _cmd_options.server and _cmd_options.server.startswith('gevent'): + import gevent.monkey; gevent.monkey.patch_all() + +-import base64, cgi, email.utils, functools, hmac, imp, itertools, mimetypes,\ +- os, re, subprocess, sys, tempfile, threading, time, warnings ++import base64, cgi, email.utils, functools, hmac, itertools, mimetypes,\ ++ os, re, subprocess, sys, tempfile, threading, time, types, warnings + + from datetime import date as datedate, datetime, timedelta + from tempfile import TemporaryFile +@@ -842,17 +842,19 @@ class Bottle(object): + return tob(template(ERROR_PAGE_TEMPLATE, e=res)) + + def _handle(self, environ): +- path = environ['bottle.raw_path'] = environ['PATH_INFO'] +- if py3k: +- try: +- environ['PATH_INFO'] = path.encode('latin1').decode('utf8') +- except UnicodeError: +- return HTTPError(400, 'Invalid path string. Expected UTF-8') +- + try: ++ + environ['bottle.app'] = self + request.bind(environ) + response.bind() ++ ++ path = environ['bottle.raw_path'] = environ['PATH_INFO'] ++ if py3k: ++ try: ++ environ['PATH_INFO'] = path.encode('latin1').decode('utf8') ++ except UnicodeError: ++ return HTTPError(400, 'Invalid path string. Expected UTF-8') ++ + try: + self.trigger_hook('before_request') + route, args = self.router.match(environ) +@@ -1779,7 +1781,7 @@ class _ImportRedirect(object): + ''' Create a virtual package that redirects imports (see PEP 302). ''' + self.name = name + self.impmask = impmask +- self.module = sys.modules.setdefault(name, imp.new_module(name)) ++ self.module = sys.modules.setdefault(name, types.ModuleType(name)) + self.module.__dict__.update({'__file__': __file__, '__path__': [], + '__all__': [], '__loader__': self}) + sys.meta_path.append(self) +-- +2.43.0 + diff --git a/0002-Python-3.12-adjust-for-removal-of-SafeConfigParser.patch b/0002-Python-3.12-adjust-for-removal-of-SafeConfigParser.patch new file mode 100644 index 0000000..22b09df --- /dev/null +++ b/0002-Python-3.12-adjust-for-removal-of-SafeConfigParser.patch @@ -0,0 +1,111 @@ +From 115ea0749bb0bb2fdcc31be845fbc39d9f04f796 Mon Sep 17 00:00:00 2001 +From: Adam Williamson +Date: Sat, 10 Feb 2024 08:50:19 -0800 +Subject: [PATCH 2/2] Python 3.12: adjust for removal of SafeConfigParser + +Signed-off-by: Adam Williamson +--- + imagefactory_plugins/EC2/EC2.py | 6 +++++- + imagefactory_plugins/IndirectionCloud/IndirectionCloud.py | 6 +++++- + imagefactory_plugins/Nova/Nova.py | 8 ++++++-- + imagefactory_plugins/Rackspace/Rackspace.py | 6 +++++- + imagefactory_plugins/TinMan/TinMan.py | 6 +++++- + 5 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/imagefactory_plugins/EC2/EC2.py b/imagefactory_plugins/EC2/EC2.py +index 9e927f9..bac6d89 100644 +--- a/imagefactory_plugins/EC2/EC2.py ++++ b/imagefactory_plugins/EC2/EC2.py +@@ -61,7 +61,11 @@ class EC2(object): + self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) + config_obj = ApplicationConfiguration() + self.app_config = config_obj.configuration +- self.oz_config = configparser.SafeConfigParser() ++ try: ++ self.oz_config = configparser.SafeConfigParser() ++ except AttributeError: ++ # SafeConfigParser was deprecated in Python 3.2 ++ self.oz_config = configparser.ConfigParser() + self.oz_config.read("/etc/oz/oz.cfg") + self.oz_config.set('paths', 'output_dir', self.app_config["imgdir"]) + self.guest = None +diff --git a/imagefactory_plugins/IndirectionCloud/IndirectionCloud.py b/imagefactory_plugins/IndirectionCloud/IndirectionCloud.py +index ff364db..a41dc74 100644 +--- a/imagefactory_plugins/IndirectionCloud/IndirectionCloud.py ++++ b/imagefactory_plugins/IndirectionCloud/IndirectionCloud.py +@@ -282,7 +282,11 @@ class IndirectionCloud(object): + def _init_oz(self): + # populate a config object to pass to OZ; this allows us to specify our + # own output dir but inherit other Oz behavior +- self.oz_config = configparser.SafeConfigParser() ++ try: ++ self.oz_config = configparser.SafeConfigParser() ++ except AttributeError: ++ # SafeConfigParser was deprecated in Python 3.2 ++ self.oz_config = configparser.ConfigParser() + if self.oz_config.read("/etc/oz/oz.cfg") != []: + self.oz_config.set('paths', 'output_dir', self.app_config["imgdir"]) + if "oz_data_dir" in self.app_config: +diff --git a/imagefactory_plugins/Nova/Nova.py b/imagefactory_plugins/Nova/Nova.py +index ff7cc08..9a8c777 100644 +--- a/imagefactory_plugins/Nova/Nova.py ++++ b/imagefactory_plugins/Nova/Nova.py +@@ -28,7 +28,11 @@ from novaimagebuilder.StackEnvironment import StackEnvironment + from time import sleep + from base64 import b64decode + #TODO: remove dependency on Oz +-from configparser import SafeConfigParser ++try: ++ from configparser import SafeConfigParser as ConfigParser ++except AttributeError: ++ # SafeConfigParser was deprecated in Python 3.2 ++ from configparser import ConfigParser + from oz.TDL import TDL + import oz.GuestFactory + +@@ -438,7 +442,7 @@ class Nova(object): + return confirmation + + def _oz_config(self, private_key_file): +- config = SafeConfigParser() ++ config = ConfigParser() + if config.read("/etc/oz/oz.cfg"): + config.set('paths', 'output_dir', self.app_config['imgdir']) + config.set('paths', 'sshprivkey', private_key_file) +diff --git a/imagefactory_plugins/Rackspace/Rackspace.py b/imagefactory_plugins/Rackspace/Rackspace.py +index e045d14..ae7fe99 100644 +--- a/imagefactory_plugins/Rackspace/Rackspace.py ++++ b/imagefactory_plugins/Rackspace/Rackspace.py +@@ -64,7 +64,11 @@ class Rackspace(object): + self.log = logging.getLogger('%s.%s' % (__name__, self.__class__.__name__)) + config_obj = ApplicationConfiguration() + self.app_config = config_obj.configuration +- self.oz_config = configparser.SafeConfigParser() ++ try: ++ self.oz_config = configparser.SafeConfigParser() ++ except AttributeError: ++ # SafeConfigParser was deprecated in Python 3.2 ++ self.oz_config = configparser.ConfigParser() + self.oz_config.read("/etc/oz/oz.cfg") + self.oz_config.set('paths', 'output_dir', self.app_config["imgdir"]) + self.active_image = None +diff --git a/imagefactory_plugins/TinMan/TinMan.py b/imagefactory_plugins/TinMan/TinMan.py +index 219a78e..27b3d23 100644 +--- a/imagefactory_plugins/TinMan/TinMan.py ++++ b/imagefactory_plugins/TinMan/TinMan.py +@@ -269,7 +269,11 @@ class TinMan(object): + + # populate a config object to pass to OZ; this allows us to specify our + # own output dir but inherit other Oz behavior +- self.oz_config = configparser.SafeConfigParser() ++ try: ++ self.oz_config = configparser.SafeConfigParser() ++ except AttributeError: ++ # SafeConfigParser was deprecated in Python 3.2 ++ self.oz_config = configparser.ConfigParser() + if self.oz_config.read("/etc/oz/oz.cfg") != []: + if self.parameters.get("oz_overrides", None) != None: + oz_overrides = json.loads(self.parameters.get("oz_overrides",None).replace("'", "\"")) +-- +2.43.0 + diff --git a/imagefactory.spec b/imagefactory.spec index e9efdc2..8cad5b4 100644 --- a/imagefactory.spec +++ b/imagefactory.spec @@ -1,6 +1,6 @@ Name: imagefactory Version: 1.1.16 -Release: 10%{?dist} +Release: 11%{?dist} Summary: System image generation tool License: ASL 2.0 URL: https://github.com/redhat-imaging/imagefactory @@ -19,7 +19,13 @@ Patch3: imagefactory-Docker.py-Pass-the-use_ino-option-to-fix-hardlnks.patch # this goes along with https://github.com/clalancette/oz/pull/310 # which was backported to oz in # https://src.fedoraproject.org/rpms/oz/c/4e5dbe2 +# Might only be needed in imagefactory-plugins, but let's have it +# here just to be safe Patch4: 0001-TinMan.py-adjust-to-oz-generate_diskimage-size-unit-.patch +# https://github.com/redhat-imaging/imagefactory/pull/459 +# Python 3.12 support and CVE-2022-31799 fix for bundled bottle +Patch5: 0001-bottle-fix-for-Python-3.12-backport-CVE-2022-31799-f.patch +Patch6: 0002-Python-3.12-adjust-for-removal-of-SafeConfigParser.patch BuildArch: noarch @@ -42,6 +48,9 @@ Requires(post): systemd Requires(preun): systemd Requires(postun): systemd +# Has a vendored copy of bottle.py as imgfac/rest/bottle.py +Provides: bundled(python-bottle) + # TODO: Any changes to the _internal_ API must increment this version or, in # the case of backwards compatible changes, add a new version (RPM # allows multiple version "=" lines for the same package or @@ -103,6 +112,9 @@ rm -f %{buildroot}/%{_initddir}/imagefactoryd %{_bindir}/imagefactoryd %changelog +* Sat Feb 10 2024 Adam Williamson - 1.1.16-11 +- Backport PR #459 to hopefully fix Python 3.12 compatibility + * Sat Feb 10 2024 Adam Williamson - 1.1.16-10 - Backport PR #458 to go with backport of oz PR #310 (image size units)