Blame SOURCES/00394-cve-2022-45061-cpu-denial-of-service-via-inefficient-idna-decoder.patch

a80c65
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a80c65
From: "Miss Islington (bot)"
a80c65
 <31488909+miss-islington@users.noreply.github.com>
a80c65
Date: Mon, 7 Nov 2022 19:22:14 -0800
a80c65
Subject: [PATCH] 00394: CVE-2022-45061: CPU denial of service via inefficient
a80c65
 IDNA decoder
a80c65
a80c65
gh-98433: Fix quadratic time idna decoding.
a80c65
a80c65
There was an unnecessary quadratic loop in idna decoding. This restores
a80c65
the behavior to linear.
a80c65
a80c65
(cherry picked from commit a6f6c3a3d6f2b580f2d87885c9b8a9350ad7bf15)
a80c65
a80c65
Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
a80c65
Co-authored-by: Gregory P. Smith <greg@krypto.org>
a80c65
---
a80c65
 Lib/encodings/idna.py                         | 32 +++++++++----------
a80c65
 Lib/test/test_codecs.py                       |  6 ++++
a80c65
 ...2-11-04-09-29-36.gh-issue-98433.l76c5G.rst |  6 ++++
a80c65
 3 files changed, 27 insertions(+), 17 deletions(-)
a80c65
 create mode 100644 Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
a80c65
a80c65
diff --git a/Lib/encodings/idna.py b/Lib/encodings/idna.py
a80c65
index ea4058512f..bf98f51336 100644
a80c65
--- a/Lib/encodings/idna.py
a80c65
+++ b/Lib/encodings/idna.py
a80c65
@@ -39,23 +39,21 @@ def nameprep(label):
a80c65
 
a80c65
     # Check bidi
a80c65
     RandAL = [stringprep.in_table_d1(x) for x in label]
a80c65
-    for c in RandAL:
a80c65
-        if c:
a80c65
-            # There is a RandAL char in the string. Must perform further
a80c65
-            # tests:
a80c65
-            # 1) The characters in section 5.8 MUST be prohibited.
a80c65
-            # This is table C.8, which was already checked
a80c65
-            # 2) If a string contains any RandALCat character, the string
a80c65
-            # MUST NOT contain any LCat character.
a80c65
-            if any(stringprep.in_table_d2(x) for x in label):
a80c65
-                raise UnicodeError("Violation of BIDI requirement 2")
a80c65
-
a80c65
-            # 3) If a string contains any RandALCat character, a
a80c65
-            # RandALCat character MUST be the first character of the
a80c65
-            # string, and a RandALCat character MUST be the last
a80c65
-            # character of the string.
a80c65
-            if not RandAL[0] or not RandAL[-1]:
a80c65
-                raise UnicodeError("Violation of BIDI requirement 3")
a80c65
+    if any(RandAL):
a80c65
+        # There is a RandAL char in the string. Must perform further
a80c65
+        # tests:
a80c65
+        # 1) The characters in section 5.8 MUST be prohibited.
a80c65
+        # This is table C.8, which was already checked
a80c65
+        # 2) If a string contains any RandALCat character, the string
a80c65
+        # MUST NOT contain any LCat character.
a80c65
+        if any(stringprep.in_table_d2(x) for x in label):
a80c65
+            raise UnicodeError("Violation of BIDI requirement 2")
a80c65
+        # 3) If a string contains any RandALCat character, a
a80c65
+        # RandALCat character MUST be the first character of the
a80c65
+        # string, and a RandALCat character MUST be the last
a80c65
+        # character of the string.
a80c65
+        if not RandAL[0] or not RandAL[-1]:
a80c65
+            raise UnicodeError("Violation of BIDI requirement 3")
a80c65
 
a80c65
     return label
a80c65
 
a80c65
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
a80c65
index 56485de3f6..a798d1f287 100644
a80c65
--- a/Lib/test/test_codecs.py
a80c65
+++ b/Lib/test/test_codecs.py
a80c65
@@ -1640,6 +1640,12 @@ class IDNACodecTest(unittest.TestCase):
a80c65
         self.assertEqual("pyth\xf6n.org".encode("idna"), b"xn--pythn-mua.org")
a80c65
         self.assertEqual("pyth\xf6n.org.".encode("idna"), b"xn--pythn-mua.org.")
a80c65
 
a80c65
+    def test_builtin_decode_length_limit(self):
a80c65
+        with self.assertRaisesRegex(UnicodeError, "too long"):
a80c65
+            (b"xn--016c"+b"a"*1100).decode("idna")
a80c65
+        with self.assertRaisesRegex(UnicodeError, "too long"):
a80c65
+            (b"xn--016c"+b"a"*70).decode("idna")
a80c65
+
a80c65
     def test_stream(self):
a80c65
         r = codecs.getreader("idna")(io.BytesIO(b"abc"))
a80c65
         r.read(3)
a80c65
diff --git a/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst b/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
a80c65
new file mode 100644
a80c65
index 0000000000..5185fac2e2
a80c65
--- /dev/null
a80c65
+++ b/Misc/NEWS.d/next/Security/2022-11-04-09-29-36.gh-issue-98433.l76c5G.rst
a80c65
@@ -0,0 +1,6 @@
a80c65
+The IDNA codec decoder used on DNS hostnames by :mod:`socket` or :mod:`asyncio`
a80c65
+related name resolution functions no longer involves a quadratic algorithm.
a80c65
+This prevents a potential CPU denial of service if an out-of-spec excessive
a80c65
+length hostname involving bidirectional characters were decoded. Some protocols
a80c65
+such as :mod:`urllib` http ``3xx`` redirects potentially allow for an attacker
a80c65
+to supply such a name.