diff options
| -rw-r--r-- | meta/recipes-devtools/go/go-1.14.inc | 1 | ||||
| -rw-r--r-- | meta/recipes-devtools/go/go-1.14/CVE-2023-39326.patch | 181 |
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 | ||
| 87 | SRC_URI_append_libc-musl = " file://0009-ld-replace-glibc-dynamic-linker-with-musl.patch" | 88 | SRC_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 @@ | |||
| 1 | From 6446af942e2e2b161c4ec1b60d9703a2b55dc4dd Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Damien Neil <dneil@google.com> | ||
| 3 | Date: Tue, 7 Nov 2023 10:47:56 -0800 | ||
| 4 | Subject: [PATCH] [release-branch.go1.20] net/http: limit chunked data overhead | ||
| 5 | |||
| 6 | The chunked transfer encoding adds some overhead to | ||
| 7 | the content transferred. When writing one byte per | ||
| 8 | chunk, for example, there are five bytes of overhead | ||
| 9 | per byte of data transferred: "1\r\nX\r\n" to send "X". | ||
| 10 | |||
| 11 | Chunks may include "chunk extensions", | ||
| 12 | which we skip over and do not use. | ||
| 13 | For example: "1;chunk extension here\r\nX\r\n". | ||
| 14 | |||
| 15 | A malicious sender can use chunk extensions to add | ||
| 16 | about 4k of overhead per byte of data. | ||
| 17 | (The maximum chunk header line size we will accept.) | ||
| 18 | |||
| 19 | Track the amount of overhead read in chunked data, | ||
| 20 | and produce an error if it seems excessive. | ||
| 21 | |||
| 22 | Updates #64433 | ||
| 23 | Fixes #64434 | ||
| 24 | Fixes CVE-2023-39326 | ||
| 25 | |||
| 26 | Change-Id: I40f8d70eb6f9575fb43f506eb19132ccedafcf39 | ||
| 27 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2076135 | ||
| 28 | Reviewed-by: Tatiana Bradley <tatianabradley@google.com> | ||
| 29 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
| 30 | (cherry picked from commit 3473ae72ee66c60744665a24b2fde143e8964d4f) | ||
| 31 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2095407 | ||
| 32 | Run-TryBot: Roland Shoemaker <bracewell@google.com> | ||
| 33 | TryBot-Result: Security TryBots <security-trybots@go-security-trybots.iam.gserviceaccount.com> | ||
| 34 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 35 | Reviewed-on: https://go-review.googlesource.com/c/go/+/547355 | ||
| 36 | Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> | ||
| 37 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 38 | |||
| 39 | Upstream-Status: Backport [https://github.com/golang/go/commit/6446af942e2e2b161c4ec1b60d9703a2b55dc4dd] | ||
| 40 | CVE: CVE-2023-39326 | ||
| 41 | Signed-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 | |||
| 47 | diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go | ||
| 48 | index 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 | |||
| 112 | diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go | ||
| 113 | index 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 | -- | ||
| 180 | 2.25.1 | ||
| 181 | |||
