diff --git a/fix-cve-2023-6597.patch b/fix-cve-2023-6597.patch new file mode 100644 index 0000000000000000000000000000000000000000..13f866552ad13f15bef76410dee5b3d9636eba42 --- /dev/null +++ b/fix-cve-2023-6597.patch @@ -0,0 +1,201 @@ +From 28d58338757622082aec9201202070910bc904db Mon Sep 17 00:00:00 2001 +From: Yang_X_Y +Date: Thu, 9 May 2024 16:31:40 +0800 +Subject: [PATCH] fix-cve-2023-6597 + +--- + Lib/tempfile.py | 27 ++++++---- + Lib/test/test_tempfile.py | 111 +++++++++++++++++++++++++++++++++++--- + 2 files changed, 123 insertions(+), 15 deletions(-) + +diff --git a/Lib/tempfile.py b/Lib/tempfile.py +index 480c172..76d4c60 100644 +--- a/Lib/tempfile.py ++++ b/Lib/tempfile.py +@@ -269,6 +269,22 @@ def _mkstemp_inner(dir, pre, suf, flags, output_type): + raise FileExistsError(_errno.EEXIST, + "No usable temporary file name found") + ++def _dont_follow_symlinks(func, path, *args): ++ # Pass follow_symlinks=False, unless not supported on this platform. ++ if func in _os.supports_follow_symlinks: ++ func(path, *args, follow_symlinks=False) ++ elif _os.name == 'nt' or not _os.path.islink(path): ++ func(path, *args) ++ ++def _resetperms(path): ++ try: ++ chflags = _os.chflags ++ except AttributeError: ++ pass ++ else: ++ _dont_follow_symlinks(chflags, path, 0) ++ _dont_follow_symlinks(_os.chmod, path, 0o700) ++ + + # User visible interfaces. + +@@ -862,17 +878,10 @@ class TemporaryDirectory: + def _rmtree(cls, name, ignore_errors=False): + def onerror(func, path, exc_info): + if issubclass(exc_info[0], PermissionError): +- def resetperms(path): +- try: +- _os.chflags(path, 0) +- except AttributeError: +- pass +- _os.chmod(path, 0o700) +- + try: + if path != name: +- resetperms(_os.path.dirname(path)) +- resetperms(path) ++ _resetperms(_os.path.dirname(path)) ++ _resetperms(path) + + try: + _os.unlink(path) +diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py +index 2632e77..bbcbb18 100644 +--- a/Lib/test/test_tempfile.py ++++ b/Lib/test/test_tempfile.py +@@ -1553,6 +1553,103 @@ class TestTemporaryDirectory(BaseTestCase): + "Contents of the directory pointed to by a symlink " + "were deleted") + d2.cleanup() ++ ++ @os_helper.skip_unless_symlink ++ def test_cleanup_with_symlink_modes(self): ++ # cleanup() should not follow symlinks when fixing mode bits (#91133) ++ with self.do_create(recurse=0) as d2: ++ file1 = os.path.join(d2, 'file1') ++ open(file1, 'wb').close() ++ dir1 = os.path.join(d2, 'dir1') ++ os.mkdir(dir1) ++ for mode in range(8): ++ mode <<= 6 ++ with self.subTest(mode=format(mode, '03o')): ++ def test(target, target_is_directory): ++ d1 = self.do_create(recurse=0) ++ symlink = os.path.join(d1.name, 'symlink') ++ os.symlink(target, symlink, ++ target_is_directory=target_is_directory) ++ try: ++ os.chmod(symlink, mode, follow_symlinks=False) ++ except NotImplementedError: ++ pass ++ try: ++ os.chmod(symlink, mode) ++ except FileNotFoundError: ++ pass ++ os.chmod(d1.name, mode) ++ d1.cleanup() ++ self.assertFalse(os.path.exists(d1.name)) ++ ++ with self.subTest('nonexisting file'): ++ test('nonexisting', target_is_directory=False) ++ with self.subTest('nonexisting dir'): ++ test('nonexisting', target_is_directory=True) ++ ++ with self.subTest('existing file'): ++ os.chmod(file1, mode) ++ old_mode = os.stat(file1).st_mode ++ test(file1, target_is_directory=False) ++ new_mode = os.stat(file1).st_mode ++ self.assertEqual(new_mode, old_mode, ++ '%03o != %03o' % (new_mode, old_mode)) ++ ++ with self.subTest('existing dir'): ++ os.chmod(dir1, mode) ++ old_mode = os.stat(dir1).st_mode ++ test(dir1, target_is_directory=True) ++ new_mode = os.stat(dir1).st_mode ++ self.assertEqual(new_mode, old_mode, ++ '%03o != %03o' % (new_mode, old_mode)) ++ ++ @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') ++ @os_helper.skip_unless_symlink ++ def test_cleanup_with_symlink_flags(self): ++ # cleanup() should not follow symlinks when fixing flags (#91133) ++ flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK ++ self.check_flags(flags) ++ ++ with self.do_create(recurse=0) as d2: ++ file1 = os.path.join(d2, 'file1') ++ open(file1, 'wb').close() ++ dir1 = os.path.join(d2, 'dir1') ++ os.mkdir(dir1) ++ def test(target, target_is_directory): ++ d1 = self.do_create(recurse=0) ++ symlink = os.path.join(d1.name, 'symlink') ++ os.symlink(target, symlink, ++ target_is_directory=target_is_directory) ++ try: ++ os.chflags(symlink, flags, follow_symlinks=False) ++ except NotImplementedError: ++ pass ++ try: ++ os.chflags(symlink, flags) ++ except FileNotFoundError: ++ pass ++ os.chflags(d1.name, flags) ++ d1.cleanup() ++ self.assertFalse(os.path.exists(d1.name)) ++ ++ with self.subTest('nonexisting file'): ++ test('nonexisting', target_is_directory=False) ++ with self.subTest('nonexisting dir'): ++ test('nonexisting', target_is_directory=True) ++ ++ with self.subTest('existing file'): ++ os.chflags(file1, flags) ++ old_flags = os.stat(file1).st_flags ++ test(file1, target_is_directory=False) ++ new_flags = os.stat(file1).st_flags ++ self.assertEqual(new_flags, old_flags) ++ ++ with self.subTest('existing dir'): ++ os.chflags(dir1, flags) ++ old_flags = os.stat(dir1).st_flags ++ test(dir1, target_is_directory=True) ++ new_flags = os.stat(dir1).st_flags ++ self.assertEqual(new_flags, old_flags) + + @support.cpython_only + def test_del_on_collection(self): +@@ -1726,10 +1823,7 @@ class TestTemporaryDirectory(BaseTestCase): + d.cleanup() + self.assertFalse(os.path.exists(d.name)) + +- @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') +- def test_flags(self): +- flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK +- ++ def check_flags(self, flags): + # skip the test if these flags are not supported (ex: FreeBSD 13) + filename = os_helper.TESTFN + try: +@@ -1738,13 +1832,18 @@ class TestTemporaryDirectory(BaseTestCase): + os.chflags(filename, flags) + except OSError as exc: + # "OSError: [Errno 45] Operation not supported" +- self.skipTest(f"chflags() doesn't support " +- f"UF_IMMUTABLE|UF_NOUNLINK: {exc}") ++ self.skipTest(f"chflags() doesn't support flags " ++ f"{flags:#b}: {exc}") + else: + os.chflags(filename, 0) + finally: + os_helper.unlink(filename) + ++ @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags') ++ def test_flags(self): ++ flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK ++ self.check_flags(flags) ++ + d = self.do_create(recurse=3, dirs=2, files=2) + with d: + # Change files and directories flags recursively. +-- +2.33.0 + diff --git a/python3.spec b/python3.spec index 756a3442fa1ddda994e10cb961c989ddcec6c14b..b1b27570ce6be73ebecfc5cee0fce430c55ae7d2 100644 --- a/python3.spec +++ b/python3.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %global pybasever 3.11 # pybasever without the dot: @@ -240,6 +240,7 @@ Patch1001: python3-3.10.10-fix-linkage.patch Patch1002: python3-3.10.10-link-C-modules-with-libpython.patch # add loongarch64 support Patch1003: 0001-add-loongarch64-support-for-python-3.10.12.patch +Patch1004: fix-cve-2023-6597.patch # ========================================== # Descriptions, and metadata for subpackages @@ -1512,6 +1513,9 @@ CheckPython optimized # ====================================================== %changelog +* Tue May 09 2024 yangxinyu - 3.11.6-2 +- fix cve-2023-6597 + * Mon Mar 4 2024 Liwei Ge - 3.11.6-1 - Update to 3.11.6