diff options
| author | Archana Polampalli <archana.polampalli@windriver.com> | 2025-11-28 21:37:58 +0530 |
|---|---|---|
| committer | Steve Sakoman <steve@sakoman.com> | 2025-12-05 06:56:34 -0800 |
| commit | 46c836aefa1968e2ea8bdbdcc1bff6d329ddcc24 (patch) | |
| tree | 615760bc2a74ce0accc51eebb57e1f4b426186d1 | |
| parent | 5f8155aefa0930c0495f24cfc2dbecc8b6ff4e0d (diff) | |
| download | poky-46c836aefa1968e2ea8bdbdcc1bff6d329ddcc24.tar.gz | |
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>
| -rw-r--r-- | meta/recipes-devtools/go/go-1.17.13.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch | 221 |
2 files changed, 222 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc index 61fee12cf9..b621fb189c 100644 --- a/meta/recipes-devtools/go/go-1.17.13.inc +++ b/meta/recipes-devtools/go/go-1.17.13.inc | |||
| @@ -71,6 +71,7 @@ SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ | |||
| 71 | file://CVE-2024-24783.patch \ | 71 | file://CVE-2024-24783.patch \ |
| 72 | file://CVE-2025-58187.patch \ | 72 | file://CVE-2025-58187.patch \ |
| 73 | file://CVE-2025-58189.patch \ | 73 | file://CVE-2025-58189.patch \ |
| 74 | file://CVE-2025-61723.patch \ | ||
| 74 | " | 75 | " |
| 75 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" | 76 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" |
| 76 | 77 | ||
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch new file mode 100644 index 0000000000..8c838a6d8a --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-61723.patch | |||
| @@ -0,0 +1,221 @@ | |||
| 1 | From 74d4d836b91318a8764b94bc2b4b66ff599eb5f2 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Roland Shoemaker <bracewell@google.com> | ||
| 3 | Date: Tue, 30 Sep 2025 11:16:56 -0700 | ||
| 4 | Subject: [PATCH] encoding/pem: make Decode complexity linear Because Decode | ||
| 5 | scanned the input first for the first BEGIN line, and then the first END | ||
| 6 | line, the complexity of Decode is quadratic. If the input contained a large | ||
| 7 | number of BEGINs and then a single END right at the end of the input, we | ||
| 8 | would find the first BEGIN, and then scan the entire input for the END, and | ||
| 9 | fail to parse the block, so move onto the next BEGIN, scan the entire input | ||
| 10 | for the END, etc. | ||
| 11 | |||
| 12 | Instead, look for the first END in the input, and then the first BEGIN | ||
| 13 | that precedes the found END. We then process the bytes between the BEGIN | ||
| 14 | and END, and move onto the bytes after the END for further processing. | ||
| 15 | This gives us linear complexity. | ||
| 16 | |||
| 17 | Fixes CVE-2025-61723 | ||
| 18 | For #75676 | ||
| 19 | Fixes #75708 | ||
| 20 | |||
| 21 | Change-Id: I813c4f63e78bca4054226c53e13865c781564ccf | ||
| 22 | Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2921 | ||
| 23 | Reviewed-by: Nicholas Husin <husin@google.com> | ||
| 24 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 25 | Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2986 | ||
| 26 | Reviewed-on: https://go-review.googlesource.com/c/go/+/709842 | ||
| 27 | TryBot-Bypass: Michael Pratt <mpratt@google.com> | ||
| 28 | Auto-Submit: Michael Pratt <mpratt@google.com> | ||
| 29 | Reviewed-by: Carlos Amedee <carlos@golang.org> | ||
| 30 | |||
| 31 | CVE: CVE-2025-61723 | ||
| 32 | |||
| 33 | Upstream-Status: Backport [https://github.com/golang/go/commit/74d4d836b91318a8764b94bc2b4b66ff599eb5f2] | ||
| 34 | |||
| 35 | Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com> | ||
| 36 | --- | ||
| 37 | src/encoding/pem/pem.go | 67 +++++++++++++++++++----------------- | ||
| 38 | src/encoding/pem/pem_test.go | 13 +++---- | ||
| 39 | 2 files changed, 43 insertions(+), 37 deletions(-) | ||
| 40 | |||
| 41 | diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go | ||
| 42 | index 1bee1c1..01bed75 100644 | ||
| 43 | --- a/src/encoding/pem/pem.go | ||
| 44 | +++ b/src/encoding/pem/pem.go | ||
| 45 | @@ -35,7 +35,7 @@ type Block struct { | ||
| 46 | // line bytes. The remainder of the byte array (also not including the new line | ||
| 47 | // bytes) is also returned and this will always be smaller than the original | ||
| 48 | // argument. | ||
| 49 | -func getLine(data []byte) (line, rest []byte) { | ||
| 50 | +func getLine(data []byte) (line, rest []byte, consumed int) { | ||
| 51 | i := bytes.IndexByte(data, '\n') | ||
| 52 | var j int | ||
| 53 | if i < 0 { | ||
| 54 | @@ -47,7 +47,7 @@ func getLine(data []byte) (line, rest []byte) { | ||
| 55 | i-- | ||
| 56 | } | ||
| 57 | } | ||
| 58 | - return bytes.TrimRight(data[0:i], " \t"), data[j:] | ||
| 59 | + return bytes.TrimRight(data[0:i], " \t"), data[j:], j | ||
| 60 | } | ||
| 61 | |||
| 62 | // removeSpacesAndTabs returns a copy of its input with all spaces and tabs | ||
| 63 | @@ -88,19 +88,29 @@ func Decode(data []byte) (p *Block, rest []byte) { | ||
| 64 | // the byte array, we'll accept the start string without it. | ||
| 65 | rest = data | ||
| 66 | for { | ||
| 67 | - if bytes.HasPrefix(rest, pemStart[1:]) { | ||
| 68 | - rest = rest[len(pemStart)-1:] | ||
| 69 | - } else if i := bytes.Index(rest, pemStart); i >= 0 { | ||
| 70 | - rest = rest[i+len(pemStart) : len(rest)] | ||
| 71 | - } else { | ||
| 72 | + // Find the first END line, and then find the last BEGIN line before | ||
| 73 | + // the end line. This lets us skip any repeated BEGIN lines that don't | ||
| 74 | + // have a matching END. | ||
| 75 | + endIndex := bytes.Index(rest, pemEnd) | ||
| 76 | + if endIndex < 0 { | ||
| 77 | return nil, data | ||
| 78 | } | ||
| 79 | - | ||
| 80 | + endTrailerIndex := endIndex + len(pemEnd) | ||
| 81 | + beginIndex := bytes.LastIndex(rest[:endIndex], pemStart[1:]) | ||
| 82 | + if beginIndex < 0 || beginIndex > 0 && rest[beginIndex-1] != '\n' { | ||
| 83 | + return nil, data | ||
| 84 | + } | ||
| 85 | + rest = rest[beginIndex+len(pemStart)-1:] | ||
| 86 | + endIndex -= beginIndex + len(pemStart) - 1 | ||
| 87 | + endTrailerIndex -= beginIndex + len(pemStart) - 1 | ||
| 88 | var typeLine []byte | ||
| 89 | - typeLine, rest = getLine(rest) | ||
| 90 | + var consumed int | ||
| 91 | + typeLine, rest, consumed = getLine(rest) | ||
| 92 | if !bytes.HasSuffix(typeLine, pemEndOfLine) { | ||
| 93 | continue | ||
| 94 | } | ||
| 95 | + endIndex -= consumed | ||
| 96 | + endTrailerIndex -= consumed | ||
| 97 | typeLine = typeLine[0 : len(typeLine)-len(pemEndOfLine)] | ||
| 98 | |||
| 99 | p = &Block{ | ||
| 100 | @@ -114,7 +124,7 @@ func Decode(data []byte) (p *Block, rest []byte) { | ||
| 101 | if len(rest) == 0 { | ||
| 102 | return nil, data | ||
| 103 | } | ||
| 104 | - line, next := getLine(rest) | ||
| 105 | + line, next, consumed := getLine(rest) | ||
| 106 | |||
| 107 | i := bytes.IndexByte(line, ':') | ||
| 108 | if i == -1 { | ||
| 109 | @@ -127,21 +137,13 @@ func Decode(data []byte) (p *Block, rest []byte) { | ||
| 110 | val = bytes.TrimSpace(val) | ||
| 111 | p.Headers[string(key)] = string(val) | ||
| 112 | rest = next | ||
| 113 | + endIndex -= consumed | ||
| 114 | + endTrailerIndex -= consumed | ||
| 115 | } | ||
| 116 | |||
| 117 | - var endIndex, endTrailerIndex int | ||
| 118 | - | ||
| 119 | - // If there were no headers, the END line might occur | ||
| 120 | - // immediately, without a leading newline. | ||
| 121 | - if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { | ||
| 122 | - endIndex = 0 | ||
| 123 | - endTrailerIndex = len(pemEnd) - 1 | ||
| 124 | - } else { | ||
| 125 | - endIndex = bytes.Index(rest, pemEnd) | ||
| 126 | - endTrailerIndex = endIndex + len(pemEnd) | ||
| 127 | - } | ||
| 128 | - | ||
| 129 | - if endIndex < 0 { | ||
| 130 | + // If there were headers, there must be a newline between the headers | ||
| 131 | + // and the END line, so endIndex should be >= 0. | ||
| 132 | + if len(p.Headers) > 0 && endIndex < 0 { | ||
| 133 | continue | ||
| 134 | } | ||
| 135 | |||
| 136 | @@ -161,21 +163,24 @@ func Decode(data []byte) (p *Block, rest []byte) { | ||
| 137 | } | ||
| 138 | |||
| 139 | // The line must end with only whitespace. | ||
| 140 | - if s, _ := getLine(restOfEndLine); len(s) != 0 { | ||
| 141 | + if s, _, _ := getLine(restOfEndLine); len(s) != 0 { | ||
| 142 | continue | ||
| 143 | } | ||
| 144 | |||
| 145 | - base64Data := removeSpacesAndTabs(rest[:endIndex]) | ||
| 146 | - p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) | ||
| 147 | - n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) | ||
| 148 | - if err != nil { | ||
| 149 | - continue | ||
| 150 | + p.Bytes = []byte{} | ||
| 151 | + if endIndex > 0 { | ||
| 152 | + base64Data := removeSpacesAndTabs(rest[:endIndex]) | ||
| 153 | + p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) | ||
| 154 | + n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) | ||
| 155 | + if err != nil { | ||
| 156 | + continue | ||
| 157 | + } | ||
| 158 | + p.Bytes = p.Bytes[:n] | ||
| 159 | } | ||
| 160 | - p.Bytes = p.Bytes[:n] | ||
| 161 | |||
| 162 | // the -1 is because we might have only matched pemEnd without the | ||
| 163 | // leading newline if the PEM block was empty. | ||
| 164 | - _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) | ||
| 165 | + _, rest, _ = getLine(rest[endIndex+len(pemEnd)-1:]) | ||
| 166 | return p, rest | ||
| 167 | } | ||
| 168 | } | ||
| 169 | diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go | ||
| 170 | index c94b5ca..a326f9b 100644 | ||
| 171 | --- a/src/encoding/pem/pem_test.go | ||
| 172 | +++ b/src/encoding/pem/pem_test.go | ||
| 173 | @@ -34,7 +34,7 @@ var getLineTests = []GetLineTest{ | ||
| 174 | |||
| 175 | func TestGetLine(t *testing.T) { | ||
| 176 | for i, test := range getLineTests { | ||
| 177 | - x, y := getLine([]byte(test.in)) | ||
| 178 | + x, y, _ := getLine([]byte(test.in)) | ||
| 179 | if string(x) != test.out1 || string(y) != test.out2 { | ||
| 180 | t.Errorf("#%d got:%+v,%+v want:%s,%s", i, x, y, test.out1, test.out2) | ||
| 181 | } | ||
| 182 | @@ -46,6 +46,7 @@ func TestDecode(t *testing.T) { | ||
| 183 | if !reflect.DeepEqual(result, certificate) { | ||
| 184 | t.Errorf("#0 got:%#v want:%#v", result, certificate) | ||
| 185 | } | ||
| 186 | + | ||
| 187 | result, remainder = Decode(remainder) | ||
| 188 | if !reflect.DeepEqual(result, privateKey) { | ||
| 189 | t.Errorf("#1 got:%#v want:%#v", result, privateKey) | ||
| 190 | @@ -68,7 +69,7 @@ func TestDecode(t *testing.T) { | ||
| 191 | } | ||
| 192 | |||
| 193 | result, remainder = Decode(remainder) | ||
| 194 | - if result == nil || result.Type != "HEADERS" || len(result.Headers) != 1 { | ||
| 195 | + if result == nil || result.Type != "VALID HEADERS" || len(result.Headers) != 1 { | ||
| 196 | t.Errorf("#5 expected single header block but got :%v", result) | ||
| 197 | } | ||
| 198 | |||
| 199 | @@ -381,15 +382,15 @@ ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg== | ||
| 200 | |||
| 201 | # This shouldn't be recognised because of the missing newline after the | ||
| 202 | headers. | ||
| 203 | ------BEGIN HEADERS----- | ||
| 204 | +-----BEGIN INVALID HEADERS----- | ||
| 205 | Header: 1 | ||
| 206 | ------END HEADERS----- | ||
| 207 | +-----END INVALID HEADERS----- | ||
| 208 | |||
| 209 | # This should be valid, however. | ||
| 210 | ------BEGIN HEADERS----- | ||
| 211 | +-----BEGIN VALID HEADERS----- | ||
| 212 | Header: 1 | ||
| 213 | |||
| 214 | ------END HEADERS-----`) | ||
| 215 | +-----END VALID HEADERS-----`) | ||
| 216 | |||
| 217 | var certificate = &Block{Type: "CERTIFICATE", | ||
| 218 | Headers: map[string]string{}, | ||
| 219 | -- | ||
| 220 | 2.40.0 | ||
| 221 | |||
