import UBI python3.12-3.12.5-2.el9_5.1
This commit is contained in:
		
							parent
							
								
									fb9cb95ae7
								
							
						
					
					
						commit
						0c48c99a16
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1 +1 @@ | ||||
| SOURCES/Python-3.12.1.tar.xz | ||||
| SOURCES/Python-3.12.5.tar.xz | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| 5b11c58ea58cd6b8e1943c7e9b5f6e0997ca3632 SOURCES/Python-3.12.1.tar.xz | ||||
| d9b83c17a717e1cbd3ab6bd14cfe3e508e6d87b2 SOURCES/Python-3.12.5.tar.xz | ||||
|  | ||||
| @ -30,10 +30,10 @@ Co-authored-by: Lumír Balhar <frenzy.madness@gmail.com> | ||||
|  3 files changed, 71 insertions(+), 4 deletions(-) | ||||
| 
 | ||||
| diff --git a/Lib/site.py b/Lib/site.py
 | ||||
| index 672fa7b000..0a9c5be53e 100644
 | ||||
| index 924cfbecec..e2871ecc89 100644
 | ||||
| --- a/Lib/site.py
 | ||||
| +++ b/Lib/site.py
 | ||||
| @@ -377,8 +377,15 @@ def getsitepackages(prefixes=None):
 | ||||
| @@ -398,8 +398,15 @@ def getsitepackages(prefixes=None):
 | ||||
|      return sitepackages | ||||
|   | ||||
|  def addsitepackages(known_paths, prefixes=None): | ||||
| @ -129,7 +129,7 @@ index 122d441bd1..2d354a11da 100644 | ||||
|          # On Windows we want to substitute 'lib' for schemes rather | ||||
|          # than the native value (without modifying vars, in case it | ||||
| diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
 | ||||
| index b6dbf3d52c..4f06a7673c 100644
 | ||||
| index 1137c2032b..8fc2b84f52 100644
 | ||||
| --- a/Lib/test/test_sysconfig.py
 | ||||
| +++ b/Lib/test/test_sysconfig.py
 | ||||
| @@ -110,8 +110,19 @@ def test_get_path(self):
 | ||||
| @ -153,7 +153,7 @@ index b6dbf3d52c..4f06a7673c 100644 | ||||
|                      os.path.normpath(expected), | ||||
|                  ) | ||||
|   | ||||
| @@ -335,7 +346,7 @@ def test_get_config_h_filename(self):
 | ||||
| @@ -344,7 +355,7 @@ def test_get_config_h_filename(self):
 | ||||
|          self.assertTrue(os.path.isfile(config_h), config_h) | ||||
|   | ||||
|      def test_get_scheme_names(self): | ||||
| @ -162,7 +162,7 @@ index b6dbf3d52c..4f06a7673c 100644 | ||||
|          if HAS_USER_BASE: | ||||
|              wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) | ||||
|          self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) | ||||
| @@ -347,6 +358,8 @@ def test_symlink(self): # Issue 7880
 | ||||
| @@ -356,6 +367,8 @@ def test_symlink(self): # Issue 7880
 | ||||
|              cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" | ||||
|              self.assertEqual(py.call_real(*cmd), py.call_link(*cmd)) | ||||
|   | ||||
|  | ||||
| @ -750,7 +750,7 @@ index 8b4eb2f..e8e4864 100644 | ||||
|              raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) | ||||
|   | ||||
|          if not digestmod: | ||||
|              raise TypeError("Missing required parameter 'digestmod'.") | ||||
|              raise TypeError("Missing required argument 'digestmod'.") | ||||
|   | ||||
| -        if _hashopenssl and isinstance(digestmod, (str, _functype)):
 | ||||
| +        if _hashopenssl.get_fips_mode() or (_hashopenssl and isinstance(digestmod, (str, _functype))):
 | ||||
|  | ||||
| @ -16,10 +16,10 @@ https://github.com/GrahamDumpleton/mod_wsgi/issues/730 | ||||
|  2 files changed, 8 insertions(+), 50 deletions(-) | ||||
| 
 | ||||
| diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
 | ||||
| index 756d5e329f..5d09775efc 100644
 | ||||
| index 2e4b860b97..3066b23ee1 100644
 | ||||
| --- a/Lib/test/test_threading.py
 | ||||
| +++ b/Lib/test/test_threading.py
 | ||||
| @@ -1007,39 +1007,6 @@ def noop(): pass
 | ||||
| @@ -1100,39 +1100,6 @@ def noop(): pass
 | ||||
|              threading.Thread(target=noop).start() | ||||
|              # Thread.join() is not called | ||||
|   | ||||
| @ -56,14 +56,14 @@ index 756d5e329f..5d09775efc 100644 | ||||
| -        self.assertEqual(out, b'')
 | ||||
| -        self.assertEqual(err, b'')
 | ||||
| -
 | ||||
|      def test_start_new_thread_at_exit(self): | ||||
|      def test_start_new_thread_at_finalization(self): | ||||
|          code = """if 1: | ||||
|              import atexit | ||||
|              import _thread | ||||
| diff --git a/Lib/threading.py b/Lib/threading.py
 | ||||
| index 8dcaf8ca6a..ed0b0f4632 100644
 | ||||
| index 0bba85d08a..b256e3273f 100644
 | ||||
| --- a/Lib/threading.py
 | ||||
| +++ b/Lib/threading.py
 | ||||
| @@ -1586,29 +1586,20 @@ def _shutdown():
 | ||||
| @@ -1587,29 +1587,20 @@ def _shutdown():
 | ||||
|   | ||||
|      global _SHUTTING_DOWN | ||||
|      _SHUTTING_DOWN = True | ||||
|  | ||||
| @ -1,19 +1,24 @@ | ||||
| From 73d2995223c725638d53b9cb8e1d26b82daf0874 Mon Sep 17 00:00:00 2001 | ||||
| From ddd8064257a1916726b784d43f18e889ea1634f7 Mon Sep 17 00:00:00 2001 | ||||
| From: Petr Viktorin <encukou@gmail.com> | ||||
| Date: Mon, 6 Mar 2023 17:24:24 +0100 | ||||
| Date: Tue, 2 Jul 2024 11:40:37 +0200 | ||||
| Subject: [PATCH] CVE-2007-4559, PEP-706: Add filters for tarfile extraction | ||||
|  (downstream) | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
| 
 | ||||
| Add and test RHEL-specific ways of configuring the default behavior: environment | ||||
| variable and config file. | ||||
| 
 | ||||
| Co-Authored-By: Tomáš Hrnčiar <thrnciar@redhat.com> | ||||
| ---
 | ||||
|  Lib/tarfile.py           |  47 +++++++++++++-- | ||||
|  Lib/tarfile.py           |  47 +++++++++++-- | ||||
|  Lib/test/test_shutil.py  |   2 +- | ||||
|  Lib/test/test_tarfile.py | 123 ++++++++++++++++++++++++++++++++++++++- | ||||
|  3 files changed, 163 insertions(+), 9 deletions(-) | ||||
|  Lib/test/test_tarfile.py | 147 +++++++++++++++++++++++++++++++++++++-- | ||||
|  3 files changed, 185 insertions(+), 11 deletions(-) | ||||
| 
 | ||||
| diff --git a/Lib/tarfile.py b/Lib/tarfile.py
 | ||||
| index 02f5e3b..f7109f3 100755
 | ||||
| index e1487e3..89b6843 100755
 | ||||
| --- a/Lib/tarfile.py
 | ||||
| +++ b/Lib/tarfile.py
 | ||||
| @@ -71,6 +71,13 @@ __all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError", "ReadError",
 | ||||
| @ -30,7 +35,7 @@ index 02f5e3b..f7109f3 100755 | ||||
|   | ||||
|  #--------------------------------------------------------- | ||||
|  # tar constants | ||||
| @@ -2217,11 +2224,41 @@ class TarFile(object):
 | ||||
| @@ -2218,11 +2225,41 @@ class TarFile(object):
 | ||||
|          if filter is None: | ||||
|              filter = self.extraction_filter | ||||
|              if filter is None: | ||||
| @ -38,7 +43,7 @@ index 02f5e3b..f7109f3 100755 | ||||
| -                    'Python 3.14 will, by default, filter extracted tar '
 | ||||
| -                    + 'archives and reject files or modify their metadata. '
 | ||||
| -                    + 'Use the filter argument to control this behavior.',
 | ||||
| -                    DeprecationWarning)
 | ||||
| -                    DeprecationWarning, stacklevel=3)
 | ||||
| +                name = os.environ.get('PYTHON_TARFILE_EXTRACTION_FILTER')
 | ||||
| +                if name is None:
 | ||||
| +                    try:
 | ||||
| @ -72,16 +77,16 @@ index 02f5e3b..f7109f3 100755 | ||||
| +                        + 'and some mode bits are cleared. '
 | ||||
| +                        + 'See https://access.redhat.com/articles/7004769 '
 | ||||
| +                        + 'for more details.',
 | ||||
| +                        RuntimeWarning)
 | ||||
| +                        RuntimeWarning, stacklevel=3)
 | ||||
| +                    return tar_filter
 | ||||
|                  return fully_trusted_filter | ||||
|              if isinstance(filter, str): | ||||
|                  raise TypeError( | ||||
| diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
 | ||||
| index 5fd8fb4..501da8f 100644
 | ||||
| index 7bc5d12..88b4bdb 100644
 | ||||
| --- a/Lib/test/test_shutil.py
 | ||||
| +++ b/Lib/test/test_shutil.py
 | ||||
| @@ -1950,7 +1950,7 @@ class TestArchives(BaseTest, unittest.TestCase):
 | ||||
| @@ -2096,7 +2096,7 @@ class TestArchives(BaseTest, unittest.TestCase):
 | ||||
|          self.check_unpack_archive(format, filter='fully_trusted') | ||||
|          self.check_unpack_archive(format, filter='data') | ||||
|          with warnings_helper.check_warnings( | ||||
| @ -91,10 +96,48 @@ index 5fd8fb4..501da8f 100644 | ||||
|   | ||||
|      def test_unpack_archive_tar(self): | ||||
| diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
 | ||||
| index c5fc76d..397e334 100644
 | ||||
| index 3fbd25e..9aa727e 100644
 | ||||
| --- a/Lib/test/test_tarfile.py
 | ||||
| +++ b/Lib/test/test_tarfile.py
 | ||||
| @@ -3097,8 +3097,8 @@ class NoneInfoExtractTests(ReadTest):
 | ||||
| @@ -727,7 +727,17 @@ class MiscReadTestBase(CommonReadTest):
 | ||||
|              tarfile.open(tarname, encoding="iso8859-1") as tar | ||||
|          ): | ||||
|              directories = [t for t in tar if t.isdir()] | ||||
| -            with self.assertWarnsRegex(DeprecationWarning, "Use the filter argument") as cm:
 | ||||
| +            with self.assertWarnsRegex(
 | ||||
| +                RuntimeWarning,
 | ||||
| +                re.escape(
 | ||||
| +                    'The default behavior of tarfile extraction has been '
 | ||||
| +                    'changed to disallow common exploits '
 | ||||
| +                    '(including CVE-2007-4559). '
 | ||||
| +                    'By default, absolute/parent paths are disallowed '
 | ||||
| +                    'and some mode bits are cleared. '
 | ||||
| +                    'See https://access.redhat.com/articles/7004769 '
 | ||||
| +                    'for more details.'
 | ||||
| +                )) as cm:
 | ||||
|                  tar.extractall(DIR, directories) | ||||
|              # check that the stacklevel of the deprecation warning is correct: | ||||
|              self.assertEqual(cm.filename, __file__) | ||||
| @@ -740,7 +750,17 @@ class MiscReadTestBase(CommonReadTest):
 | ||||
|              tarfile.open(tarname, encoding="iso8859-1") as tar | ||||
|          ): | ||||
|              tarinfo = tar.getmember(dirtype) | ||||
| -            with self.assertWarnsRegex(DeprecationWarning, "Use the filter argument") as cm:
 | ||||
| +            with self.assertWarnsRegex(
 | ||||
| +                RuntimeWarning,
 | ||||
| +                re.escape(
 | ||||
| +                    'The default behavior of tarfile extraction has been '
 | ||||
| +                    'changed to disallow common exploits '
 | ||||
| +                    '(including CVE-2007-4559). '
 | ||||
| +                    'By default, absolute/parent paths are disallowed '
 | ||||
| +                    'and some mode bits are cleared. '
 | ||||
| +                    'See https://access.redhat.com/articles/7004769 '
 | ||||
| +                    'for more details.'
 | ||||
| +                )) as cm:
 | ||||
|                  tar.extract(tarinfo, path=DIR) | ||||
|              # check that the stacklevel of the deprecation warning is correct: | ||||
|              self.assertEqual(cm.filename, __file__) | ||||
| @@ -3144,8 +3164,8 @@ class NoneInfoExtractTests(ReadTest):
 | ||||
|          tar.errorlevel = 0 | ||||
|          with ExitStack() as cm: | ||||
|              if cls.extraction_filter is None: | ||||
| @ -105,7 +148,7 @@ index c5fc76d..397e334 100644 | ||||
|              tar.extractall(cls.control_dir, filter=cls.extraction_filter) | ||||
|          tar.close() | ||||
|          cls.control_paths = set( | ||||
| @@ -3919,7 +3919,7 @@ class TestExtractionFilters(unittest.TestCase):
 | ||||
| @@ -3966,7 +3986,7 @@ class TestExtractionFilters(unittest.TestCase):
 | ||||
|          with ArchiveMaker() as arc: | ||||
|              arc.add('foo') | ||||
|          with warnings_helper.check_warnings( | ||||
| @ -114,7 +157,7 @@ index c5fc76d..397e334 100644 | ||||
|              with self.check_context(arc.open(), None): | ||||
|                  self.expect_file('foo') | ||||
|   | ||||
| @@ -4089,6 +4089,123 @@ class TestExtractionFilters(unittest.TestCase):
 | ||||
| @@ -4136,6 +4156,123 @@ class TestExtractionFilters(unittest.TestCase):
 | ||||
|              self.expect_exception(TypeError)  # errorlevel is not int | ||||
|   | ||||
|   | ||||
| @ -235,9 +278,9 @@ index c5fc76d..397e334 100644 | ||||
| +                self.check_trusted_default(tar, tempdir)
 | ||||
| +
 | ||||
| +
 | ||||
|  def setUpModule(): | ||||
|      os_helper.unlink(TEMPDIR) | ||||
|      os.makedirs(TEMPDIR) | ||||
| -- 
 | ||||
| 2.43.0 | ||||
|  class OverwriteTests(archiver_tests.OverwriteTests, unittest.TestCase): | ||||
|      testdir = os.path.join(TEMPDIR, "testoverwrite") | ||||
|   | ||||
| -- 
 | ||||
| 2.44.0 | ||||
| 
 | ||||
|  | ||||
| @ -19,7 +19,7 @@ Co-Authored-By: Thomas Dwyer <github@tomd.tel> | ||||
|  create mode 100644 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst | ||||
| 
 | ||||
| diff --git a/Doc/library/email.utils.rst b/Doc/library/email.utils.rst
 | ||||
| index 345b64001c..d693a9bc39 100644
 | ||||
| index 6ba42491d6..6bd45200d8 100644
 | ||||
| --- a/Doc/library/email.utils.rst
 | ||||
| +++ b/Doc/library/email.utils.rst
 | ||||
| @@ -58,13 +58,18 @@ of the new API.
 | ||||
| @ -72,7 +72,7 @@ index 345b64001c..d693a9bc39 100644 | ||||
|  .. function:: parsedate(date) | ||||
|   | ||||
| diff --git a/Lib/email/utils.py b/Lib/email/utils.py
 | ||||
| index 81da5394ea..43c3627fca 100644
 | ||||
| index 1de547a011..e53abc8b84 100644
 | ||||
| --- a/Lib/email/utils.py
 | ||||
| +++ b/Lib/email/utils.py
 | ||||
| @@ -48,6 +48,7 @@
 | ||||
| @ -81,7 +81,7 @@ index 81da5394ea..43c3627fca 100644 | ||||
|   | ||||
| +
 | ||||
|  def _has_surrogates(s): | ||||
|      """Return True if s contains surrogate-escaped binary data.""" | ||||
|      """Return True if s may contain surrogate-escaped binary data.""" | ||||
|      # This check is based on the fact that unless there are surrogates, utf8 | ||||
| @@ -106,12 +107,127 @@ def formataddr(pair, charset='utf-8'):
 | ||||
|      return address | ||||
| @ -255,7 +255,7 @@ index 81da5394ea..43c3627fca 100644 | ||||
|   | ||||
|   | ||||
| diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py
 | ||||
| index 2a237095b9..4672b790d8 100644
 | ||||
| index fc8d87974e..ef8aa0d53c 100644
 | ||||
| --- a/Lib/test/test_email/test_email.py
 | ||||
| +++ b/Lib/test/test_email/test_email.py
 | ||||
| @@ -16,6 +16,7 @@
 | ||||
| @ -266,7 +266,7 @@ index 2a237095b9..4672b790d8 100644 | ||||
|   | ||||
|  from email.charset import Charset | ||||
|  from email.generator import Generator, DecodedGenerator, BytesGenerator | ||||
| @@ -3337,15 +3338,137 @@ def test_getaddresses_comma_in_name(self):
 | ||||
| @@ -3352,15 +3353,137 @@ def test_getaddresses_comma_in_name(self):
 | ||||
|              ], | ||||
|          ) | ||||
|   | ||||
| @ -412,7 +412,7 @@ index 2a237095b9..4672b790d8 100644 | ||||
|   | ||||
|      def test_getaddresses_embedded_comment(self): | ||||
|          """Test proper handling of a nested comment""" | ||||
| @@ -3536,6 +3659,54 @@ def test_mime_classes_policy_argument(self):
 | ||||
| @@ -3551,6 +3674,54 @@ def test_mime_classes_policy_argument(self):
 | ||||
|                  m = cls(*constructor, policy=email.policy.default) | ||||
|                  self.assertIs(m.policy, email.policy.default) | ||||
|   | ||||
|  | ||||
| @ -0,0 +1,63 @@ | ||||
| From 60d40d7095983e0bc23a103b2050adc519dc7fe3 Mon Sep 17 00:00:00 2001 | ||||
| From: Lumir Balhar <lbalhar@redhat.com> | ||||
| Date: Fri, 3 May 2024 14:17:48 +0200 | ||||
| Subject: [PATCH] Expect failures in tests not working properly with expat with | ||||
|  a fixed CVE in RHEL | ||||
| 
 | ||||
| ---
 | ||||
|  Lib/test/test_pyexpat.py   | 1 + | ||||
|  Lib/test/test_sax.py       | 1 + | ||||
|  Lib/test/test_xml_etree.py | 3 +++ | ||||
|  3 files changed, 5 insertions(+) | ||||
| 
 | ||||
| diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
 | ||||
| index 43cbd27..27b1502 100644
 | ||||
| --- a/Lib/test/test_pyexpat.py
 | ||||
| +++ b/Lib/test/test_pyexpat.py
 | ||||
| @@ -793,6 +793,7 @@ class ReparseDeferralTest(unittest.TestCase):
 | ||||
|   | ||||
|          self.assertEqual(started, ['doc']) | ||||
|   | ||||
| +    @unittest.expectedFailure
 | ||||
|      def test_reparse_deferral_disabled(self): | ||||
|          started = [] | ||||
|   | ||||
| diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
 | ||||
| index 9b3014a..646c92d 100644
 | ||||
| --- a/Lib/test/test_sax.py
 | ||||
| +++ b/Lib/test/test_sax.py
 | ||||
| @@ -1240,6 +1240,7 @@ class ExpatReaderTest(XmlTestBase):
 | ||||
|   | ||||
|          self.assertEqual(result.getvalue(), start + b"<doc></doc>") | ||||
|   | ||||
| +    @unittest.expectedFailure
 | ||||
|      def test_flush_reparse_deferral_disabled(self): | ||||
|          result = BytesIO() | ||||
|          xmlgen = XMLGenerator(result) | ||||
| diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
 | ||||
| index 9c382d1..62f2871 100644
 | ||||
| --- a/Lib/test/test_xml_etree.py
 | ||||
| +++ b/Lib/test/test_xml_etree.py
 | ||||
| @@ -1424,9 +1424,11 @@ class XMLPullParserTest(unittest.TestCase):
 | ||||
|          self.assert_event_tags(parser, [('end', 'root')]) | ||||
|          self.assertIsNone(parser.close()) | ||||
|   | ||||
| +    @unittest.expectedFailure
 | ||||
|      def test_simple_xml_chunk_1(self): | ||||
|          self.test_simple_xml(chunk_size=1, flush=True) | ||||
|   | ||||
| +    @unittest.expectedFailure
 | ||||
|      def test_simple_xml_chunk_5(self): | ||||
|          self.test_simple_xml(chunk_size=5, flush=True) | ||||
|   | ||||
| @@ -1651,6 +1653,7 @@ class XMLPullParserTest(unittest.TestCase):
 | ||||
|   | ||||
|          self.assert_event_tags(parser, [('end', 'doc')]) | ||||
|   | ||||
| +    @unittest.expectedFailure
 | ||||
|      def test_flush_reparse_deferral_disabled(self): | ||||
|          parser = ET.XMLPullParser(events=('start', 'end')) | ||||
|   | ||||
| -- 
 | ||||
| 2.44.0 | ||||
| 
 | ||||
| @ -1,88 +0,0 @@ | ||||
| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 | ||||
| From: Serhiy Storchaka <storchaka@gmail.com> | ||||
| Date: Sun, 11 Feb 2024 12:08:39 +0200 | ||||
| Subject: [PATCH] 00422: gh-115133: Fix tests for XMLPullParser with Expat | ||||
|  2.6.0 | ||||
| 
 | ||||
| Feeding the parser by too small chunks defers parsing to prevent | ||||
| CVE-2023-52425. Future versions of Expat may be more reactive. | ||||
| 
 | ||||
| (cherry picked from commit 4a08e7b3431cd32a0daf22a33421cd3035343dc4) | ||||
| ---
 | ||||
|  Lib/test/test_xml_etree.py                    | 58 ++++++++++++------- | ||||
|  ...-02-08-14-21-28.gh-issue-115133.ycl4ko.rst |  2 + | ||||
|  2 files changed, 38 insertions(+), 22 deletions(-) | ||||
|  create mode 100644 Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst | ||||
| 
 | ||||
| diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
 | ||||
| index b50898f1d1..6fb888cb21 100644
 | ||||
| --- a/Lib/test/test_xml_etree.py
 | ||||
| +++ b/Lib/test/test_xml_etree.py
 | ||||
| @@ -1400,28 +1400,37 @@ class XMLPullParserTest(unittest.TestCase):
 | ||||
|          self.assertEqual([(action, elem.tag) for action, elem in events], | ||||
|                           expected) | ||||
|   | ||||
| -    def test_simple_xml(self):
 | ||||
| -        for chunk_size in (None, 1, 5):
 | ||||
| -            with self.subTest(chunk_size=chunk_size):
 | ||||
| -                parser = ET.XMLPullParser()
 | ||||
| -                self.assert_event_tags(parser, [])
 | ||||
| -                self._feed(parser, "<!-- comment -->\n", chunk_size)
 | ||||
| -                self.assert_event_tags(parser, [])
 | ||||
| -                self._feed(parser,
 | ||||
| -                           "<root>\n  <element key='value'>text</element",
 | ||||
| -                           chunk_size)
 | ||||
| -                self.assert_event_tags(parser, [])
 | ||||
| -                self._feed(parser, ">\n", chunk_size)
 | ||||
| -                self.assert_event_tags(parser, [('end', 'element')])
 | ||||
| -                self._feed(parser, "<element>text</element>tail\n", chunk_size)
 | ||||
| -                self._feed(parser, "<empty-element/>\n", chunk_size)
 | ||||
| -                self.assert_event_tags(parser, [
 | ||||
| -                    ('end', 'element'),
 | ||||
| -                    ('end', 'empty-element'),
 | ||||
| -                    ])
 | ||||
| -                self._feed(parser, "</root>\n", chunk_size)
 | ||||
| -                self.assert_event_tags(parser, [('end', 'root')])
 | ||||
| -                self.assertIsNone(parser.close())
 | ||||
| +    def test_simple_xml(self, chunk_size=None):
 | ||||
| +        parser = ET.XMLPullParser()
 | ||||
| +        self.assert_event_tags(parser, [])
 | ||||
| +        self._feed(parser, "<!-- comment -->\n", chunk_size)
 | ||||
| +        self.assert_event_tags(parser, [])
 | ||||
| +        self._feed(parser,
 | ||||
| +                   "<root>\n  <element key='value'>text</element",
 | ||||
| +                   chunk_size)
 | ||||
| +        self.assert_event_tags(parser, [])
 | ||||
| +        self._feed(parser, ">\n", chunk_size)
 | ||||
| +        self.assert_event_tags(parser, [('end', 'element')])
 | ||||
| +        self._feed(parser, "<element>text</element>tail\n", chunk_size)
 | ||||
| +        self._feed(parser, "<empty-element/>\n", chunk_size)
 | ||||
| +        self.assert_event_tags(parser, [
 | ||||
| +            ('end', 'element'),
 | ||||
| +            ('end', 'empty-element'),
 | ||||
| +            ])
 | ||||
| +        self._feed(parser, "</root>\n", chunk_size)
 | ||||
| +        self.assert_event_tags(parser, [('end', 'root')])
 | ||||
| +        self.assertIsNone(parser.close())
 | ||||
| +
 | ||||
| +    @unittest.expectedFailure
 | ||||
| +    def test_simple_xml_chunk_1(self):
 | ||||
| +        self.test_simple_xml(chunk_size=1)
 | ||||
| +
 | ||||
| +    @unittest.expectedFailure
 | ||||
| +    def test_simple_xml_chunk_5(self):
 | ||||
| +        self.test_simple_xml(chunk_size=5)
 | ||||
| +
 | ||||
| +    def test_simple_xml_chunk_22(self):
 | ||||
| +        self.test_simple_xml(chunk_size=22)
 | ||||
|   | ||||
|      def test_feed_while_iterating(self): | ||||
|          parser = ET.XMLPullParser() | ||||
| diff --git a/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst
 | ||||
| new file mode 100644 | ||||
| index 0000000000..6f1015235c
 | ||||
| --- /dev/null
 | ||||
| +++ b/Misc/NEWS.d/next/Library/2024-02-08-14-21-28.gh-issue-115133.ycl4ko.rst
 | ||||
| @@ -0,0 +1,2 @@
 | ||||
| +Fix tests for :class:`~xml.etree.ElementTree.XMLPullParser` with Expat
 | ||||
| +2.6.0.
 | ||||
| @ -1,345 +0,0 @@ | ||||
| From 7a25b2f511054dd2011308275bb24e914e1977af Mon Sep 17 00:00:00 2001 | ||||
| From: Petr Viktorin <encukou@gmail.com> | ||||
| Date: Tue, 6 Aug 2024 19:07:19 +0200 | ||||
| Subject: [PATCH] gh-121650: Encode newlines in headers, and verify headers are | ||||
|  sound (GH-122233) (#122599) | ||||
| 
 | ||||
| * gh-121650: Encode newlines in headers, and verify headers are sound (GH-122233) | ||||
| 
 | ||||
| - Encode header parts that contain newlines
 | ||||
| 
 | ||||
| Per RFC 2047: | ||||
| 
 | ||||
| > [...] these encoding schemes allow the
 | ||||
| > encoding of arbitrary octet values, mail readers that implement this
 | ||||
| > decoding should also ensure that display of the decoded data on the
 | ||||
| > recipient's terminal will not cause unwanted side-effects
 | ||||
| 
 | ||||
| It seems that the "quoted-word" scheme is a valid way to include | ||||
| a newline character in a header value, just like we already allow | ||||
| undecodable bytes or control characters. | ||||
| They do need to be properly quoted when serialized to text, though. | ||||
| 
 | ||||
| - Verify that email headers are well-formed
 | ||||
| 
 | ||||
| This should fail for custom fold() implementations that aren't careful | ||||
| about newlines. | ||||
| 
 | ||||
| Co-authored-by: Bas Bloemsaat <bas@bloemsaat.org> | ||||
| Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> | ||||
| (cherry picked from commit 097633981879b3c9de9a1dd120d3aa585ecc2384) | ||||
| 
 | ||||
| * Document changes as made in 3.12.5 | ||||
| ---
 | ||||
|  Doc/library/email.errors.rst                  |  7 +++ | ||||
|  Doc/library/email.policy.rst                  | 18 ++++++ | ||||
|  Lib/email/_header_value_parser.py             | 12 +++- | ||||
|  Lib/email/_policybase.py                      |  8 +++ | ||||
|  Lib/email/errors.py                           |  4 ++ | ||||
|  Lib/email/generator.py                        | 13 +++- | ||||
|  Lib/test/test_email/test_generator.py         | 62 +++++++++++++++++++ | ||||
|  Lib/test/test_email/test_policy.py            | 26 ++++++++ | ||||
|  ...-07-27-16-10-41.gh-issue-121650.nf6oc9.rst |  5 ++ | ||||
|  9 files changed, 151 insertions(+), 4 deletions(-) | ||||
|  create mode 100644 Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst | ||||
| 
 | ||||
| diff --git a/Doc/library/email.errors.rst b/Doc/library/email.errors.rst
 | ||||
| index 56aea65..27b0481 100644
 | ||||
| --- a/Doc/library/email.errors.rst
 | ||||
| +++ b/Doc/library/email.errors.rst
 | ||||
| @@ -58,6 +58,13 @@ The following exception classes are defined in the :mod:`email.errors` module:
 | ||||
|     :class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g. | ||||
|     :class:`~email.mime.image.MIMEImage`). | ||||
|   | ||||
| +
 | ||||
| +.. exception:: HeaderWriteError()
 | ||||
| +
 | ||||
| +   Raised when an error occurs when the :mod:`~email.generator` outputs
 | ||||
| +   headers.
 | ||||
| +
 | ||||
| +
 | ||||
|  .. exception:: MessageDefect() | ||||
|   | ||||
|     This is the base class for all defects found when parsing email messages. | ||||
| diff --git a/Doc/library/email.policy.rst b/Doc/library/email.policy.rst
 | ||||
| index fd47dd0..6ec6e4d 100644
 | ||||
| --- a/Doc/library/email.policy.rst
 | ||||
| +++ b/Doc/library/email.policy.rst
 | ||||
| @@ -230,6 +230,24 @@ added matters.  To illustrate::
 | ||||
|   | ||||
|        .. versionadded:: 3.6 | ||||
|   | ||||
| +
 | ||||
| +   .. attribute:: verify_generated_headers
 | ||||
| +
 | ||||
| +      If ``True`` (the default), the generator will raise
 | ||||
| +      :exc:`~email.errors.HeaderWriteError` instead of writing a header
 | ||||
| +      that is improperly folded or delimited, such that it would
 | ||||
| +      be parsed as multiple headers or joined with adjacent data.
 | ||||
| +      Such headers can be generated by custom header classes or bugs
 | ||||
| +      in the ``email`` module.
 | ||||
| +
 | ||||
| +      As it's a security feature, this defaults to ``True`` even in the
 | ||||
| +      :class:`~email.policy.Compat32` policy.
 | ||||
| +      For backwards compatible, but unsafe, behavior, it must be set to
 | ||||
| +      ``False`` explicitly.
 | ||||
| +
 | ||||
| +      .. versionadded:: 3.12.5
 | ||||
| +
 | ||||
| +
 | ||||
|     The following :class:`Policy` method is intended to be called by code using | ||||
|     the email library to create policy instances with custom settings: | ||||
|   | ||||
| diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
 | ||||
| index 0d6bd81..362edc5 100644
 | ||||
| --- a/Lib/email/_header_value_parser.py
 | ||||
| +++ b/Lib/email/_header_value_parser.py
 | ||||
| @@ -92,6 +92,8 @@ TOKEN_ENDS = TSPECIALS | WSP
 | ||||
|  ASPECIALS = TSPECIALS | set("*'%") | ||||
|  ATTRIBUTE_ENDS = ASPECIALS | WSP | ||||
|  EXTENDED_ATTRIBUTE_ENDS = ATTRIBUTE_ENDS - set('%') | ||||
| +NLSET = {'\n', '\r'}
 | ||||
| +SPECIALSNL = SPECIALS | NLSET
 | ||||
|   | ||||
|  def quote_string(value): | ||||
|      return '"'+str(value).replace('\\', '\\\\').replace('"', r'\"')+'"' | ||||
| @@ -2776,9 +2778,13 @@ def _refold_parse_tree(parse_tree, *, policy):
 | ||||
|              wrap_as_ew_blocked -= 1 | ||||
|              continue | ||||
|          tstr = str(part) | ||||
| -        if part.token_type == 'ptext' and set(tstr) & SPECIALS:
 | ||||
| -            # Encode if tstr contains special characters.
 | ||||
| -            want_encoding = True
 | ||||
| +        if not want_encoding:
 | ||||
| +            if part.token_type == 'ptext':
 | ||||
| +                # Encode if tstr contains special characters.
 | ||||
| +                want_encoding = not SPECIALSNL.isdisjoint(tstr)
 | ||||
| +            else:
 | ||||
| +                # Encode if tstr contains newlines.
 | ||||
| +                want_encoding = not NLSET.isdisjoint(tstr)
 | ||||
|          try: | ||||
|              tstr.encode(encoding) | ||||
|              charset = encoding | ||||
| diff --git a/Lib/email/_policybase.py b/Lib/email/_policybase.py
 | ||||
| index c9cbadd..d1f4821 100644
 | ||||
| --- a/Lib/email/_policybase.py
 | ||||
| +++ b/Lib/email/_policybase.py
 | ||||
| @@ -157,6 +157,13 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta):
 | ||||
|      message_factory     -- the class to use to create new message objects. | ||||
|                             If the value is None, the default is Message. | ||||
|   | ||||
| +    verify_generated_headers
 | ||||
| +                        -- if true, the generator verifies that each header
 | ||||
| +                           they are properly folded, so that a parser won't
 | ||||
| +                           treat it as multiple headers, start-of-body, or
 | ||||
| +                           part of another header.
 | ||||
| +                           This is a check against custom Header & fold()
 | ||||
| +                           implementations.
 | ||||
|      """ | ||||
|   | ||||
|      raise_on_defect = False | ||||
| @@ -165,6 +172,7 @@ class Policy(_PolicyBase, metaclass=abc.ABCMeta):
 | ||||
|      max_line_length = 78 | ||||
|      mangle_from_ = False | ||||
|      message_factory = None | ||||
| +    verify_generated_headers = True
 | ||||
|   | ||||
|      def handle_defect(self, obj, defect): | ||||
|          """Based on policy, either raise defect or call register_defect. | ||||
| diff --git a/Lib/email/errors.py b/Lib/email/errors.py
 | ||||
| index 3ad0056..02aa5ec 100644
 | ||||
| --- a/Lib/email/errors.py
 | ||||
| +++ b/Lib/email/errors.py
 | ||||
| @@ -29,6 +29,10 @@ class CharsetError(MessageError):
 | ||||
|      """An illegal charset was given.""" | ||||
|   | ||||
|   | ||||
| +class HeaderWriteError(MessageError):
 | ||||
| +    """Error while writing headers."""
 | ||||
| +
 | ||||
| +
 | ||||
|  # These are parsing defects which the parser was able to work around. | ||||
|  class MessageDefect(ValueError): | ||||
|      """Base class for a message defect.""" | ||||
| diff --git a/Lib/email/generator.py b/Lib/email/generator.py
 | ||||
| index 7ccbe10..ea87ad2 100644
 | ||||
| --- a/Lib/email/generator.py
 | ||||
| +++ b/Lib/email/generator.py
 | ||||
| @@ -14,12 +14,14 @@ import random
 | ||||
|  from copy import deepcopy | ||||
|  from io import StringIO, BytesIO | ||||
|  from email.utils import _has_surrogates | ||||
| +from email.errors import HeaderWriteError
 | ||||
|   | ||||
|  UNDERSCORE = '_' | ||||
|  NL = '\n'  # XXX: no longer used by the code below. | ||||
|   | ||||
|  NLCRE = re.compile(r'\r\n|\r|\n') | ||||
|  fcre = re.compile(r'^From ', re.MULTILINE) | ||||
| +NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]')
 | ||||
|   | ||||
|   | ||||
|  class Generator: | ||||
| @@ -222,7 +224,16 @@ class Generator:
 | ||||
|   | ||||
|      def _write_headers(self, msg): | ||||
|          for h, v in msg.raw_items(): | ||||
| -            self.write(self.policy.fold(h, v))
 | ||||
| +            folded = self.policy.fold(h, v)
 | ||||
| +            if self.policy.verify_generated_headers:
 | ||||
| +                linesep = self.policy.linesep
 | ||||
| +                if not folded.endswith(self.policy.linesep):
 | ||||
| +                    raise HeaderWriteError(
 | ||||
| +                        f'folded header does not end with {linesep!r}: {folded!r}')
 | ||||
| +                if NEWLINE_WITHOUT_FWSP.search(folded.removesuffix(linesep)):
 | ||||
| +                    raise HeaderWriteError(
 | ||||
| +                        f'folded header contains newline: {folded!r}')
 | ||||
| +            self.write(folded)
 | ||||
|          # A blank line always separates headers from body | ||||
|          self.write(self._NL) | ||||
|   | ||||
| diff --git a/Lib/test/test_email/test_generator.py b/Lib/test/test_email/test_generator.py
 | ||||
| index 89e7ede..d29400f 100644
 | ||||
| --- a/Lib/test/test_email/test_generator.py
 | ||||
| +++ b/Lib/test/test_email/test_generator.py
 | ||||
| @@ -6,6 +6,7 @@ from email.message import EmailMessage
 | ||||
|  from email.generator import Generator, BytesGenerator | ||||
|  from email.headerregistry import Address | ||||
|  from email import policy | ||||
| +import email.errors
 | ||||
|  from test.test_email import TestEmailBase, parameterize | ||||
|   | ||||
|   | ||||
| @@ -216,6 +217,44 @@ class TestGeneratorBase:
 | ||||
|          g.flatten(msg) | ||||
|          self.assertEqual(s.getvalue(), self.typ(expected)) | ||||
|   | ||||
| +    def test_keep_encoded_newlines(self):
 | ||||
| +        msg = self.msgmaker(self.typ(textwrap.dedent("""\
 | ||||
| +            To: nobody
 | ||||
| +            Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com
 | ||||
| +
 | ||||
| +            None
 | ||||
| +            """)))
 | ||||
| +        expected = textwrap.dedent("""\
 | ||||
| +            To: nobody
 | ||||
| +            Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com
 | ||||
| +
 | ||||
| +            None
 | ||||
| +            """)
 | ||||
| +        s = self.ioclass()
 | ||||
| +        g = self.genclass(s, policy=self.policy.clone(max_line_length=80))
 | ||||
| +        g.flatten(msg)
 | ||||
| +        self.assertEqual(s.getvalue(), self.typ(expected))
 | ||||
| +
 | ||||
| +    def test_keep_long_encoded_newlines(self):
 | ||||
| +        msg = self.msgmaker(self.typ(textwrap.dedent("""\
 | ||||
| +            To: nobody
 | ||||
| +            Subject: Bad subject=?UTF-8?Q?=0A?=Bcc: injection@example.com
 | ||||
| +
 | ||||
| +            None
 | ||||
| +            """)))
 | ||||
| +        expected = textwrap.dedent("""\
 | ||||
| +            To: nobody
 | ||||
| +            Subject: Bad subject
 | ||||
| +             =?utf-8?q?=0A?=Bcc:
 | ||||
| +             injection@example.com
 | ||||
| +
 | ||||
| +            None
 | ||||
| +            """)
 | ||||
| +        s = self.ioclass()
 | ||||
| +        g = self.genclass(s, policy=self.policy.clone(max_line_length=30))
 | ||||
| +        g.flatten(msg)
 | ||||
| +        self.assertEqual(s.getvalue(), self.typ(expected))
 | ||||
| +
 | ||||
|   | ||||
|  class TestGenerator(TestGeneratorBase, TestEmailBase): | ||||
|   | ||||
| @@ -224,6 +263,29 @@ class TestGenerator(TestGeneratorBase, TestEmailBase):
 | ||||
|      ioclass = io.StringIO | ||||
|      typ = str | ||||
|   | ||||
| +    def test_verify_generated_headers(self):
 | ||||
| +        """gh-121650: by default the generator prevents header injection"""
 | ||||
| +        class LiteralHeader(str):
 | ||||
| +            name = 'Header'
 | ||||
| +            def fold(self, **kwargs):
 | ||||
| +                return self
 | ||||
| +
 | ||||
| +        for text in (
 | ||||
| +            'Value\r\nBad Injection\r\n',
 | ||||
| +            'NoNewLine'
 | ||||
| +        ):
 | ||||
| +            with self.subTest(text=text):
 | ||||
| +                message = message_from_string(
 | ||||
| +                    "Header: Value\r\n\r\nBody",
 | ||||
| +                    policy=self.policy,
 | ||||
| +                )
 | ||||
| +
 | ||||
| +                del message['Header']
 | ||||
| +                message['Header'] = LiteralHeader(text)
 | ||||
| +
 | ||||
| +                with self.assertRaises(email.errors.HeaderWriteError):
 | ||||
| +                    message.as_string()
 | ||||
| +
 | ||||
|   | ||||
|  class TestBytesGenerator(TestGeneratorBase, TestEmailBase): | ||||
|   | ||||
| diff --git a/Lib/test/test_email/test_policy.py b/Lib/test/test_email/test_policy.py
 | ||||
| index e87c275..ff1ddf7 100644
 | ||||
| --- a/Lib/test/test_email/test_policy.py
 | ||||
| +++ b/Lib/test/test_email/test_policy.py
 | ||||
| @@ -26,6 +26,7 @@ class PolicyAPITests(unittest.TestCase):
 | ||||
|          'raise_on_defect':          False, | ||||
|          'mangle_from_':             True, | ||||
|          'message_factory':          None, | ||||
| +        'verify_generated_headers': True,
 | ||||
|          } | ||||
|      # These default values are the ones set on email.policy.default. | ||||
|      # If any of these defaults change, the docs must be updated. | ||||
| @@ -277,6 +278,31 @@ class PolicyAPITests(unittest.TestCase):
 | ||||
|                  with self.assertRaises(email.errors.HeaderParseError): | ||||
|                      policy.fold("Subject", subject) | ||||
|   | ||||
| +    def test_verify_generated_headers(self):
 | ||||
| +        """Turning protection off allows header injection"""
 | ||||
| +        policy = email.policy.default.clone(verify_generated_headers=False)
 | ||||
| +        for text in (
 | ||||
| +            'Header: Value\r\nBad: Injection\r\n',
 | ||||
| +            'Header: NoNewLine'
 | ||||
| +        ):
 | ||||
| +            with self.subTest(text=text):
 | ||||
| +                message = email.message_from_string(
 | ||||
| +                    "Header: Value\r\n\r\nBody",
 | ||||
| +                    policy=policy,
 | ||||
| +                )
 | ||||
| +                class LiteralHeader(str):
 | ||||
| +                    name = 'Header'
 | ||||
| +                    def fold(self, **kwargs):
 | ||||
| +                        return self
 | ||||
| +
 | ||||
| +                del message['Header']
 | ||||
| +                message['Header'] = LiteralHeader(text)
 | ||||
| +
 | ||||
| +                self.assertEqual(
 | ||||
| +                    message.as_string(),
 | ||||
| +                    f"{text}\nBody",
 | ||||
| +                )
 | ||||
| +
 | ||||
|      # XXX: Need subclassing tests. | ||||
|      # For adding subclassed objects, make sure the usual rules apply (subclass | ||||
|      # wins), but that the order still works (right overrides left). | ||||
| diff --git a/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst
 | ||||
| new file mode 100644 | ||||
| index 0000000..83dd28d
 | ||||
| --- /dev/null
 | ||||
| +++ b/Misc/NEWS.d/next/Library/2024-07-27-16-10-41.gh-issue-121650.nf6oc9.rst
 | ||||
| @@ -0,0 +1,5 @@
 | ||||
| +:mod:`email` headers with embedded newlines are now quoted on output. The
 | ||||
| +:mod:`~email.generator` will now refuse to serialize (write) headers that
 | ||||
| +are unsafely folded or delimited; see
 | ||||
| +:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas
 | ||||
| +Bloemsaat and Petr Viktorin in :gh:`121650`.)
 | ||||
| -- 
 | ||||
| 2.45.2 | ||||
| 
 | ||||
| @ -1,18 +0,0 @@ | ||||
| -----BEGIN PGP SIGNATURE----- | ||||
| 
 | ||||
| iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmVyMspfFIAAAAAALgAo | ||||
| aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx | ||||
| Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6 | ||||
| YwWv5w/+JlGtfy+x+6mtauH1uOkt7n9PMQou1LcthDs5s41wuwjO7RbwnmJD6aDk | ||||
| DqwLHheoq6Kjbl6PF1kG2T8ZbHkMudhnc5yH4eQG52IGNQ6evilxoC6AyhVg8ANi | ||||
| +u6Juh9r2Hjz/LDWFB4hzwcOBKy0jYw98+A0uMvpPd2bmdFMBLQE0GTZCdrRsGYs | ||||
| q0oysUX7uCJBfINp7XwiVGAK/6ma0nrr0A1ho6LCau+VGkDnJZdKZgIMyyxp6qL1 | ||||
| 7tMjb3LUpV3FWp57L2za59TaayApNf5BlanC+de6oKEhEJ8oEFyWxOx2GmXHZwch | ||||
| ucj7Z1dxuI7fjNVkEvZ+JuheLGtB9mAmUZslXgUJf5wo49bCo9E4/ZlIFQk7VJR3 | ||||
| Bm9VlQb5mMydB8QJbMy/BpgNjgKmEvBTnir37prJpUV/TL1YZT0eZ5JxCnlUIL/F | ||||
| 6cOzAE3zHPnvHcyHhKV3q5CoONdBtB3RWgS66m4eMneuWoNKaoEbO5IDxtKvCd1J | ||||
| AKLmzCB0/KCWVUIYBTfJ8ytBVQA0Z2w8CZ7SC8asX4DocDCvxim1sQg5s8c4mzh+ | ||||
| 1JVbyqqEmf9m74Mqby0vICC6UVvgaPyiOxTphtRXLIYHUscLVn5+586RMYnM9nP4 | ||||
| nEK+H/fq6Rcp1XEtIPzCG4IPUAYnuDLjbGQegltpKV/SAYn+DGg= | ||||
| =dCpy | ||||
| -----END PGP SIGNATURE----- | ||||
							
								
								
									
										18
									
								
								SOURCES/Python-3.12.5.tar.xz.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								SOURCES/Python-3.12.5.tar.xz.asc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| -----BEGIN PGP SIGNATURE----- | ||||
| 
 | ||||
| iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmayiFtfFIAAAAAALgAo | ||||
| aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx | ||||
| Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6 | ||||
| YwUr4g//VyVs9tvbtiSp8pGe8f1gYErEw54r124sL/CBuNii8Irts1j5ymGxcm+l | ||||
| hshPK5UlqRnhd5dCJWFTvLTXa5Ko2R1L3JyyxfGd1hmDuMhrWsDHijI0R7L/mGM5 | ||||
| 6X2LTaadBVNvk8HaNKvR8SEWvo68rdnOuYElFA9ir7uqwjO26ZWz9FfH80YDGwo8 | ||||
| Blef2NYw8rNhiaZMFV0HYV7D+YyUAZnFNfW8M7Fd4oskUyj1tD9J89T9FFLYN09d | ||||
| BcCIf+EdiEfqRpKxH89bW2g52kDrm4jYGONtpyF8eruyS3YwYSbvbuWioBYKmlxC | ||||
| s51mieXz6G325GTZnmPxLek3ywPv6Gil9y0wH3fIr2BsWsmXust4LBpjDGt56Fy6 | ||||
| seokGBg8xzsBSk3iEqNoFmNsy/QOiuCcDejX4XqBDNodOlETQPJb07TkTI2iOmg9 | ||||
| NG4Atiz1HvGVxK68UuK9IIcNHyaWUmH8h4VQFGvc6KV6feP5Nm21Y12PZ5XIqJBO | ||||
| Y8M/VJIJ5koaNPQfnBbbI5YBkUr4BVpIXIpY5LM/L5sUo2C3R7hMi0VGK88HGfSQ | ||||
| KV4JmZgf6RMBNmrWY12sryS1QQ6q3P110GTUGQWB3sxxNbhmfcrK+4viqHc83yDz | ||||
| ifmk33HuqaQGU7OzUMHeNcoCJIPo3H1FpoHOn9wLLCtA1pT+as4= | ||||
| =t0Rk | ||||
| -----END PGP SIGNATURE----- | ||||
| @ -16,12 +16,12 @@ URL: https://www.python.org/ | ||||
| 
 | ||||
| #  WARNING  When rebasing to a new Python version, | ||||
| #           remember to update the python3-docs package as well | ||||
| %global general_version %{pybasever}.1 | ||||
| %global general_version %{pybasever}.5 | ||||
| #global prerel ... | ||||
| %global upstream_version %{general_version}%{?prerel} | ||||
| Version: %{general_version}%{?prerel:~%{prerel}} | ||||
| Release: 4%{?dist}.4 | ||||
| License: Python | ||||
| Release: 2%{?dist}.1 | ||||
| License: Python-2.0.1 | ||||
| 
 | ||||
| 
 | ||||
| # ================================== | ||||
| @ -66,36 +66,31 @@ License: Python | ||||
| # If the rpmwheels condition is disabled, we use the bundled wheel packages | ||||
| # from Python with the versions below. | ||||
| # This needs to be manually updated when we update Python. | ||||
| %global pip_version 23.2.1 | ||||
| %global pip_version 24.2 | ||||
| %global setuptools_version 67.6.1 | ||||
| %global wheel_version 0.40.0 | ||||
| # All of those also include a list of indirect bundled libs: | ||||
| # pip | ||||
| #  $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt) | ||||
| %global pip_bundled_provides %{expand: | ||||
| Provides: bundled(python3dist(cachecontrol)) = 0.12.11 | ||||
| Provides: bundled(python3dist(certifi)) = 2023.5.7 | ||||
| Provides: bundled(python3dist(chardet)) = 5.1 | ||||
| Provides: bundled(python3dist(colorama)) = 0.4.6 | ||||
| Provides: bundled(python3dist(distlib)) = 0.3.6 | ||||
| Provides: bundled(python3dist(distro)) = 1.8 | ||||
| Provides: bundled(python3dist(idna)) = 3.4 | ||||
| Provides: bundled(python3dist(msgpack)) = 1.0.5 | ||||
| Provides: bundled(python3dist(packaging)) = 21.3 | ||||
| Provides: bundled(python3dist(platformdirs)) = 3.8.1 | ||||
| Provides: bundled(python3dist(pygments)) = 2.15.1 | ||||
| Provides: bundled(python3dist(pyparsing)) = 3.1 | ||||
| Provides: bundled(python3dist(cachecontrol)) = 0.14 | ||||
| Provides: bundled(python3dist(certifi)) = 2024.7.4 | ||||
| Provides: bundled(python3dist(distlib)) = 0.3.8 | ||||
| Provides: bundled(python3dist(distro)) = 1.9 | ||||
| Provides: bundled(python3dist(idna)) = 3.7 | ||||
| Provides: bundled(python3dist(msgpack)) = 1.0.8 | ||||
| Provides: bundled(python3dist(packaging)) = 24.1 | ||||
| Provides: bundled(python3dist(platformdirs)) = 4.2.2 | ||||
| Provides: bundled(python3dist(pygments)) = 2.18 | ||||
| Provides: bundled(python3dist(pyproject-hooks)) = 1 | ||||
| Provides: bundled(python3dist(requests)) = 2.31 | ||||
| Provides: bundled(python3dist(requests)) = 2.32.3 | ||||
| Provides: bundled(python3dist(resolvelib)) = 1.0.1 | ||||
| Provides: bundled(python3dist(rich)) = 13.4.2 | ||||
| Provides: bundled(python3dist(setuptools)) = 68 | ||||
| Provides: bundled(python3dist(six)) = 1.16 | ||||
| Provides: bundled(python3dist(tenacity)) = 8.2.2 | ||||
| Provides: bundled(python3dist(rich)) = 13.7.1 | ||||
| Provides: bundled(python3dist(setuptools)) = 70.3 | ||||
| Provides: bundled(python3dist(tomli)) = 2.0.1 | ||||
| Provides: bundled(python3dist(typing-extensions)) = 4.7.1 | ||||
| Provides: bundled(python3dist(urllib3)) = 1.26.16 | ||||
| Provides: bundled(python3dist(webencodings)) = 0.5.1 | ||||
| Provides: bundled(python3dist(truststore)) = 0.9.1 | ||||
| Provides: bundled(python3dist(typing-extensions)) = 4.12.2 | ||||
| Provides: bundled(python3dist(urllib3)) = 1.26.18 | ||||
| } | ||||
| # setuptools | ||||
| # vendor.txt files not in .whl | ||||
| @ -116,7 +111,7 @@ Provides: bundled(python3dist(typing-extensions)) = 4.4 | ||||
| Provides: bundled(python3dist(zipp)) = 3.7 | ||||
| } | ||||
| # wheel | ||||
| #  $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheel-*.whl wheel/vendored/vendor.txt) | ||||
| #  $ %%{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheeldata/wheel-*.whl wheel/vendored/vendor.txt) | ||||
| %global wheel_bundled_provides %{expand: | ||||
| Provides: bundled(python3dist(packaging)) = 23 | ||||
| } | ||||
| @ -200,6 +195,13 @@ Provides: bundled(python3dist(packaging)) = 23 | ||||
| %global py_INSTSONAME_optimized libpython%{LDVERSION_optimized}.so.%{py_SOVERSION} | ||||
| %global py_INSTSONAME_debug     libpython%{LDVERSION_debug}.so.%{py_SOVERSION} | ||||
| 
 | ||||
| # The -O flag for the compiler, optimized builds | ||||
| # https://fedoraproject.org/wiki/Changes/Python_built_with_gcc_O3 | ||||
| %global optflags_optimized -O3 | ||||
| # The -O flag for the compiler, debug builds | ||||
| # -Wno-cpp avoids some warnings with -O0 | ||||
| %global optflags_debug -O0 -Wno-cpp | ||||
| 
 | ||||
| # Disable automatic bytecompilation. The python3 binary is not yet be | ||||
| # available in /usr/bin when Python is built. Also, the bytecompilation fails | ||||
| # on files that test invalid syntax. | ||||
| @ -386,42 +388,18 @@ Patch397: 00397-tarfile-filter.patch | ||||
| Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-parseaddr-111116.patch | ||||
| 
 | ||||
| # 00422 # a353cebef737c41420dc7ae2469dd657371b8881 | ||||
| # gh-115133: Fix tests for XMLPullParser with Expat 2.6.0 | ||||
| # Fix tests for XMLPullParser with Expat 2.6.0 | ||||
| # | ||||
| # Feeding the parser by too small chunks defers parsing to prevent | ||||
| # CVE-2023-52425. Future versions of Expat may be more reactive. | ||||
| Patch422: 00422-gh-115133-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch | ||||
| 
 | ||||
| # 00435 # | ||||
| # Security fix for CVE-2024-6923 | ||||
| # gh-121650: Encode newlines in headers, and verify headers are sound | ||||
| # | ||||
| # Encode header parts that contain newlines | ||||
| # | ||||
| # Per RFC 2047: | ||||
| # | ||||
| # > [...] these encoding schemes allow the | ||||
| # > encoding of arbitrary octet values, mail readers that implement this | ||||
| # > decoding should also ensure that display of the decoded data on the | ||||
| # > recipient's terminal will not cause unwanted side-effects | ||||
| # | ||||
| # It seems that the "quoted-word" scheme is a valid way to include | ||||
| # a newline character in a header value, just like we already allow | ||||
| # undecodable bytes or control characters. | ||||
| # They do need to be properly quoted when serialized to text, though. | ||||
| # | ||||
| # Verify that email headers are well-formed | ||||
| # | ||||
| # This should fail for custom fold() implementations that aren't careful about newlines. | ||||
| # Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2302255 | ||||
| # Resolved upstream: https://github.com/python/cpython/issues/121650 | ||||
| Patch435: 00435-CVE-2024-6923.patch | ||||
| Patch422: 00422-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch | ||||
| 
 | ||||
| # 00436 # c76cc2aa3a2c30375ade4859b732ada851cc89ed | ||||
| # [CVE-2024-8088] gh-122905: Sanitize names in zipfile.Path. | ||||
| Patch436: 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch | ||||
| 
 | ||||
| # CVE-2024-6232: Remove backtracking when parsing tarfile headers | ||||
| # 00437 # | ||||
| # CVE-2024-6232: gh-121285: Remove backtracking when parsing tarfile headers | ||||
| # Resolved upstream: https://github.com/python/cpython/issues/121285 | ||||
| Patch437: 00437-CVE-2024-6232.patch | ||||
| 
 | ||||
| @ -750,13 +728,13 @@ The debug runtime additionally supports debug builds of C-API extensions | ||||
| # setuptools.whl does not contain the vendored.txt files | ||||
| if [ -f %{_rpmconfigdir}/pythonbundles.py ]; then | ||||
|   %{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/ensurepip/_bundled/pip-*.whl pip/_vendor/vendor.txt) --compare-with '%pip_bundled_provides' | ||||
|   %{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheel-*.whl wheel/vendored/vendor.txt) --compare-with '%wheel_bundled_provides' | ||||
|   %{_rpmconfigdir}/pythonbundles.py <(unzip -p Lib/test/wheeldata/wheel-*.whl wheel/vendored/vendor.txt) --compare-with '%wheel_bundled_provides' | ||||
| fi | ||||
| 
 | ||||
| %if %{with rpmwheels} | ||||
| rm Lib/ensurepip/_bundled/pip-%{pip_version}-py3-none-any.whl | ||||
| rm Lib/test/setuptools-%{setuptools_version}-py3-none-any.whl | ||||
| rm Lib/test/wheel-%{wheel_version}-py3-none-any.whl | ||||
| rm Lib/test/wheeldata/setuptools-%{setuptools_version}-py3-none-any.whl | ||||
| rm Lib/test/wheeldata/wheel-%{wheel_version}-py3-none-any.whl | ||||
| %endif | ||||
| 
 | ||||
| # Remove all exe files to ensure we are not shipping prebuilt binaries | ||||
| @ -835,6 +813,7 @@ BuildPython() { | ||||
|   ConfName=$1 | ||||
|   ExtraConfigArgs=$2 | ||||
|   MoreCFlags=$3 | ||||
|   MoreCFlagsNodist=$4 | ||||
| 
 | ||||
|   # Each build is done in its own directory | ||||
|   ConfDir=build/$ConfName | ||||
| @ -874,7 +853,7 @@ BuildPython() { | ||||
|   $ExtraConfigArgs \ | ||||
|   %{nil} | ||||
| 
 | ||||
| %global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags" | ||||
| %global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags $MoreCFlagsNodist" | ||||
| 
 | ||||
| %if %{without bootstrap} | ||||
|   # Regenerate generated files (needs python3) | ||||
| @ -897,12 +876,14 @@ BuildPython() { | ||||
| # See also: https://bugzilla.redhat.com/show_bug.cgi?id=1818857 | ||||
| BuildPython debug \ | ||||
|   "--without-ensurepip --with-pydebug" \ | ||||
|   "-O0 -Wno-cpp" | ||||
|   "%{optflags_debug}" \ | ||||
|   "" | ||||
| %endif # with debug_build | ||||
| 
 | ||||
| BuildPython optimized \ | ||||
|   "--without-ensurepip %{optimizations_flag}" \ | ||||
|   "" | ||||
|   "" \ | ||||
|   "%{optflags_optimized}" | ||||
| 
 | ||||
| # ====================================================== | ||||
| # Installing the built code: | ||||
| @ -1007,7 +988,7 @@ EOF | ||||
| %if %{with debug_build} | ||||
| InstallPython debug \ | ||||
|   %{py_INSTSONAME_debug} \ | ||||
|   -O0 \ | ||||
|   "%{optflags_debug}" \ | ||||
|   %{LDVERSION_debug} | ||||
| %endif # with debug_build | ||||
| 
 | ||||
| @ -1382,10 +1363,6 @@ CheckPython optimized | ||||
| %{dynload_dir}/termios.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/unicodedata.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_uuid.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxlimited.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxlimited_35.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_xxsubinterpreters.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxsubtype.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/zlib.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_zoneinfo.%{SOABI_optimized}.so | ||||
| 
 | ||||
| @ -1486,12 +1463,6 @@ CheckPython optimized | ||||
| 
 | ||||
| %{pylibdir}/zoneinfo | ||||
| 
 | ||||
| %dir %{pylibdir}/__phello__/ | ||||
| %dir %{pylibdir}/__phello__/__pycache__/ | ||||
| %{pylibdir}/__phello__/__init__.py | ||||
| %{pylibdir}/__phello__/spam.py | ||||
| %{pylibdir}/__phello__/__pycache__/*%{bytecode_suffixes} | ||||
| 
 | ||||
| %if "%{_lib}" == "lib64" | ||||
| %attr(0755,root,root) %dir %{_prefix}/lib/python%{pybasever} | ||||
| %attr(0755,root,root) %dir %{_prefix}/lib/python%{pybasever}/site-packages | ||||
| @ -1586,7 +1557,17 @@ CheckPython optimized | ||||
| %{dynload_dir}/_testmultiphase.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_testsinglephase.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_xxinterpchannels.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_xxsubinterpreters.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/_xxtestfuzz.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxlimited.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxlimited_35.%{SOABI_optimized}.so | ||||
| %{dynload_dir}/xxsubtype.%{SOABI_optimized}.so | ||||
| 
 | ||||
| %dir %{pylibdir}/__phello__/ | ||||
| %dir %{pylibdir}/__phello__/__pycache__/ | ||||
| %{pylibdir}/__phello__/__init__.py | ||||
| %{pylibdir}/__phello__/spam.py | ||||
| %{pylibdir}/__phello__/__pycache__/*%{bytecode_suffixes} | ||||
| 
 | ||||
| # We don't bother splitting the debug build out into further subpackages: | ||||
| # if you need it, you're probably a developer. | ||||
| @ -1668,10 +1649,6 @@ CheckPython optimized | ||||
| %{dynload_dir}/termios.%{SOABI_debug}.so | ||||
| %{dynload_dir}/unicodedata.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_uuid.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxlimited.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxlimited_35.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_xxsubinterpreters.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxsubtype.%{SOABI_debug}.so | ||||
| %{dynload_dir}/zlib.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_zoneinfo.%{SOABI_debug}.so | ||||
| 
 | ||||
| @ -1708,7 +1685,11 @@ CheckPython optimized | ||||
| %{dynload_dir}/_testmultiphase.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_testsinglephase.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_xxinterpchannels.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_xxsubinterpreters.%{SOABI_debug}.so | ||||
| %{dynload_dir}/_xxtestfuzz.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxlimited.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxlimited_35.%{SOABI_debug}.so | ||||
| %{dynload_dir}/xxsubtype.%{SOABI_debug}.so | ||||
| 
 | ||||
| %{pylibdir}/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}.py | ||||
| %{pylibdir}/__pycache__/_sysconfigdata_%{ABIFLAGS_debug}_linux_%{platform_triplet}%{bytecode_suffixes} | ||||
| @ -1736,22 +1717,52 @@ CheckPython optimized | ||||
| # ====================================================== | ||||
| 
 | ||||
| %changelog | ||||
| * Mon Oct 07 2024 Arti Agrawal <artagraw@redhat.com> - 3.12.1-4.4 | ||||
| * Wed Sep 11 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.5-2.1 | ||||
| - Security fix for CVE-2024-6232 | ||||
| Resolves: RHEL-57416 | ||||
| Resolves: RHEL-57415 | ||||
| 
 | ||||
| * Fri Aug 23 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-4.3 | ||||
| * Fri Aug 23 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.5-2 | ||||
| - Security fix for CVE-2024-8088 | ||||
| Resolves: RHEL-55964 | ||||
| Resolves: RHEL-55963 | ||||
| 
 | ||||
| * Mon Aug 12 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-4.2 | ||||
| * Wed Aug 07 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.5-1 | ||||
| - Update to 3.12.5 | ||||
| - Security fix for CVE-2024-6923 | ||||
| Resolves: RHEL-53087 | ||||
| Resolves: RHEL-53041 | ||||
| 
 | ||||
| * Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.1-4.1 | ||||
| - Fix tests for XMLPullParser with Expat with fixed CVE | ||||
| * Thu Jul 25 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-3 | ||||
| - Properly propagate the optimization flags to C extensions | ||||
| 
 | ||||
| * Wed Jul 17 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.4-2 | ||||
| - Build Python with -O3 | ||||
| - https://fedoraproject.org/wiki/Changes/Python_built_with_gcc_O3 | ||||
| 
 | ||||
| * Fri Jun 28 2024 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.12.4-1 | ||||
| - Update to 3.12.4 | ||||
| Resolves: RHEL-44103 | ||||
| 
 | ||||
| * Tue Jun 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.3-2 | ||||
| - Enable importing of hash-based .pyc files under FIPS mode | ||||
| Resolves: RHEL-40773 | ||||
| Resolves: RHEL-40772 | ||||
| 
 | ||||
| * Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.3-1 | ||||
| - Update to 3.12.3 | ||||
| Related: RHEL-33690 | ||||
| 
 | ||||
| * Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-3 | ||||
| - Move all test modules to the python3-test package, namely: | ||||
|    - __phello__ | ||||
|    - _xxsubinterpreters | ||||
|    - xxlimited | ||||
|    - xxlimited_35 | ||||
|    - xxsubtype | ||||
| 
 | ||||
| * Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-2 | ||||
| - Fix tests for XMLPullParser with Expat with fixed CVE | ||||
| 
 | ||||
| * Fri May 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.12.2-1 | ||||
| - Update to 3.12.2 | ||||
| Resolves: RHEL-33690 | ||||
| 
 | ||||
| * Mon Feb 19 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.12.1-4 | ||||
| - Add Red Hat configuration for CVE-2007-4559 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user