backport: fix CVE-2024-24783,CVE-2024-24785,CVE-2023-45290,CVE-2023-45289

This commit is contained in:
hanchao 2024-03-15 13:05:09 +08:00
parent a0067aaa00
commit 5f0e9e311b
5 changed files with 658 additions and 1 deletions

View File

@ -0,0 +1,78 @@
From 5dfc2e6c42724349a9e9ecbcc69be920c18d90e9 Mon Sep 17 00:00:00 2001
From: Roland Shoemaker <bracewell@google.com>
Date: Thu, 18 Jan 2024 12:51:13 -0800
Subject: [PATCH 1/4] [release-branch.go1.21] crypto/x509: make sure pub key is
non-nil before interface conversion
alreadyInChain assumes all keys fit a interface which contains the
Equal method (which they do), but this ignores that certificates may
have a nil key when PublicKeyAlgorithm is UnknownPublicKeyAlgorithm. In
this case alreadyInChain panics.
Check that the key is non-nil as part of considerCandidate (we are never
going to build a chain containing UnknownPublicKeyAlgorithm anyway).
For #65390
Fixes #65392
Fixes CVE-2024-24783
Change-Id: Ibdccc0a487e3368b6812be35daad2512220243f3
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2137282
Reviewed-by: Damien Neil <dneil@google.com>
Run-TryBot: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173774
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Carlos Amedee <amedee@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/569238
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
---
src/crypto/x509/verify.go | 2 +-
src/crypto/x509/verify_test.go | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 345d434453c..56a1a1725cc 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -899,7 +899,7 @@ func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, o
)
considerCandidate := func(certType int, candidate *Certificate) {
- if alreadyInChain(candidate, currentChain) {
+ if candidate.PublicKey == nil || alreadyInChain(candidate, currentChain) {
return
}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 3551b470ced..d8678d03f93 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -2693,3 +2693,22 @@ func TestVerifyEKURootAsLeaf(t *testing.T) {
}
}
+
+func TestVerifyNilPubKey(t *testing.T) {
+ c := &Certificate{
+ RawIssuer: []byte{1, 2, 3},
+ AuthorityKeyId: []byte{1, 2, 3},
+ }
+ opts := &VerifyOptions{}
+ opts.Roots = NewCertPool()
+ r := &Certificate{
+ RawSubject: []byte{1, 2, 3},
+ SubjectKeyId: []byte{1, 2, 3},
+ }
+ opts.Roots.AddCert(r)
+
+ _, err := c.buildChains([]*Certificate{r}, nil, opts)
+ if _, ok := err.(UnknownAuthorityError); !ok {
+ t.Fatalf("buildChains returned unexpected error, got: %v, want %v", err, UnknownAuthorityError{})
+ }
+}
--
2.33.0

View File

@ -0,0 +1,193 @@
From 0787ee55dd0d42dd8bef97d4e7ed7584f44c16e9 Mon Sep 17 00:00:00 2001
From: Roland Shoemaker <roland@golang.org>
Date: Wed, 14 Feb 2024 17:18:36 -0800
Subject: [PATCH 2/4] [release-branch.go1.21] html/template: escape additional
tokens in MarshalJSON errors
Escape "</script" and "<!--" in errors returned from MarshalJSON errors
when attempting to marshal types in script blocks. This prevents any
user controlled content from prematurely terminating the script block.
Updates #65697
Fixes #65968
Change-Id: Icf0e26c54ea7d9c1deed0bff11b6506c99ddef1b
Reviewed-on: https://go-review.googlesource.com/c/go/+/564196
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
(cherry picked from commit ccbc725f2d678255df1bd326fa511a492aa3a0aa)
Reviewed-on: https://go-review.googlesource.com/c/go/+/567515
Reviewed-by: Carlos Amedee <carlos@golang.org>
---
src/html/template/js.go | 22 ++++++++-
src/html/template/js_test.go | 96 ++++++++++++++++++++----------------
2 files changed, 74 insertions(+), 44 deletions(-)
diff --git a/src/html/template/js.go b/src/html/template/js.go
index 4e05c145572..f4d1303bebe 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -171,13 +171,31 @@ func jsValEscaper(args ...any) string {
// cyclic data. This may be an unacceptable DoS risk.
b, err := json.Marshal(a)
if err != nil {
- // Put a space before comment so that if it is flush against
+ // While the standard JSON marshaller does not include user controlled
+ // information in the error message, if a type has a MarshalJSON method,
+ // the content of the error message is not guaranteed. Since we insert
+ // the error into the template, as part of a comment, we attempt to
+ // prevent the error from either terminating the comment, or the script
+ // block itself.
+ //
+ // In particular we:
+ // * replace "*/" comment end tokens with "* /", which does not
+ // terminate the comment
+ // * replace "</script" with "\x3C/script", and "<!--" with
+ // "\x3C!--", which prevents confusing script block termination
+ // semantics
+ //
+ // We also put a space before the comment so that if it is flush against
// a division operator it is not turned into a line comment:
// x/{{y}}
// turning into
// x//* error marshaling y:
// second line of error message */null
- return fmt.Sprintf(" /* %s */null ", strings.ReplaceAll(err.Error(), "*/", "* /"))
+ errStr := err.Error()
+ errStr = strings.ReplaceAll(errStr, "*/", "* /")
+ errStr = strings.ReplaceAll(errStr, "</script", `\x3C/script`)
+ errStr = strings.ReplaceAll(errStr, "<!--", `\x3C!--`)
+ return fmt.Sprintf(" /* %s */null ", errStr)
}
// TODO: maybe post-process output to prevent it from containing
diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
index 259dcfbdc5b..17cedcec05f 100644
--- a/src/html/template/js_test.go
+++ b/src/html/template/js_test.go
@@ -5,6 +5,7 @@
package template
import (
+ "errors"
"math"
"strings"
"testing"
@@ -103,61 +104,72 @@ func TestNextJsCtx(t *testing.T) {
}
}
+type jsonErrType struct{}
+
+func (e *jsonErrType) MarshalJSON() ([]byte, error) {
+ return nil, errors.New("beep */ boop </script blip <!--")
+}
+
func TestJSValEscaper(t *testing.T) {
tests := []struct {
- x any
- js string
+ x any
+ js string
+ skipNest bool
}{
- {int(42), " 42 "},
- {uint(42), " 42 "},
- {int16(42), " 42 "},
- {uint16(42), " 42 "},
- {int32(-42), " -42 "},
- {uint32(42), " 42 "},
- {int16(-42), " -42 "},
- {uint16(42), " 42 "},
- {int64(-42), " -42 "},
- {uint64(42), " 42 "},
- {uint64(1) << 53, " 9007199254740992 "},
+ {int(42), " 42 ", false},
+ {uint(42), " 42 ", false},
+ {int16(42), " 42 ", false},
+ {uint16(42), " 42 ", false},
+ {int32(-42), " -42 ", false},
+ {uint32(42), " 42 ", false},
+ {int16(-42), " -42 ", false},
+ {uint16(42), " 42 ", false},
+ {int64(-42), " -42 ", false},
+ {uint64(42), " 42 ", false},
+ {uint64(1) << 53, " 9007199254740992 ", false},
// ulp(1 << 53) > 1 so this loses precision in JS
// but it is still a representable integer literal.
- {uint64(1)<<53 + 1, " 9007199254740993 "},
- {float32(1.0), " 1 "},
- {float32(-1.0), " -1 "},
- {float32(0.5), " 0.5 "},
- {float32(-0.5), " -0.5 "},
- {float32(1.0) / float32(256), " 0.00390625 "},
- {float32(0), " 0 "},
- {math.Copysign(0, -1), " -0 "},
- {float64(1.0), " 1 "},
- {float64(-1.0), " -1 "},
- {float64(0.5), " 0.5 "},
- {float64(-0.5), " -0.5 "},
- {float64(0), " 0 "},
- {math.Copysign(0, -1), " -0 "},
- {"", `""`},
- {"foo", `"foo"`},
+ {uint64(1)<<53 + 1, " 9007199254740993 ", false},
+ {float32(1.0), " 1 ", false},
+ {float32(-1.0), " -1 ", false},
+ {float32(0.5), " 0.5 ", false},
+ {float32(-0.5), " -0.5 ", false},
+ {float32(1.0) / float32(256), " 0.00390625 ", false},
+ {float32(0), " 0 ", false},
+ {math.Copysign(0, -1), " -0 ", false},
+ {float64(1.0), " 1 ", false},
+ {float64(-1.0), " -1 ", false},
+ {float64(0.5), " 0.5 ", false},
+ {float64(-0.5), " -0.5 ", false},
+ {float64(0), " 0 ", false},
+ {math.Copysign(0, -1), " -0 ", false},
+ {"", `""`, false},
+ {"foo", `"foo"`, false},
// Newlines.
- {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`},
+ {"\r\n\u2028\u2029", `"\r\n\u2028\u2029"`, false},
// "\v" == "v" on IE 6 so use "\u000b" instead.
- {"\t\x0b", `"\t\u000b"`},
- {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`},
- {[]any{}, "[]"},
- {[]any{42, "foo", nil}, `[42,"foo",null]`},
- {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`},
- {"<!--", `"\u003c!--"`},
- {"-->", `"--\u003e"`},
- {"<![CDATA[", `"\u003c![CDATA["`},
- {"]]>", `"]]\u003e"`},
- {"</script", `"\u003c/script"`},
- {"\U0001D11E", "\"\U0001D11E\""}, // or "\uD834\uDD1E"
- {nil, " null "},
+ {"\t\x0b", `"\t\u000b"`, false},
+ {struct{ X, Y int }{1, 2}, `{"X":1,"Y":2}`, false},
+ {[]any{}, "[]", false},
+ {[]any{42, "foo", nil}, `[42,"foo",null]`, false},
+ {[]string{"<!--", "</script>", "-->"}, `["\u003c!--","\u003c/script\u003e","--\u003e"]`, false},
+ {"<!--", `"\u003c!--"`, false},
+ {"-->", `"--\u003e"`, false},
+ {"<![CDATA[", `"\u003c![CDATA["`, false},
+ {"]]>", `"]]\u003e"`, false},
+ {"</script", `"\u003c/script"`, false},
+ {"\U0001D11E", "\"\U0001D11E\"", false}, // or "\uD834\uDD1E"
+ {nil, " null ", false},
+ {&jsonErrType{}, " /* json: error calling MarshalJSON for type *template.jsonErrType: beep * / boop \\x3C/script blip \\x3C!-- */null ", true},
}
for _, test := range tests {
if js := jsValEscaper(test.x); js != test.js {
t.Errorf("%+v: want\n\t%q\ngot\n\t%q", test.x, test.js, js)
}
+ if test.skipNest {
+ continue
+ }
// Make sure that escaping corner cases are not broken
// by nesting.
a := []any{test.x}
--
2.33.0

View File

@ -0,0 +1,266 @@
From 1e8ba3a45a208d2d9838904e4ea8730d31f24d5b Mon Sep 17 00:00:00 2001
From: Damien Neil <dneil@google.com>
Date: Tue, 16 Jan 2024 15:37:52 -0800
Subject: [PATCH 3/4] [release-branch.go1.21] net/textproto, mime/multipart:
avoid unbounded read in MIME header
mime/multipart.Reader.ReadForm allows specifying the maximum amount
of memory that will be consumed by the form. While this limit is
correctly applied to the parsed form data structure, it was not
being applied to individual header lines in a form.
For example, when presented with a form containing a header line
that never ends, ReadForm will continue to read the line until it
runs out of memory.
Limit the amount of data consumed when reading a header.
Fixes CVE-2023-45290
Fixes #65389
For #65383
Change-Id: I7f9264d25752009e95f6b2c80e3d76aaf321d658
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2134435
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173776
Reviewed-by: Carlos Amedee <amedee@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/569240
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
---
src/mime/multipart/formdata_test.go | 42 +++++++++++++++++++++++++
src/net/textproto/reader.go | 48 ++++++++++++++++++++---------
src/net/textproto/reader_test.go | 12 ++++++++
3 files changed, 87 insertions(+), 15 deletions(-)
diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
index d422729c96a..bfa9f683825 100644
--- a/src/mime/multipart/formdata_test.go
+++ b/src/mime/multipart/formdata_test.go
@@ -452,6 +452,48 @@ func TestReadFormLimits(t *testing.T) {
}
}
+func TestReadFormEndlessHeaderLine(t *testing.T) {
+ for _, test := range []struct {
+ name string
+ prefix string
+ }{{
+ name: "name",
+ prefix: "X-",
+ }, {
+ name: "value",
+ prefix: "X-Header: ",
+ }, {
+ name: "continuation",
+ prefix: "X-Header: foo\r\n ",
+ }} {
+ t.Run(test.name, func(t *testing.T) {
+ const eol = "\r\n"
+ s := `--boundary` + eol
+ s += `Content-Disposition: form-data; name="a"` + eol
+ s += `Content-Type: text/plain` + eol
+ s += test.prefix
+ fr := io.MultiReader(
+ strings.NewReader(s),
+ neverendingReader('X'),
+ )
+ r := NewReader(fr, "boundary")
+ _, err := r.ReadForm(1 << 20)
+ if err != ErrMessageTooLarge {
+ t.Fatalf("ReadForm(1 << 20): %v, want ErrMessageTooLarge", err)
+ }
+ })
+ }
+}
+
+type neverendingReader byte
+
+func (r neverendingReader) Read(p []byte) (n int, err error) {
+ for i := range p {
+ p[i] = byte(r)
+ }
+ return len(p), nil
+}
+
func BenchmarkReadForm(b *testing.B) {
for _, test := range []struct {
name string
diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
index fc2590b1cdc..fcd1a011ac7 100644
--- a/src/net/textproto/reader.go
+++ b/src/net/textproto/reader.go
@@ -16,6 +16,10 @@ import (
"sync"
)
+// TODO: This should be a distinguishable error (ErrMessageTooLarge)
+// to allow mime/multipart to detect it.
+var errMessageTooLarge = errors.New("message too large")
+
// A Reader implements convenience methods for reading requests
// or responses from a text protocol network connection.
type Reader struct {
@@ -36,20 +40,23 @@ func NewReader(r *bufio.Reader) *Reader {
// ReadLine reads a single line from r,
// eliding the final \n or \r\n from the returned string.
func (r *Reader) ReadLine() (string, error) {
- line, err := r.readLineSlice()
+ line, err := r.readLineSlice(-1)
return string(line), err
}
// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
func (r *Reader) ReadLineBytes() ([]byte, error) {
- line, err := r.readLineSlice()
+ line, err := r.readLineSlice(-1)
if line != nil {
line = bytes.Clone(line)
}
return line, err
}
-func (r *Reader) readLineSlice() ([]byte, error) {
+// readLineSlice reads a single line from r,
+// up to lim bytes long (or unlimited if lim is less than 0),
+// eliding the final \r or \r\n from the returned string.
+func (r *Reader) readLineSlice(lim int64) ([]byte, error) {
r.closeDot()
var line []byte
for {
@@ -57,6 +64,9 @@ func (r *Reader) readLineSlice() ([]byte, error) {
if err != nil {
return nil, err
}
+ if lim >= 0 && int64(len(line))+int64(len(l)) > lim {
+ return nil, errMessageTooLarge
+ }
// Avoid the copy if the first call produced a full line.
if line == nil && !more {
return l, nil
@@ -88,7 +98,7 @@ func (r *Reader) readLineSlice() ([]byte, error) {
//
// Empty lines are never continued.
func (r *Reader) ReadContinuedLine() (string, error) {
- line, err := r.readContinuedLineSlice(noValidation)
+ line, err := r.readContinuedLineSlice(-1, noValidation)
return string(line), err
}
@@ -109,7 +119,7 @@ func trim(s []byte) []byte {
// ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string.
func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
- line, err := r.readContinuedLineSlice(noValidation)
+ line, err := r.readContinuedLineSlice(-1, noValidation)
if line != nil {
line = bytes.Clone(line)
}
@@ -120,13 +130,14 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
// returning a byte slice with all lines. The validateFirstLine function
// is run on the first read line, and if it returns an error then this
// error is returned from readContinuedLineSlice.
-func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([]byte, error) {
+// It reads up to lim bytes of data (or unlimited if lim is less than 0).
+func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) {
if validateFirstLine == nil {
return nil, fmt.Errorf("missing validateFirstLine func")
}
// Read the first line.
- line, err := r.readLineSlice()
+ line, err := r.readLineSlice(lim)
if err != nil {
return nil, err
}
@@ -154,13 +165,21 @@ func (r *Reader) readContinuedLineSlice(validateFirstLine func([]byte) error) ([
// copy the slice into buf.
r.buf = append(r.buf[:0], trim(line)...)
+ if lim < 0 {
+ lim = math.MaxInt64
+ }
+ lim -= int64(len(r.buf))
+
// Read continuation lines.
for r.skipSpace() > 0 {
- line, err := r.readLineSlice()
+ r.buf = append(r.buf, ' ')
+ if int64(len(r.buf)) >= lim {
+ return nil, errMessageTooLarge
+ }
+ line, err := r.readLineSlice(lim - int64(len(r.buf)))
if err != nil {
break
}
- r.buf = append(r.buf, ' ')
r.buf = append(r.buf, trim(line)...)
}
return r.buf, nil
@@ -507,7 +526,8 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
// The first line cannot start with a leading space.
if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
- line, err := r.readLineSlice()
+ const errorLimit = 80 // arbitrary limit on how much of the line we'll quote
+ line, err := r.readLineSlice(errorLimit)
if err != nil {
return m, err
}
@@ -515,7 +535,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
}
for {
- kv, err := r.readContinuedLineSlice(mustHaveFieldNameColon)
+ kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon)
if len(kv) == 0 {
return m, err
}
@@ -544,7 +564,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
maxHeaders--
if maxHeaders < 0 {
- return nil, errors.New("message too large")
+ return nil, errMessageTooLarge
}
// Skip initial spaces in value.
@@ -557,9 +577,7 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error)
}
maxMemory -= int64(len(value))
if maxMemory < 0 {
- // TODO: This should be a distinguishable error (ErrMessageTooLarge)
- // to allow mime/multipart to detect it.
- return m, errors.New("message too large")
+ return m, errMessageTooLarge
}
if vv == nil && len(strs) > 0 {
// More than likely this will be a single-element key.
diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
index 696ae406f38..26ff617470b 100644
--- a/src/net/textproto/reader_test.go
+++ b/src/net/textproto/reader_test.go
@@ -36,6 +36,18 @@ func TestReadLine(t *testing.T) {
}
}
+func TestReadLineLongLine(t *testing.T) {
+ line := strings.Repeat("12345", 10000)
+ r := reader(line + "\r\n")
+ s, err := r.ReadLine()
+ if err != nil {
+ t.Fatalf("Line 1: %v", err)
+ }
+ if s != line {
+ t.Fatalf("%v-byte line does not match expected %v-byte line", len(s), len(line))
+ }
+}
+
func TestReadContinuedLine(t *testing.T) {
r := reader("line1\nline\n 2\nline3\n")
s, err := r.ReadContinuedLine()
--
2.33.0

View File

@ -0,0 +1,117 @@
From 6021dca711926c32959c2dc4c2a68c9494e9a4fc Mon Sep 17 00:00:00 2001
From: Damien Neil <dneil@google.com>
Date: Thu, 11 Jan 2024 11:31:57 -0800
Subject: [PATCH 4/4] [release-branch.go1.21] net/http, net/http/cookiejar:
avoid subdomain matches on IPv6 zones
When deciding whether to forward cookies or sensitive headers
across a redirect, do not attempt to interpret an IPv6 address
as a domain name.
Avoids a case where a maliciously-crafted redirect to an
IPv6 address with a scoped addressing zone could be
misinterpreted as a within-domain redirect. For example,
we could interpret "::1%.www.example.com" as a subdomain
of "www.example.com".
Thanks to Juho Nurminen of Mattermost for reporting this issue.
Fixes CVE-2023-45289
Fixes #65385
For #65065
Change-Id: I8f463f59f0e700c8a18733d2b264a8bcb3a19599
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2131938
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
Reviewed-by: Roland Shoemaker <bracewell@google.com>
Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2173775
Reviewed-by: Carlos Amedee <amedee@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/569239
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
TryBot-Bypass: Michael Knyszek <mknyszek@google.com>
---
src/net/http/client.go | 6 ++++++
src/net/http/client_test.go | 1 +
src/net/http/cookiejar/jar.go | 7 +++++++
src/net/http/cookiejar/jar_test.go | 10 ++++++++++
4 files changed, 24 insertions(+)
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 2cab53a585a..77a701b8061 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -1014,6 +1014,12 @@ func isDomainOrSubdomain(sub, parent string) bool {
if sub == parent {
return true
}
+ // If sub contains a :, it's probably an IPv6 address (and is definitely not a hostname).
+ // Don't check the suffix in this case, to avoid matching the contents of a IPv6 zone.
+ // For example, "::1%.www.example.com" is not a subdomain of "www.example.com".
+ if strings.ContainsAny(sub, ":%") {
+ return false
+ }
// If sub is "foo.example.com" and parent is "example.com",
// that means sub must end in "."+parent.
// Do it without allocating.
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 0fe555af38f..fc1d7916124 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -1725,6 +1725,7 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
{"authorization", "http://foo.com/", "https://foo.com/", true},
{"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true},
{"www-authenticate", "http://foo.com/", "http://bar.com/", false},
+ {"authorization", "http://foo.com/", "http://[::1%25.foo.com]/", false},
// But subdomains should work:
{"www-authenticate", "http://foo.com/", "http://foo.com/", true},
diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go
index 273b54c84c7..4b16266057b 100644
--- a/src/net/http/cookiejar/jar.go
+++ b/src/net/http/cookiejar/jar.go
@@ -362,6 +362,13 @@ func jarKey(host string, psl PublicSuffixList) string {
// isIP reports whether host is an IP address.
func isIP(host string) bool {
+ if strings.ContainsAny(host, ":%") {
+ // Probable IPv6 address.
+ // Hostnames can't contain : or %, so this is definitely not a valid host.
+ // Treating it as an IP is the more conservative option, and avoids the risk
+ // of interpeting ::1%.www.example.com as a subtomain of www.example.com.
+ return true
+ }
return net.ParseIP(host) != nil
}
diff --git a/src/net/http/cookiejar/jar_test.go b/src/net/http/cookiejar/jar_test.go
index 56d0695a660..251f7c16171 100644
--- a/src/net/http/cookiejar/jar_test.go
+++ b/src/net/http/cookiejar/jar_test.go
@@ -252,6 +252,7 @@ var isIPTests = map[string]bool{
"127.0.0.1": true,
"1.2.3.4": true,
"2001:4860:0:2001::68": true,
+ "::1%zone": true,
"example.com": false,
"1.1.1.300": false,
"www.foo.bar.net": false,
@@ -629,6 +630,15 @@ var basicsTests = [...]jarTest{
{"http://www.host.test:1234/", "a=1"},
},
},
+ {
+ "IPv6 zone is not treated as a host.",
+ "https://example.com/",
+ []string{"a=1"},
+ "a=1",
+ []query{
+ {"https://[::1%25.example.com]:80/", ""},
+ },
+ },
}
func TestBasics(t *testing.T) {
--
2.33.0

View File

@ -63,7 +63,7 @@
Name: golang
Version: 1.21.4
Release: 2
Release: 3
Summary: The Go Programming Language
License: BSD and Public Domain
URL: https://golang.org/
@ -354,6 +354,9 @@ fi
%files devel -f go-tests.list -f go-misc.list -f go-src.list
%changelog
* Fri Mar 15 2024 hanchao <hanchao63@huawei.com> - 1.21.4-3
- fix CVE-2024-24783,CVE-2024-24785,CVE-2023-45290,CVE-2023-45289
* Wed Dec 13 2023 jiahua.yu <jiahua.yu@shingroup.cn> - 1.21.4-2
- init support for arch ppc64le