diff mbox series

[scarthgap,08/14] go: patch CVE-2026-39820

Message ID 20260521100949.1299757-8-tgaige.opensource@witekio.com
State New
Headers show
Series [scarthgap,01/14] go: patch CVE-2026-27142 | expand

Commit Message

tgaige.opensource@witekio.com May 21, 2026, 10:09 a.m. UTC
From: "Theo Gaige (Schneider Electric)" <tgaige.opensource@witekio.com>

Backport patch from [1] mentionned in [2]

[1] https://go.dev/cl/759940

[2] https://security-tracker.debian.org/tracker/CVE-2026-39820

Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
Reviewed-by: Bruno Vernay <bruno.vernay@se.com>
---
 meta/recipes-devtools/go/go-1.22.12.inc       |   1 +
 .../go/go/CVE-2026-39820.patch                | 112 ++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 meta/recipes-devtools/go/go/CVE-2026-39820.patch
diff mbox series

Patch

diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc
index dba826011b..002d443059 100644
--- a/meta/recipes-devtools/go/go-1.22.12.inc
+++ b/meta/recipes-devtools/go/go-1.22.12.inc
@@ -48,6 +48,7 @@  SRC_URI += "\
     file://CVE-2026-33811.patch \
     file://CVE-2026-39817.patch \
     file://CVE-2026-39819.patch \
+    file://CVE-2026-39820.patch \
 "
 SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71"
 
diff --git a/meta/recipes-devtools/go/go/CVE-2026-39820.patch b/meta/recipes-devtools/go/go/CVE-2026-39820.patch
new file mode 100644
index 0000000000..c5f84282a9
--- /dev/null
+++ b/meta/recipes-devtools/go/go/CVE-2026-39820.patch
@@ -0,0 +1,112 @@ 
+From e459f8fe1061679f866c599210466db386348f08 Mon Sep 17 00:00:00 2001
+From: mohammadmseet-hue <mohammadmseet@gmail.com>
+Date: Sat, 4 Apr 2026 05:17:25 +0000
+Subject: [PATCH] net/mail: fix quadratic complexity in consumeComment
+
+consumeComment builds the comment string by repeated string
+concatenation inside a loop. Each concatenation copies the
+entire string built so far, making the function O(n^2) in the
+depth of nested comments.
+
+Replace the concatenation with a strings.Builder, which
+amortizes allocation by doubling its internal buffer. This
+reduces consumeComment from O(n^2) to O(n).
+
+This is the same bug class as the consumeDomainLiteral fix
+in CVE-2025-61725.
+
+Benchmark results (benchstat, 8 runs):
+
+  name                        old time/op  new time/op  delta
+  ConsumeComment/depth10      2.481us      1.838us      -25.92%
+  ConsumeComment/depth100     86.58us      6.498us      -92.50%
+  ConsumeComment/depth1000    7.963ms      52.82us      -99.34%
+  ConsumeComment/depth10000   897.8ms      521.3us      -99.94%
+
+The quadratic cost becomes visible at depth 100 and dominant
+by depth 1000. At depth 10000, the fix is roughly 1700x
+faster.
+
+Change-Id: I3c927f02646fcab7bab167cb82fd46d3327d6d34
+GitHub-Last-Rev: 7742dad716ee371766543f88e82bd163bd9d7ac2
+GitHub-Pull-Request: golang/go#78393
+Reviewed-on: https://go-review.googlesource.com/c/go/+/759940
+Reviewed-by: Sean Liao <sean@liao.dev>
+LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
+Auto-Submit: Sean Liao <sean@liao.dev>
+Reviewed-by: David Chase <drchase@google.com>
+Reviewed-by: Junyang Shao <shaojunyang@google.com>
+
+CVE: CVE-2026-39820
+Upstream-Status: Backport [https://github.com/golang/go/commit/0d0799f055dcc9b3b41df74bee3fbe398ae2f0e7]
+Signed-off-by: Theo Gaige (Schneider Electric) <tgaige.opensource@witekio.com>
+---
+ src/net/mail/message.go      |  6 +++---
+ src/net/mail/message_test.go | 19 +++++++++++++++++++
+ 2 files changed, 22 insertions(+), 3 deletions(-)
+
+diff --git a/src/net/mail/message.go b/src/net/mail/message.go
+index fc2a9e46f8..37d7ff5df1 100644
+--- a/src/net/mail/message.go
++++ b/src/net/mail/message.go
+@@ -780,7 +780,7 @@ func (p *addrParser) consumeComment() (string, bool) {
+ 	// '(' already consumed.
+ 	depth := 1
+ 
+-	var comment string
++	var comment strings.Builder
+ 	for {
+ 		if p.empty() || depth == 0 {
+ 			break
+@@ -794,12 +794,12 @@ func (p *addrParser) consumeComment() (string, bool) {
+ 			depth--
+ 		}
+ 		if depth > 0 {
+-			comment += p.s[:1]
++			comment.WriteByte(p.s[0])
+ 		}
+ 		p.s = p.s[1:]
+ 	}
+ 
+-	return comment, depth == 0
++	return comment.String(), depth == 0
+ }
+ 
+ func (p *addrParser) decodeRFC2047Word(s string) (word string, isEncoded bool, err error) {
+diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
+index 1f2f62afbf..1b165317f9 100644
+--- a/src/net/mail/message_test.go
++++ b/src/net/mail/message_test.go
+@@ -6,6 +6,7 @@ package mail
+ 
+ import (
+ 	"bytes"
++	"fmt"
+ 	"io"
+ 	"mime"
+ 	"reflect"
+@@ -1217,3 +1218,21 @@ func TestEmptyAddress(t *testing.T) {
+ 		t.Errorf(`ParseAddressList("") = %v, %v, want nil, error`, list, err)
+ 	}
+ }
++
++func BenchmarkConsumeComment(b *testing.B) {
++	for _, n := range []int{10, 100, 1000, 10000} {
++		b.Run(fmt.Sprintf("depth-%d", n), func(b *testing.B) {
++			// Build a deeply nested comment: (((...a...)))
++			open := strings.Repeat("(", n)
++			close := strings.Repeat(")", n)
++			// consumeComment expects the leading '(' already consumed,
++			// so we start with one fewer opening paren and the parser
++			// will handle nesting from there.
++			input := open[:n-1] + "a" + close
++			for b.Loop() {
++				p := addrParser{s: input}
++				p.consumeComment()
++			}
++		})
++	}
++}
+-- 
+2.43.0
+