All of lore.kernel.org
 help / color / mirror / Atom feed
* [OE-core][scarthgap][PATCH] python3-idna: Fix CVE-2026-45409
@ 2026-08-20  5:56 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)
  0 siblings, 0 replies; only message in thread
From: Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco) @ 2026-08-20  5:56 UTC (permalink / raw)
  To: openembedded-core; +Cc: xe-linux-external, Hetvi Thakar

From: Hetvi Thakar <hthakar@cisco.com>

This patch applies the complete upstream fix chain for
CVE-2026-45409. Commit [1] introduces early domain-length rejection
required by [2]. Commit [2] is the v3.14 fix identified by [5], and
commit [3] extends the protection to per-label conversions and codec
support to complete the v3.15 fix described in [4].

[1] https://github.com/kjd/idna/commit/c0dda4501df5
[2] https://github.com/kjd/idna/commit/628fef84d3ed
[3] https://github.com/kjd/idna/commit/e1cb465b6376
[4] https://github.com/kjd/idna/security/advisories/GHSA-65pc-fj4g-8rjx
[5] https://security-tracker.debian.org/tracker/CVE-2026-45409

Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
---
 .../python3-idna/CVE-2026-45409_p1.patch      | 75 +++++++++++++++++++
 .../python3-idna/CVE-2026-45409_p2.patch      | 48 ++++++++++++
 .../python3-idna/CVE-2026-45409_p3.patch      | 72 ++++++++++++++++++
 .../python/python3-idna_3.7.bb                |  5 ++
 4 files changed, 200 insertions(+)
 create mode 100644 meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p1.patch
 create mode 100644 meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p2.patch
 create mode 100644 meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p3.patch

diff --git a/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p1.patch b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p1.patch
new file mode 100644
index 0000000000..02a8090b84
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p1.patch
@@ -0,0 +1,75 @@
+From b34cd8399981324b361ae4f2b8e0eb77444ae0e3 Mon Sep 17 00:00:00 2001
+From: Kim Davies <kim@cynosure.com.au>
+Date: Sun, 10 May 2026 08:47:22 -0700
+Subject: [PATCH 1/3] Merge commit from fork
+
+CVE: CVE-2026-45409
+Upstream-Status: Backport [https://github.com/kjd/idna/commit/c0dda4501df5d91c3181ce6f962dc5de74e82cc1]
+
+Backport Changes:
+- Omit the HISTORY.rst hunk because it documents the upstream 3.14
+  release and is not applicable to the Scarthgap 3.7 source.
+
+(cherry picked from commit c0dda4501df5d91c3181ce6f962dc5de74e82cc1)
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ idna/core.py       | 14 ++++++++++++++
+ tests/test_idna.py | 13 +++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/idna/core.py b/idna/core.py
+index 0dae61a..a549326 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -340,6 +340,15 @@ def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
+             raise IDNAError('should pass a unicode string to the function rather than a byte string.')
+     if uts46:
+         s = uts46_remap(s, std3_rules, transitional)
++
++    # Reject inputs that exceed the maximum DNS domain length up-front.
++    # Each codepoint in a U-label contributes at least one octet to its
++    # A-label form, so any input longer than the domain limit cannot
++    # produce a valid A-domain. Short-circuiting here prevents per-label
++    # validation from being driven into quadratic time
++    if len(s) > 254:
++        raise IDNAError("Domain too long")
++
+     trailing_dot = False
+     result = []
+     if strict:
+@@ -373,6 +382,11 @@ def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
+         raise IDNAError('Invalid ASCII in A-label')
+     if uts46:
+         s = uts46_remap(s, std3_rules, False)
++    # See encode() for rationale; the same bound applies because every
++    # legal A-domain is at most 254 octets and every codepoint of a
++    # legal U-domain contributes at least one octet to its A-form.
++    if len(s) > 254:
++        raise IDNAError("Domain too long")
+     trailing_dot = False
+     result = []
+     if not strict:
+diff --git a/tests/test_idna.py b/tests/test_idna.py
+index 81afb32..5001b48 100755
+--- a/tests/test_idna.py
++++ b/tests/test_idna.py
+@@ -78,6 +78,19 @@ class IDNATests(unittest.TestCase):
+         self.assertFalse(idna.valid_label_length('a' * 64))
+         self.assertRaises(idna.IDNAError, idna.encode, 'a' * 64)
+ 
++    def test_oversized_input_rejected_promptly(self):
++        # GHSA-65pc-fj4g-8rjx: encode/decode must reject inputs that
++        # exceed the maximum DNS domain length before per-codepoint
++        # validation runs, so labels dominated by CONTEXTO codepoints
++        # cannot drive validation into quadratic time.
++        import time
++
++        for payload in ("٠" * 8000, "・" * 8000 + "漢"):
++            start = time.perf_counter()
++            self.assertRaises(idna.IDNAError, idna.encode, payload)
++            self.assertRaises(idna.IDNAError, idna.decode, payload)
++            self.assertLess(time.perf_counter() - start, 1.0)
++
+     def test_check_bidi(self):
+ 
+         l = '\u0061'
diff --git a/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p2.patch b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p2.patch
new file mode 100644
index 0000000000..a79e1e9c20
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p2.patch
@@ -0,0 +1,48 @@
+From fabb538f1885a135e48a60de2e3c656d965e861d Mon Sep 17 00:00:00 2001
+From: Kim Davies <kim@cynosure.com.au>
+Date: Sun, 10 May 2026 12:44:47 -0700
+Subject: [PATCH 2/3] Use valid_string_length() for early oversized-input check
+
+CVE: CVE-2026-45409
+Upstream-Status: Backport [https://github.com/kjd/idna/commit/628fef84d3eda59321c21127e73dcd873db23ead]
+
+(cherry picked from commit 628fef84d3eda59321c21127e73dcd873db23ead)
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ idna/core.py | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+diff --git a/idna/core.py b/idna/core.py
+index a549326..4a9fc75 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -341,12 +341,9 @@ def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
+     if uts46:
+         s = uts46_remap(s, std3_rules, transitional)
+ 
+-    # Reject inputs that exceed the maximum DNS domain length up-front.
+-    # Each codepoint in a U-label contributes at least one octet to its
+-    # A-label form, so any input longer than the domain limit cannot
+-    # produce a valid A-domain. Short-circuiting here prevents per-label
+-    # validation from being driven into quadratic time
+-    if len(s) > 254:
++    # Reject inputs that exceed the maximum DNS domain length up-front
++    # to avoid expensive computation on long inputs.
++    if not valid_string_length(s, trailing_dot=True):
+         raise IDNAError("Domain too long")
+ 
+     trailing_dot = False
+@@ -382,10 +379,9 @@ def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool =
+         raise IDNAError('Invalid ASCII in A-label')
+     if uts46:
+         s = uts46_remap(s, std3_rules, False)
+-    # See encode() for rationale; the same bound applies because every
+-    # legal A-domain is at most 254 octets and every codepoint of a
+-    # legal U-domain contributes at least one octet to its A-form.
+-    if len(s) > 254:
++    # Reject inputs that exceed the maximum DNS domain length up-front
++    # to avoid expensive computation on long inputs.
++    if not valid_string_length(s, trailing_dot=True):
+         raise IDNAError("Domain too long")
+     trailing_dot = False
+     result = []
diff --git a/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p3.patch b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p3.patch
new file mode 100644
index 0000000000..2ebbd5c13d
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-idna/CVE-2026-45409_p3.patch
@@ -0,0 +1,72 @@
+From 22acbaae97c3698005e69555eb4ebccc168b2fff Mon Sep 17 00:00:00 2001
+From: metsw24-max <metsw24@gmail.com>
+Date: Mon, 11 May 2026 20:59:30 +0530
+Subject: [PATCH 3/3] Enforce early length limits in check_label
+
+CVE: CVE-2026-45409
+Upstream-Status: Backport [https://github.com/kjd/idna/commit/e1cb465b6376f33306a26f467d197edbcd01c4b9]
+
+(cherry picked from commit e1cb465b6376f33306a26f467d197edbcd01c4b9)
+Signed-off-by: Hetvi Thakar <hthakar@cisco.com>
+---
+ idna/core.py       | 11 +++++++++++
+ tests/test_idna.py | 24 ++++++++++++++++++++++++
+ 2 files changed, 35 insertions(+)
+
+diff --git a/idna/core.py b/idna/core.py
+index 4a9fc75..26bb9fa 100644
+--- a/idna/core.py
++++ b/idna/core.py
+@@ -230,6 +230,17 @@ def check_label(label: Union[str, bytes, bytearray]) -> None:
+         label = label.decode('utf-8')
+     if len(label) == 0:
+         raise IDNAError('Empty Label')
++    # Reject oversized labels before per-codepoint validation runs.
++    # CONTEXTJ/CONTEXTO checks scan the whole label per codepoint, so an
++    # uncapped label drives validation into quadratic time
++    # (GHSA-65pc-fj4g-8rjx / CVE-2024-3651). encode()/decode() cap the
++    # whole-domain length; this cap protects direct callers of
++    # alabel/ulabel/check_label and the idna2008 incremental codec.
++    # Use the whole-domain bound rather than the per-label DNS bound so
++    # that UTS #46 lenient decoding of labels longer than 63 chars is
++    # preserved.
++    if not valid_string_length(label, trailing_dot=True):
++        raise IDNAError("Label too long")
+ 
+     check_nfc(label)
+     check_hyphen_ok(label)
+diff --git a/tests/test_idna.py b/tests/test_idna.py
+index 5001b48..2dc0892 100755
+--- a/tests/test_idna.py
++++ b/tests/test_idna.py
+@@ -91,6 +91,30 @@ class IDNATests(unittest.TestCase):
+             self.assertRaises(idna.IDNAError, idna.decode, payload)
+             self.assertLess(time.perf_counter() - start, 1.0)
+ 
++    def test_oversized_label_rejected_promptly(self):
++        # The whole-domain cap in encode()/decode() does not cover direct
++        # callers of alabel/ulabel/check_label, nor the idna2008
++        # incremental codec which calls alabel/ulabel per label. Without a
++        # per-label cap, a single oversized CONTEXTO-heavy label still
++        # drives validation into quadratic time.
++        import codecs
++        import time
++
++        import idna.codec  # noqa: F401  (register the idna2008 codec)
++
++        payload = "・" * 8000 + "漢"
++        start = time.perf_counter()
++        self.assertRaises(idna.IDNAError, idna.check_label, payload)
++        self.assertRaises(idna.IDNAError, idna.alabel, payload)
++        self.assertRaises(idna.IDNAError, idna.ulabel, payload)
++        self.assertRaises(
++            idna.IDNAError,
++            codecs.getincrementalencoder("idna2008")().encode,
++            payload,
++            True,
++        )
++        self.assertLess(time.perf_counter() - start, 1.0)
++
+     def test_check_bidi(self):
+ 
+         l = '\u0061'
diff --git a/meta/recipes-devtools/python/python3-idna_3.7.bb b/meta/recipes-devtools/python/python3-idna_3.7.bb
index 729aff1c46..5322984a24 100644
--- a/meta/recipes-devtools/python/python3-idna_3.7.bb
+++ b/meta/recipes-devtools/python/python3-idna_3.7.bb
@@ -3,6 +3,11 @@ HOMEPAGE = "https://github.com/kjd/idna"
 LICENSE = "BSD-3-Clause & Python-2.0 & Unicode-TOU"
 LIC_FILES_CHKSUM = "file://LICENSE.md;md5=204c0612e40a4dd46012a78d02c80fb1"
 
+SRC_URI += " \
+    file://CVE-2026-45409_p1.patch \
+    file://CVE-2026-45409_p2.patch \
+    file://CVE-2026-45409_p3.patch \
+"
 SRC_URI[sha256sum] = "028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"
 
 inherit pypi python_flit_core
-- 
2.35.6



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-08-20  5:56 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20  5:56 [OE-core][scarthgap][PATCH] python3-idna: Fix CVE-2026-45409 Hetvi Thakar -X (hthakar - E INFOCHIPS PRIVATE LIMITED at Cisco)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.