summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVijay Anusuri <vanusuri@mvista.com>2023-12-27 07:14:26 +0530
committerSteve Sakoman <steve@sakoman.com>2024-01-05 03:25:38 -1000
commita2bf2f28c4f2ae2ab19a963d801029abb7de5dc9 (patch)
tree94aa1a6eabeafb80f75017a33ff5db19dddbad9c
parentc0e5370a91c87145d0a8eb753241b04ee3b1928e (diff)
downloadpoky-a2bf2f28c4f2ae2ab19a963d801029abb7de5dc9.tar.gz
go: Fix CVE-2023-39326
A malicious HTTP sender can use chunk extensions to cause a receiver reading from a request or response body to read many more bytes from the network than are in the body. A malicious HTTP client can further exploit this to cause a server to automatically read a large amount of data (up to about 1GiB) when a handler fails to read the entire body of a request. Chunk extensions are a little-used HTTP feature which permit including additional metadata in a request or response body sent using the chunked encoding. The net/http chunked encoding reader discards this metadata. A sender can exploit this by inserting a large metadata segment with each byte transferred. The chunk reader now produces an error if the ratio of real body to encoded bytes grows too small. References: https://nvd.nist.gov/vuln/detail/CVE-2023-39326 https://security-tracker.debian.org/tracker/CVE-2023-39326 (From OE-Core rev: 5b55648f3142762c9563289c1b19aa3b7de27164) Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-devtools/go/go-1.14.inc1
-rw-r--r--meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch181
2 files changed, 182 insertions, 0 deletions
diff --git a/meta/recipes-devtools/go/go-1.14.inc b/meta/recipes-devtools/go/go-1.14.inc
index 091b778de8..b827a3606d 100644
--- a/meta/recipes-devtools/go/go-1.14.inc
+++ b/meta/recipes-devtools/go/go-1.14.inc
@@ -82,6 +82,7 @@ SRC_URI += "\
82 file://CVE-2023-24536_3.patch \ 82 file://CVE-2023-24536_3.patch \
83 file://CVE-2023-39318.patch \ 83 file://CVE-2023-39318.patch \
84 file://CVE-2023-39319.patch \ 84 file://CVE-2023-39319.patch \
85 file://CVE-2023-39326.patch \
85" 86"
86 87
87SRC_URI_append_libc-musl = " file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch" 88SRC_URI_append_libc-musl = " file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch"
diff --git a/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch b/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch
new file mode 100644
index 0000000000..998af361e8
--- /dev/null
+++ b/meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch
@@ -0,0 +1,181 @@
1From 6446af942e2e2b161c4ec1b60d9703a2b55dc4dd Mon Sep 17 00:00:00 2001
2From: Damien Neil <dneil@google.com>
3Date: Tue, 7 Nov 2023 10:47:56 -0800
4Subject: [PATCH] [release-branch.go1.20] net/http: limit chunked data overhead
5
6The chunked transfer encoding adds some overhead to
7the content transferred. When writing one byte per
8chunk, for example, there are five bytes of overhead
9per byte of data transferred: "1\r\nX\r\n" to send "X".
10
11Chunks may include "chunk extensions",
12which we skip over and do not use.
13For example: "1;chunk extension here\r\nX\r\n".
14
15A malicious sender can use chunk extensions to add
16about 4k of overhead per byte of data.
17(The maximum chunk header line size we will accept.)
18
19Track the amount of overhead read in chunked data,
20and produce an error if it seems excessive.
21
22Updates #64433
23Fixes #64434
24Fixes CVE-2023-39326
25
26Change-Id: I40f8d70eb6f9575fb43f506eb19132ccedafcf39
27Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2076135
28Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
29Reviewed-by: Roland Shoemaker <bracewell@google.com>
30(cherry picked from commit 3473ae72ee66c60744665a24b2fde143e8964d4f)
31Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2095407
32Run-TryBot: Roland Shoemaker <bracewell@google.com>
33TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com>
34Reviewed-by: Damien Neil <dneil@google.com>
35Reviewed-on: https://go-review.googlesource.com/c/go/+/547355
36Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
37LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
38
39Upstream-Status: Backport [https://github.com/golang/go/commit/6446af942e2e2b161c4ec1b60d9703a2b55dc4dd]
40CVE: CVE-2023-39326
41Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
42---
43 src/net/http/internal/chunked.go | 36 +++++++++++++---
44 src/net/http/internal/chunked_test.go | 59 +++++++++++++++++++++++++++
45 2 files changed, 89 insertions(+), 6 deletions(-)
46
47diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
48index f06e572..ddbaacb 100644
49--- a/src/net/http/internal/chunked.go
50+++ b/src/net/http/internal/chunked.go
51@@ -39,7 +39,8 @@ type chunkedReader struct {
52 n uint64 // unread bytes in chunk
53 err error
54 buf [2]byte
55- checkEnd bool // whether need to check for \r\n chunk footer
56+ checkEnd bool // whether need to check for \r\n chunk footer
57+ excess int64 // "excessive" chunk overhead, for malicious sender detection
58 }
59
60 func (cr *chunkedReader) beginChunk() {
61@@ -49,10 +50,38 @@ func (cr *chunkedReader) beginChunk() {
62 if cr.err != nil {
63 return
64 }
65+ cr.excess += int64(len(line)) + 2 // header, plus \r\n after the chunk data
66+ line = trimTrailingWhitespace(line)
67+ line, cr.err = removeChunkExtension(line)
68+ if cr.err != nil {
69+ return
70+ }
71 cr.n, cr.err = parseHexUint(line)
72 if cr.err != nil {
73 return
74 }
75+ // A sender who sends one byte per chunk will send 5 bytes of overhead
76+ // for every byte of data. ("1\r\nX\r\n" to send "X".)
77+ // We want to allow this, since streaming a byte at a time can be legitimate.
78+ //
79+ // A sender can use chunk extensions to add arbitrary amounts of additional
80+ // data per byte read. ("1;very long extension\r\nX\r\n" to send "X".)
81+ // We don't want to disallow extensions (although we discard them),
82+ // but we also don't want to allow a sender to reduce the signal/noise ratio
83+ // arbitrarily.
84+ //
85+ // We track the amount of excess overhead read,
86+ // and produce an error if it grows too large.
87+ //
88+ // Currently, we say that we're willing to accept 16 bytes of overhead per chunk,
89+ // plus twice the amount of real data in the chunk.
90+ cr.excess -= 16 + (2 * int64(cr.n))
91+ if cr.excess < 0 {
92+ cr.excess = 0
93+ }
94+ if cr.excess > 16*1024 {
95+ cr.err = errors.New("chunked encoding contains too much non-data")
96+ }
97 if cr.n == 0 {
98 cr.err = io.EOF
99 }
100@@ -133,11 +162,6 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) {
101 if len(p) >= maxLineLength {
102 return nil, ErrLineTooLong
103 }
104- p = trimTrailingWhitespace(p)
105- p, err = removeChunkExtension(p)
106- if err != nil {
107- return nil, err
108- }
109 return p, nil
110 }
111
112diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go
113index d067165..b20747d 100644
114--- a/src/net/http/internal/chunked_test.go
115+++ b/src/net/http/internal/chunked_test.go
116@@ -212,3 +212,62 @@ func TestChunkReadPartial(t *testing.T) {
117 }
118
119 }
120+
121+func TestChunkReaderTooMuchOverhead(t *testing.T) {
122+ // If the sender is sending 100x as many chunk header bytes as chunk data,
123+ // we should reject the stream at some point.
124+ chunk := []byte("1;")
125+ for i := 0; i < 100; i++ {
126+ chunk = append(chunk, 'a') // chunk extension
127+ }
128+ chunk = append(chunk, "\r\nX\r\n"...)
129+ const bodylen = 1 << 20
130+ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) {
131+ if i < bodylen {
132+ return chunk, nil
133+ }
134+ return []byte("0\r\n"), nil
135+ }})
136+ _, err := io.ReadAll(r)
137+ if err == nil {
138+ t.Fatalf("successfully read body with excessive overhead; want error")
139+ }
140+}
141+
142+func TestChunkReaderByteAtATime(t *testing.T) {
143+ // Sending one byte per chunk should not trip the excess-overhead detection.
144+ const bodylen = 1 << 20
145+ r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) {
146+ if i < bodylen {
147+ return []byte("1\r\nX\r\n"), nil
148+ }
149+ return []byte("0\r\n"), nil
150+ }})
151+ got, err := io.ReadAll(r)
152+ if err != nil {
153+ t.Errorf("unexpected error: %v", err)
154+ }
155+ if len(got) != bodylen {
156+ t.Errorf("read %v bytes, want %v", len(got), bodylen)
157+ }
158+}
159+
160+type funcReader struct {
161+ f func(iteration int) ([]byte, error)
162+ i int
163+ b []byte
164+ err error
165+}
166+
167+func (r *funcReader) Read(p []byte) (n int, err error) {
168+ if len(r.b) == 0 && r.err == nil {
169+ r.b, r.err = r.f(r.i)
170+ r.i++
171+ }
172+ n = copy(p, r.b)
173+ r.b = r.b[n:]
174+ if len(r.b) > 0 {
175+ return n, nil
176+ }
177+ return n, r.err
178+}
179--
1802.25.1
181