- Add patch to fix an issue in the HTML parser where a large number of open elements can cause the parser to become extremely slow by limiting the stack size of open elements (bsc#1251453, CVE-2025-47911) - Add patch to fix an issue in the HTML parser where a specific HTML document can cause the parser to enter an infinite loop when trying to parse a </tbody> and implied </tr> next to each other. (bsc#1251704, CVE-2025-58190) OBS-URL: https://build.opensuse.org/request/show/1309831 OBS-URL: https://build.opensuse.org/package/show/Cloud:Tools/google-osconfig-agent?expand=0&rev=54
99 lines
3.1 KiB
Diff
99 lines
3.1 KiB
Diff
From c217fe54b033f05ca89b931c1650738a68914f30 Mon Sep 17 00:00:00 2001
|
|
From: Roland Shoemaker <roland@golang.org>
|
|
Date: Mon, 29 Sep 2025 16:33:18 -0700
|
|
Subject: [PATCH 2/2] html: impose open element stack size limit
|
|
|
|
The HTML specification contains a number of algorithms which are
|
|
quadratic in complexity by design. Instead of adding complicated
|
|
workarounds to prevent these cases from becoming extremely expensive in
|
|
pathological cases, we impose a limit of 512 to the size of the stack of
|
|
open elements. It is extremely unlikely that non-adversarial HTML
|
|
documents will ever hit this limit (but if we see cases of this, we may
|
|
want to make the limit configurable via a ParseOption).
|
|
|
|
Thanks to Guido Vranken and Jakub Ciolek for both independently
|
|
reporting this issue.
|
|
|
|
Fixes CVE-2025-47911
|
|
Fixes golang/go#75682
|
|
|
|
Change-Id: I890517b189af4ffbf427d25d3fde7ad7ec3509ad
|
|
Reviewed-on: https://go-review.googlesource.com/c/net/+/709876
|
|
Reviewed-by: Damien Neil <dneil@google.com>
|
|
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
|
---
|
|
html/escape.go | 2 +-
|
|
html/parse.go | 21 +++++++++++++++++----
|
|
2 files changed, 18 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/html/escape.go b/html/escape.go
|
|
index 04c6bec..12f2273 100644
|
|
--- a/html/escape.go
|
|
+++ b/html/escape.go
|
|
@@ -299,7 +299,7 @@ func escape(w writer, s string) error {
|
|
case '\r':
|
|
esc = " "
|
|
default:
|
|
- panic("unrecognized escape character")
|
|
+ panic("html: unrecognized escape character")
|
|
}
|
|
s = s[i+1:]
|
|
if _, err := w.WriteString(esc); err != nil {
|
|
diff --git a/html/parse.go b/html/parse.go
|
|
index 722e927..88fc005 100644
|
|
--- a/html/parse.go
|
|
+++ b/html/parse.go
|
|
@@ -231,7 +231,14 @@ func (p *parser) addChild(n *Node) {
|
|
}
|
|
|
|
if n.Type == ElementNode {
|
|
- p.oe = append(p.oe, n)
|
|
+ p.insertOpenElement(n)
|
|
+ }
|
|
+}
|
|
+
|
|
+func (p *parser) insertOpenElement(n *Node) {
|
|
+ p.oe = append(p.oe, n)
|
|
+ if len(p.oe) > 512 {
|
|
+ panic("html: open stack of elements exceeds 512 nodes")
|
|
}
|
|
}
|
|
|
|
@@ -810,7 +817,7 @@ func afterHeadIM(p *parser) bool {
|
|
p.im = inFramesetIM
|
|
return true
|
|
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
|
|
- p.oe = append(p.oe, p.head)
|
|
+ p.insertOpenElement(p.head)
|
|
defer p.oe.remove(p.head)
|
|
return inHeadIM(p)
|
|
case a.Head:
|
|
@@ -2324,9 +2331,13 @@ func (p *parser) parseCurrentToken() {
|
|
}
|
|
}
|
|
|
|
-func (p *parser) parse() error {
|
|
+func (p *parser) parse() (err error) {
|
|
+ defer func() {
|
|
+ if panicErr := recover(); panicErr != nil {
|
|
+ err = fmt.Errorf("%s", panicErr)
|
|
+ }
|
|
+ }()
|
|
// Iterate until EOF. Any other error will cause an early return.
|
|
- var err error
|
|
for err != io.EOF {
|
|
// CDATA sections are allowed only in foreign content.
|
|
n := p.oe.top()
|
|
@@ -2355,6 +2366,8 @@ func (p *parser) parse() error {
|
|
// <tag>s. Conversely, explicit <tag>s in r's data can be silently dropped,
|
|
// with no corresponding node in the resulting tree.
|
|
//
|
|
+// Parse will reject HTML that is nested deeper than 512 elements.
|
|
+//
|
|
// The input is assumed to be UTF-8 encoded.
|
|
func Parse(r io.Reader) (*Node, error) {
|
|
return ParseWithOptions(r)
|
|
--
|
|
2.51.0
|
|
|