All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" <deeratho@cisco.com>
To: openembedded-core@lists.openembedded.org
Subject: [OE-core][scarthgap][PATCH] python3: fix CVE-2026-15308
Date: Thu, 23 Jul 2026 19:13:04 +0530	[thread overview]
Message-ID: <20260723134304.2505230-1-deeratho@cisco.com> (raw)

From: Deepak Rathore <deeratho@cisco.com>

Backport the upstream CPython fix for CVE-2026-15308 to Python
3.12.13. The issue is a CPU denial of service in incremental
html.parser.HTMLParser parsing, where repeated feed() calls with
unterminated markup could repeatedly rescan and concatenate a growing
buffer.

The embedded patch is based on the Python 3.13 backport in [1]. The
public CVE advisory is referenced in [2]. Scarthgap-specific source
differences are recorded under Backport Changes in the embedded patch
header.

[1] https://github.com/python/cpython/commit/7933f4bf7131aa4140750f9404f5de0aa2969ced
[2] https://nvd.nist.gov/vuln/detail/CVE-2026-15308

Signed-off-by: Deepak Rathore <deeratho@cisco.com>
---
 .../python/python3/CVE-2026-15308.patch       | 116 ++++++++++++++++++
 .../python/python3_3.12.13.bb                 |   1 +
 2 files changed, 117 insertions(+)
 create mode 100644 meta/recipes-devtools/python/python3/CVE-2026-15308.patch

diff --git a/meta/recipes-devtools/python/python3/CVE-2026-15308.patch b/meta/recipes-devtools/python/python3/CVE-2026-15308.patch
new file mode 100644
index 0000000000..7ed63b17ce
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2026-15308.patch
@@ -0,0 +1,116 @@
+From b30795b2ecf621df2c09b059b9fa7d881f537378 Mon Sep 17 00:00:00 2001
+From: "Miss Islington (bot)"
+ <31488909+miss-islington@users.noreply.github.com>
+Date: Sat, 4 Jul 2026 20:01:22 +0200
+Subject: [PATCH] [3.13] gh-153030: Fix quadratic complexity in incremental
+ parsing in HTMLParser (GH-153031) (GH-153040)
+
+When an unterminated construct (e.g. a tag or comment) spanned many
+feed() calls, rescanning the growing buffer and concatenating new data
+onto it were both quadratic.  New data is now accumulated in a list and
+only joined and parsed once enough has piled up.
+
+CVE: CVE-2026-15308
+Upstream-Status: Backport [https://github.com/python/cpython/commit/7933f4bf7131aa4140750f9404f5de0aa2969ced]
+
+Backport Changes:
+- Omitted Misc/NEWS.d/next/Security/2026-07-04-17-00-00.gh-issue-153030.RovkP6.rst
+  because the target source does not carry pending NEWS fragments.
+
+(cherry picked from commit bcf98ddbc40ec9b3ee87da0124a5660b19b7e606)
+Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
+Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
+(cherry picked from commit 7933f4bf7131aa4140750f9404f5de0aa2969ced)
+Signed-off-by: Deepak Rathore <deeratho@cisco.com>
+
+---
+ Lib/html/parser.py          | 32 ++++++++++++++++++++++++++++++--
+ Lib/test/test_htmlparser.py | 20 ++++++++++++++++++++
+ 2 files changed, 50 insertions(+), 2 deletions(-)
+
+diff --git a/Lib/html/parser.py b/Lib/html/parser.py
+index bfab3e64cd5..c5d2340b712 100644
+--- a/Lib/html/parser.py
++++ b/Lib/html/parser.py
+@@ -138,6 +138,9 @@ class HTMLParser(_markupbase.ParserBase):
+         self.cdata_elem = None
+         self._support_cdata = True
+         self._escapable = True
++        self._pending = []
++        self._pending_len = 0
++        self._parse_threshold = 1
+         super().reset()
+
+     def feed(self, data):
+@@ -146,11 +149,36 @@ class HTMLParser(_markupbase.ParserBase):
+         Call this as often as you want, with as little or as much text
+         as you want (may include '\n').
+         """
+-        self.rawdata = self.rawdata + data
+-        self.goahead(0)
++        # Accumulate new data in a list and only join and parse it once
++        # enough has piled up.  Rescanning an unparsed buffer (e.g. an
++        # unterminated tag) and concatenating onto it on every call would
++        # both be quadratic in the input size.
++        self._pending_len += len(data)
++        if self._pending_len < self._parse_threshold:
++            self._pending.append(data)
++        else:
++            if not self._pending:
++                self.rawdata += data
++            else:
++                self._pending.append(data)
++                self.rawdata += ''.join(self._pending)
++                self._pending.clear()
++            self._pending_len = 0
++            n = len(self.rawdata)
++            self.goahead(0)
++            if len(self.rawdata) < n:
++                # Some data was parsed; resume on the next call.
++                self._parse_threshold = 1
++            else:
++                # Nothing was parsed; wait until the buffer doubles.
++                self._parse_threshold = len(self.rawdata)
+
+     def close(self):
+         """Handle any buffered data."""
++        if self._pending:
++            self.rawdata += ''.join(self._pending)
++            self._pending.clear()
++            self._pending_len = 0
+         self.goahead(1)
+
+     __starttag_text = None
+diff --git a/Lib/test/test_htmlparser.py b/Lib/test/test_htmlparser.py
+index 303c0baa87b..e6d92a7ec51 100644
+--- a/Lib/test/test_htmlparser.py
++++ b/Lib/test/test_htmlparser.py
+@@ -930,6 +930,26 @@ text
+         check("<![CDATA[" * 9 * n)
+         check("<!doctype" * 35 * n)
+
++    @support.requires_resource('cpu')
++    def test_incremental_no_quadratic_complexity(self):
++        # An unterminated construct fed in many small chunks used to take
++        # quadratic time, both to rescan and to concatenate the buffer.
++        # Now it takes a fraction of a second.
++        def check(prefix, chunk, suffix):
++            parser = html.parser.HTMLParser()
++            parser.feed(prefix)
++            for _ in range(200_000):
++                parser.feed(chunk)
++            parser.feed(suffix)
++            parser.close()
++        chunk = "a" * 64
++        check("<!--", chunk, "-->")       # comment
++        check("<?", chunk, ">")           # processing instruction
++        check("<!doctype ", chunk, ">")   # doctype
++        check("<![CDATA[", chunk, "]]>")  # CDATA section
++        check("<a href='", chunk, "'>")   # start tag
++        check("<script>", chunk, "</script>")  # RAWTEXT element
++
+
+ class AttributesTestCase(TestCaseBase):
+
+--
+2.51.0
diff --git a/meta/recipes-devtools/python/python3_3.12.13.bb b/meta/recipes-devtools/python/python3_3.12.13.bb
index de174f7bfd..a3d07d14a4 100644
--- a/meta/recipes-devtools/python/python3_3.12.13.bb
+++ b/meta/recipes-devtools/python/python3_3.12.13.bb
@@ -47,6 +47,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
            file://CVE-2026-11940.patch \
            file://CVE-2026-11972.patch \
            file://CVE-2026-9669.patch \
+           file://CVE-2026-15308.patch \
            "
 
 SRC_URI:append:class-native = " \
-- 
2.35.6


             reply	other threads:[~2026-07-23 13:43 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-23 13:43 Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco) [this message]
2026-07-27 15:52 ` [OE-core][scarthgap][PATCH] python3: fix CVE-2026-15308 Yoann Congal
2026-08-31 12:57 ` Yoann Congal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260723134304.2505230-1-deeratho@cisco.com \
    --to=deeratho@cisco.com \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.