mirror of
https://git.yoctoproject.org/git/poky
synced 2026-01-01 13:58:04 +00:00
go: fix CVE-2025-61723
The processing time for parsing some invalid inputs scales non-linearly with respect to the size of the input. This affects programs which parse untrusted PEM inputs. (From OE-Core rev: cfafebef95330e531ab7bb590e5fb566dd5a3dce) Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
parent
5f8155aefa
commit
46c836aefa
|
|
@ -71,6 +71,7 @@ SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \
|
||||||
file://CVE-2024-24783.patch \
|
file://CVE-2024-24783.patch \
|
||||||
file://CVE-2025-58187.patch \
|
file://CVE-2025-58187.patch \
|
||||||
file://CVE-2025-58189.patch \
|
file://CVE-2025-58189.patch \
|
||||||
|
file://CVE-2025-61723.patch \
|
||||||
"
|
"
|
||||||
SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd"
|
SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd"
|
||||||
|
|
||||||
|
|
|
||||||
221
meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch
Normal file
221
meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
From 74d4d836b91318a8764b94bc2b4b66ff599eb5f2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Roland Shoemaker <bracewell@google.com>
|
||||||
|
Date: Tue, 30 Sep 2025 11:16:56 -0700
|
||||||
|
Subject: [PATCH] encoding/pem: make Decode complexity linear Because Decode
|
||||||
|
scanned the input first for the first BEGIN line, and then the first END
|
||||||
|
line, the complexity of Decode is quadratic. If the input contained a large
|
||||||
|
number of BEGINs and then a single END right at the end of the input, we
|
||||||
|
would find the first BEGIN, and then scan the entire input for the END, and
|
||||||
|
fail to parse the block, so move onto the next BEGIN, scan the entire input
|
||||||
|
for the END, etc.
|
||||||
|
|
||||||
|
Instead, look for the first END in the input, and then the first BEGIN
|
||||||
|
that precedes the found END. We then process the bytes between the BEGIN
|
||||||
|
and END, and move onto the bytes after the END for further processing.
|
||||||
|
This gives us linear complexity.
|
||||||
|
|
||||||
|
Fixes CVE-2025-61723
|
||||||
|
For #75676
|
||||||
|
Fixes #75708
|
||||||
|
|
||||||
|
Change-Id: I813c4f63e78bca4054226c53e13865c781564ccf
|
||||||
|
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2921
|
||||||
|
Reviewed-by: Nicholas Husin <husin@google.com>
|
||||||
|
Reviewed-by: Damien Neil <dneil@google.com>
|
||||||
|
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2986
|
||||||
|
Reviewed-on: https://go-review.googlesource.com/c/go/+/709842
|
||||||
|
TryBot-Bypass: Michael Pratt <mpratt@google.com>
|
||||||
|
Auto-Submit: Michael Pratt <mpratt@google.com>
|
||||||
|
Reviewed-by: Carlos Amedee <carlos@golang.org>
|
||||||
|
|
||||||
|
CVE: CVE-2025-61723
|
||||||
|
|
||||||
|
Upstream-Status: Backport [https://github.com/golang/go/commit/74d4d836b91318a8764b94bc2b4b66ff599eb5f2]
|
||||||
|
|
||||||
|
Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
|
||||||
|
---
|
||||||
|
src/encoding/pem/pem.go | 67 +++++++++++++++++++-----------------
|
||||||
|
src/encoding/pem/pem_test.go | 13 +++----
|
||||||
|
2 files changed, 43 insertions(+), 37 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
|
||||||
|
index 1bee1c1..01bed75 100644
|
||||||
|
--- a/src/encoding/pem/pem.go
|
||||||
|
+++ b/src/encoding/pem/pem.go
|
||||||
|
@@ -35,7 +35,7 @@ type Block struct {
|
||||||
|
// line bytes. The remainder of the byte array (also not including the new line
|
||||||
|
// bytes) is also returned and this will always be smaller than the original
|
||||||
|
// argument.
|
||||||
|
-func getLine(data []byte) (line, rest []byte) {
|
||||||
|
+func getLine(data []byte) (line, rest []byte, consumed int) {
|
||||||
|
i := bytes.IndexByte(data, '\n')
|
||||||
|
var j int
|
||||||
|
if i < 0 {
|
||||||
|
@@ -47,7 +47,7 @@ func getLine(data []byte) (line, rest []byte) {
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- return bytes.TrimRight(data[0:i], " \t"), data[j:]
|
||||||
|
+ return bytes.TrimRight(data[0:i], " \t"), data[j:], j
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeSpacesAndTabs returns a copy of its input with all spaces and tabs
|
||||||
|
@@ -88,19 +88,29 @@ func Decode(data []byte) (p *Block, rest []byte) {
|
||||||
|
// the byte array, we'll accept the start string without it.
|
||||||
|
rest = data
|
||||||
|
for {
|
||||||
|
- if bytes.HasPrefix(rest, pemStart[1:]) {
|
||||||
|
- rest = rest[len(pemStart)-1:]
|
||||||
|
- } else if i := bytes.Index(rest, pemStart); i >= 0 {
|
||||||
|
- rest = rest[i+len(pemStart) : len(rest)]
|
||||||
|
- } else {
|
||||||
|
+ // Find the first END line, and then find the last BEGIN line before
|
||||||
|
+ // the end line. This lets us skip any repeated BEGIN lines that don't
|
||||||
|
+ // have a matching END.
|
||||||
|
+ endIndex := bytes.Index(rest, pemEnd)
|
||||||
|
+ if endIndex < 0 {
|
||||||
|
return nil, data
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ endTrailerIndex := endIndex + len(pemEnd)
|
||||||
|
+ beginIndex := bytes.LastIndex(rest[:endIndex], pemStart[1:])
|
||||||
|
+ if beginIndex < 0 || beginIndex > 0 && rest[beginIndex-1] != '\n' {
|
||||||
|
+ return nil, data
|
||||||
|
+ }
|
||||||
|
+ rest = rest[beginIndex+len(pemStart)-1:]
|
||||||
|
+ endIndex -= beginIndex + len(pemStart) - 1
|
||||||
|
+ endTrailerIndex -= beginIndex + len(pemStart) - 1
|
||||||
|
var typeLine []byte
|
||||||
|
- typeLine, rest = getLine(rest)
|
||||||
|
+ var consumed int
|
||||||
|
+ typeLine, rest, consumed = getLine(rest)
|
||||||
|
if !bytes.HasSuffix(typeLine, pemEndOfLine) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
+ endIndex -= consumed
|
||||||
|
+ endTrailerIndex -= consumed
|
||||||
|
typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)]
|
||||||
|
|
||||||
|
p = &Block{
|
||||||
|
@@ -114,7 +124,7 @@ func Decode(data []byte) (p *Block, rest []byte) {
|
||||||
|
if len(rest) == 0 {
|
||||||
|
return nil, data
|
||||||
|
}
|
||||||
|
- line, next := getLine(rest)
|
||||||
|
+ line, next, consumed := getLine(rest)
|
||||||
|
|
||||||
|
i := bytes.IndexByte(line, ':')
|
||||||
|
if i == -1 {
|
||||||
|
@@ -127,21 +137,13 @@ func Decode(data []byte) (p *Block, rest []byte) {
|
||||||
|
val = bytes.TrimSpace(val)
|
||||||
|
p.Headers[string(key)] = string(val)
|
||||||
|
rest = next
|
||||||
|
+ endIndex -= consumed
|
||||||
|
+ endTrailerIndex -= consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
- var endIndex, endTrailerIndex int
|
||||||
|
-
|
||||||
|
- // If there were no headers, the END line might occur
|
||||||
|
- // immediately, without a leading newline.
|
||||||
|
- if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) {
|
||||||
|
- endIndex = 0
|
||||||
|
- endTrailerIndex = len(pemEnd) - 1
|
||||||
|
- } else {
|
||||||
|
- endIndex = bytes.Index(rest, pemEnd)
|
||||||
|
- endTrailerIndex = endIndex + len(pemEnd)
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if endIndex < 0 {
|
||||||
|
+ // If there were headers, there must be a newline between the headers
|
||||||
|
+ // and the END line, so endIndex should be >= 0.
|
||||||
|
+ if len(p.Headers) > 0 && endIndex < 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -161,21 +163,24 @@ func Decode(data []byte) (p *Block, rest []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// The line must end with only whitespace.
|
||||||
|
- if s, _ := getLine(restOfEndLine); len(s) != 0 {
|
||||||
|
+ if s, _, _ := getLine(restOfEndLine); len(s) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
- base64Data := removeSpacesAndTabs(rest[:endIndex])
|
||||||
|
- p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
|
||||||
|
- n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
|
||||||
|
- if err != nil {
|
||||||
|
- continue
|
||||||
|
+ p.Bytes = []byte{}
|
||||||
|
+ if endIndex > 0 {
|
||||||
|
+ base64Data := removeSpacesAndTabs(rest[:endIndex])
|
||||||
|
+ p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
|
||||||
|
+ n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
|
||||||
|
+ if err != nil {
|
||||||
|
+ continue
|
||||||
|
+ }
|
||||||
|
+ p.Bytes = p.Bytes[:n]
|
||||||
|
}
|
||||||
|
- p.Bytes = p.Bytes[:n]
|
||||||
|
|
||||||
|
// the -1 is because we might have only matched pemEnd without the
|
||||||
|
// leading newline if the PEM block was empty.
|
||||||
|
- _, rest = getLine(rest[endIndex+len(pemEnd)-1:])
|
||||||
|
+ _, rest, _ = getLine(rest[endIndex+len(pemEnd)-1:])
|
||||||
|
return p, rest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go
|
||||||
|
index c94b5ca..a326f9b 100644
|
||||||
|
--- a/src/encoding/pem/pem_test.go
|
||||||
|
+++ b/src/encoding/pem/pem_test.go
|
||||||
|
@@ -34,7 +34,7 @@ var getLineTests = []GetLineTest{
|
||||||
|
|
||||||
|
func TestGetLine(t *testing.T) {
|
||||||
|
for i, test := range getLineTests {
|
||||||
|
- x, y := getLine([]byte(test.in))
|
||||||
|
+ x, y, _ := getLine([]byte(test.in))
|
||||||
|
if string(x) != test.out1 || string(y) != test.out2 {
|
||||||
|
t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2)
|
||||||
|
}
|
||||||
|
@@ -46,6 +46,7 @@ func TestDecode(t *testing.T) {
|
||||||
|
if !reflect.DeepEqual(result, certificate) {
|
||||||
|
t.Errorf("#0 got:%#v want:%#v", result, certificate)
|
||||||
|
}
|
||||||
|
+
|
||||||
|
result, remainder = Decode(remainder)
|
||||||
|
if !reflect.DeepEqual(result, privateKey) {
|
||||||
|
t.Errorf("#1 got:%#v want:%#v", result, privateKey)
|
||||||
|
@@ -68,7 +69,7 @@ func TestDecode(t *testing.T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
result, remainder = Decode(remainder)
|
||||||
|
- if result == nil || result.Type != "HEADERS" || len(result.Headers) != 1 {
|
||||||
|
+ if result == nil || result.Type != "VALID HEADERS" || len(result.Headers) != 1 {
|
||||||
|
t.Errorf("#5 expected single header block but got :%v", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -381,15 +382,15 @@ ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
|
||||||
|
|
||||||
|
# This shouldn't be recognised because of the missing newline after the
|
||||||
|
headers.
|
||||||
|
------BEGIN HEADERS-----
|
||||||
|
+-----BEGIN INVALID HEADERS-----
|
||||||
|
Header: 1
|
||||||
|
------END HEADERS-----
|
||||||
|
+-----END INVALID HEADERS-----
|
||||||
|
|
||||||
|
# This should be valid, however.
|
||||||
|
------BEGIN HEADERS-----
|
||||||
|
+-----BEGIN VALID HEADERS-----
|
||||||
|
Header: 1
|
||||||
|
|
||||||
|
------END HEADERS-----`)
|
||||||
|
+-----END VALID HEADERS-----`)
|
||||||
|
|
||||||
|
var certificate = &Block{Type: "CERTIFICATE",
|
||||||
|
Headers: map[string]string{},
|
||||||
|
--
|
||||||
|
2.40.0
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user