diff options
| author | CoprDistGit <infra@openeuler.org> | 2024-09-12 04:23:51 +0000 | 
|---|---|---|
| committer | CoprDistGit <infra@openeuler.org> | 2024-09-12 04:23:51 +0000 | 
| commit | 86d143317839566c602c276fafb1a30ad469941e (patch) | |
| tree | 4e895b6b563710cbc2cce86ead21f0a8d58cdcd3 | |
| parent | 2784bd2c52574b27d271d643816d481d9e4dfc8c (diff) | |
automatic import of golang
18 files changed, 3325 insertions, 0 deletions
| @@ -0,0 +1 @@ +/go1.21.4.src.tar.gz diff --git a/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch b/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch new file mode 100644 index 0000000..7ee3178 --- /dev/null +++ b/backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch @@ -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 + diff --git a/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch b/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch new file mode 100644 index 0000000..403cf6b --- /dev/null +++ b/backport-0002-release-branch.go1.21-html-template-escape-additiona.patch @@ -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 + diff --git a/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch b/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch new file mode 100644 index 0000000..a5d2254 --- /dev/null +++ b/backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch @@ -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 + diff --git a/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch b/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch new file mode 100644 index 0000000..db25f1e --- /dev/null +++ b/backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch @@ -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 + diff --git a/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch b/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch new file mode 100644 index 0000000..fc7b26c --- /dev/null +++ b/backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch @@ -0,0 +1,204 @@ +From 11c0f19796e30484848a6c9c469364c0841c17ef Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Wed, 10 Jan 2024 11:02:14 -0800 +Subject: [PATCH] [release-branch.go1.21] net/mail: properly handle special + characters in phrase and obs-phrase + +Fixes a couple of misalignments with RFC 5322 which introduce +significant diffs between (mostly) conformant parsers. + +This change reverts the changes made in CL50911, which allowed certain +special RFC 5322 characters to appear unquoted in the "phrase" syntax. +It is unclear why this change was made in the first place, and created +a divergence from comformant parsers. In particular this resulted in +treating comments in display names incorrectly. + +Additionally properly handle trailing malformed comments in the group +syntax. + +For #65083 +Fixes #65848 + +Change-Id: I00dddc044c6ae3381154e43236632604c390f672 +Reviewed-on: https://go-review.googlesource.com/c/go/+/555596 +Reviewed-by: Damien Neil <dneil@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/566195 +Reviewed-by: Carlos Amedee <carlos@golang.org> +--- + src/net/mail/message.go      | 30 +++++++++++++++------------ + src/net/mail/message_test.go | 40 ++++++++++++++++++++++++++---------- + 2 files changed, 46 insertions(+), 24 deletions(-) + +diff --git a/src/net/mail/message.go b/src/net/mail/message.go +index af516fc30f..fc2a9e46f8 100644 +--- a/src/net/mail/message.go ++++ b/src/net/mail/message.go +@@ -280,7 +280,7 @@ func (a *Address) String() string { + 	// Add quotes if needed + 	quoteLocal := false + 	for i, r := range local { +-		if isAtext(r, false, false) { ++		if isAtext(r, false) { + 			continue + 		} + 		if r == '.' { +@@ -444,7 +444,7 @@ func (p *addrParser) parseAddress(handleGroup bool) ([]*Address, error) { + 	if !p.consume('<') { + 		atext := true + 		for _, r := range displayName { +-			if !isAtext(r, true, false) { ++			if !isAtext(r, true) { + 				atext = false + 				break + 			} +@@ -479,7 +479,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) { + 	// handle empty group. + 	p.skipSpace() + 	if p.consume(';') { +-		p.skipCFWS() ++		if !p.skipCFWS() { ++			return nil, errors.New("mail: misformatted parenthetical comment") ++		} + 		return group, nil + 	} +  +@@ -496,7 +498,9 @@ func (p *addrParser) consumeGroupList() ([]*Address, error) { + 			return nil, errors.New("mail: misformatted parenthetical comment") + 		} + 		if p.consume(';') { +-			p.skipCFWS() ++			if !p.skipCFWS() { ++				return nil, errors.New("mail: misformatted parenthetical comment") ++			} + 			break + 		} + 		if !p.consume(',') { +@@ -566,6 +570,12 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { + 	var words []string + 	var isPrevEncoded bool + 	for { ++		// obs-phrase allows CFWS after one word ++		if len(words) > 0 { ++			if !p.skipCFWS() { ++				return "", errors.New("mail: misformatted parenthetical comment") ++			} ++		} + 		// word = atom / quoted-string + 		var word string + 		p.skipSpace() +@@ -661,7 +671,6 @@ Loop: + // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. + // If permissive is true, consumeAtom will not fail on: + // - leading/trailing/double dots in the atom (see golang.org/issue/4938) +-// - special characters (RFC 5322 3.2.3) except '<', '>', ':' and '"' (see golang.org/issue/21018) + func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { + 	i := 0 +  +@@ -672,7 +681,7 @@ Loop: + 		case size == 1 && r == utf8.RuneError: + 			return "", fmt.Errorf("mail: invalid utf-8 in address: %q", p.s) +  +-		case size == 0 || !isAtext(r, dot, permissive): ++		case size == 0 || !isAtext(r, dot): + 			break Loop +  + 		default: +@@ -850,18 +859,13 @@ func (e charsetError) Error() string { +  + // isAtext reports whether r is an RFC 5322 atext character. + // If dot is true, period is included. +-// If permissive is true, RFC 5322 3.2.3 specials is included, +-// except '<', '>', ':' and '"'. +-func isAtext(r rune, dot, permissive bool) bool { ++func isAtext(r rune, dot bool) bool { + 	switch r { + 	case '.': + 		return dot +  + 	// RFC 5322 3.2.3. specials +-	case '(', ')', '[', ']', ';', '@', '\\', ',': +-		return permissive +- +-	case '<', '>', '"', ':': ++	case '(', ')', '<', '>', '[', ']', ':', ';', '@', '\\', ',', '"': // RFC 5322 3.2.3. specials + 		return false + 	} + 	return isVchar(r) +diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go +index 1e1bb4092f..1f2f62afbf 100644 +--- a/src/net/mail/message_test.go ++++ b/src/net/mail/message_test.go +@@ -385,8 +385,11 @@ func TestAddressParsingError(t *testing.T) { + 		13: {"group not closed: null@example.com", "expected comma"}, + 		14: {"group: first@example.com, second@example.com;", "group with multiple addresses"}, + 		15: {"john.doe", "missing '@' or angle-addr"}, +-		16: {"john.doe@", "no angle-addr"}, ++		16: {"john.doe@", "missing '@' or angle-addr"}, + 		17: {"John Doe@foo.bar", "no angle-addr"}, ++		18: {" group: null@example.com; (asd", "misformatted parenthetical comment"}, ++		19: {" group: ; (asd", "misformatted parenthetical comment"}, ++		20: {`(John) Doe <jdoe@machine.example>`, "missing word in phrase:"}, + 	} +  + 	for i, tc := range mustErrTestCases { +@@ -436,24 +439,19 @@ func TestAddressParsing(t *testing.T) { + 				Address: "john.q.public@example.com", + 			}}, + 		}, +-		{ +-			`"John (middle) Doe" <jdoe@machine.example>`, +-			[]*Address{{ +-				Name:    "John (middle) Doe", +-				Address: "jdoe@machine.example", +-			}}, +-		}, ++		// Comment in display name + 		{ + 			`John (middle) Doe <jdoe@machine.example>`, + 			[]*Address{{ +-				Name:    "John (middle) Doe", ++				Name:    "John Doe", + 				Address: "jdoe@machine.example", + 			}}, + 		}, ++		// Display name is quoted string, so comment is not a comment + 		{ +-			`John !@M@! Doe <jdoe@machine.example>`, ++			`"John (middle) Doe" <jdoe@machine.example>`, + 			[]*Address{{ +-				Name:    "John !@M@! Doe", ++				Name:    "John (middle) Doe", + 				Address: "jdoe@machine.example", + 			}}, + 		}, +@@ -788,6 +786,26 @@ func TestAddressParsing(t *testing.T) { + 				}, + 			}, + 		}, ++		// Comment in group display name ++		{ ++			`group (comment:): a@example.com, b@example.com;`, ++			[]*Address{ ++				{ ++					Address: "a@example.com", ++				}, ++				{ ++					Address: "b@example.com", ++				}, ++			}, ++		}, ++		{ ++			`x(:"):"@a.example;("@b.example;`, ++			[]*Address{ ++				{ ++					Address: `@a.example;(@b.example`, ++				}, ++			}, ++		}, + 	} + 	for _, test := range tests { + 		if len(test.exp) == 1 { +--  +2.33.0 + diff --git a/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch b/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch new file mode 100644 index 0000000..ab4dfb2 --- /dev/null +++ b/backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch @@ -0,0 +1,82 @@ +From a65a2b54e18a7e269bff32526b4180ece22e9aa6 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 28 Mar 2024 16:57:51 -0700 +Subject: [PATCH] [Backport] net/http: update bundled golang.org/x/net/http2 + +Offering: Cloud Core Network +CVE: CVE-2023-45288 +Reference: https://go-review.googlesource.com/c/go/+/576076 + +Disable cmd/internal/moddeps test, since this update includes PRIVATE +track fixes. + +Fixes CVE-2023-45288 +For #65051 +Fixes #66298 + +Change-Id: I5bbf774ebe7651e4bb7e55139d3794bd2b8e8fa8 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2197227 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Run-TryBot: Damien Neil <dneil@google.com> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/576076 +Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> +TryBot-Bypass: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: Than McIntosh <thanm@google.com> +Signed-off-by: Ma Chang Wang machangwang@huawei.com +--- + src/net/http/h2_bundle.go | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go +index dd59e1f4f2..cd95f84269 100644 +--- a/src/net/http/h2_bundle.go ++++ b/src/net/http/h2_bundle.go +@@ -2966,6 +2966,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr + 		if size > remainSize { + 			hdec.SetEmitEnabled(false) + 			mh.Truncated = true ++			remainSize = 0 + 			return + 		} + 		remainSize -= size +@@ -2978,6 +2979,36 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr + 	var hc http2headersOrContinuation = hf + 	for { + 		frag := hc.HeaderBlockFragment() ++ ++		// Avoid parsing large amounts of headers that we will then discard. ++		// If the sender exceeds the max header list size by too much, ++		// skip parsing the fragment and close the connection. ++		// ++		// "Too much" is either any CONTINUATION frame after we've already ++		// exceeded the max header list size (in which case remainSize is 0), ++		// or a frame whose encoded size is more than twice the remaining ++		// header list bytes we're willing to accept. ++		if int64(len(frag)) > int64(2*remainSize) { ++			if http2VerboseLogs { ++				log.Printf("http2: header list too large") ++			} ++			// It would be nice to send a RST_STREAM before sending the GOAWAY, ++			// but the struture of the server's frame writer makes this difficult. ++			return nil, http2ConnectionError(http2ErrCodeProtocol) ++		} ++ ++		// Also close the connection after any CONTINUATION frame following an ++		// invalid header, since we stop tracking the size of the headers after ++		// an invalid one. ++		if invalid != nil { ++			if http2VerboseLogs { ++				log.Printf("http2: invalid header: %v", invalid) ++			} ++			// It would be nice to send a RST_STREAM before sending the GOAWAY, ++			// but the struture of the server's frame writer makes this difficult. ++			return nil, http2ConnectionError(http2ErrCodeProtocol) ++		} ++ + 		if _, err := hdec.Write(frag); err != nil { + 			return nil, http2ConnectionError(http2ErrCodeCompression) + 		} +--  +2.33.0 + diff --git a/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch b/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch new file mode 100644 index 0000000..b1c16a5 --- /dev/null +++ b/backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch @@ -0,0 +1,133 @@ +From 7edadbad6c5ba7db3c4ab6925369096dedcf8e0b Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Thu, 25 Apr 2024 13:09:54 -0700 +Subject: [PATCH] [Backport] cmd/go: disallow -lto_library in LDFLAGS +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Offering: Cloud Core Network +CVE: CVE-2024-24787 +Reference: https://go-review.googlesource.com/c/go/+/583796 + +The darwin linker allows setting the LTO library with the -lto_library +flag. This wasn't caught by our "safe linker flags" check because it +was covered by the -lx flag used for linking libraries. This change +adds a specific check for excluded flags which otherwise satisfy our +existing checks. + +Loading a mallicious LTO library would allow an attacker to cause the +linker to execute abritrary code when "go build" was called. + +Thanks to Juho Forsén of Mattermost for reporting this issue. + +Fixes #67119 +Fixes #67122 +Fixes CVE-2024-24787 + +Change-Id: I77ac8585efbdbdfd5f39c39ed623b9408a0f9eaf +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1380 +Reviewed-by: Russ Cox <rsc@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit 9a79141fbbca1105e5c786f15e38741ca7843290) +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1420 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/583796 +Reviewed-by: David Chase <drchase@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Signed-off-by: Ma Chang Wang machangwang@huawei.com +--- + src/cmd/go/internal/work/security.go          | 19 +++++++++++++++---- + .../script/darwin_lto_library_ldflag.txt      | 17 +++++++++++++++++ + 2 files changed, 32 insertions(+), 4 deletions(-) + create mode 100644 src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt + +diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go +index 270a34e9c7..db49eb6488 100644 +--- a/src/cmd/go/internal/work/security.go ++++ b/src/cmd/go/internal/work/security.go +@@ -141,6 +141,12 @@ var validCompilerFlagsWithNextArg = []string{ + 	"-x", + } +  ++var invalidLinkerFlags = []*lazyregexp.Regexp{ ++	// On macOS this means the linker loads and executes the next argument. ++	// Have to exclude separately because -lfoo is allowed in general. ++	re(`-lto_library`), ++} ++ + var validLinkerFlags = []*lazyregexp.Regexp{ + 	re(`-F([^@\-].*)`), + 	re(`-l([^@\-].*)`), +@@ -231,12 +237,12 @@ var validLinkerFlagsWithNextArg = []string{ +  + func checkCompilerFlags(name, source string, list []string) error { + 	checkOverrides := true +-	return checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides) ++	return checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides) + } +  + func checkLinkerFlags(name, source string, list []string) error { + 	checkOverrides := true +-	return checkFlags(name, source, list, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) ++	return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides) + } +  + // checkCompilerFlagsForInternalLink returns an error if 'list' +@@ -245,7 +251,7 @@ func checkLinkerFlags(name, source string, list []string) error { + // external linker). + func checkCompilerFlagsForInternalLink(name, source string, list []string) error { + 	checkOverrides := false +-	if err := checkFlags(name, source, list, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil { ++	if err := checkFlags(name, source, list, nil, validCompilerFlags, validCompilerFlagsWithNextArg, checkOverrides); err != nil { + 		return err + 	} + 	// Currently the only flag on the allow list that causes problems +@@ -258,7 +264,7 @@ func checkCompilerFlagsForInternalLink(name, source string, list []string) error + 	return nil + } +  +-func checkFlags(name, source string, list []string, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error { ++func checkFlags(name, source string, list []string, invalid, valid []*lazyregexp.Regexp, validNext []string, checkOverrides bool) error { + 	// Let users override rules with $CGO_CFLAGS_ALLOW, $CGO_CFLAGS_DISALLOW, etc. + 	var ( + 		allow    *regexp.Regexp +@@ -290,6 +296,11 @@ Args: + 		if allow != nil && allow.FindString(arg) == arg { + 			continue Args + 		} ++		for _, re := range invalid { ++			if re.FindString(arg) == arg { // must be complete match ++				goto Bad ++			} ++		} + 		for _, re := range valid { + 			if re.FindString(arg) == arg { // must be complete match + 				continue Args +diff --git a/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt b/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt +new file mode 100644 +index 0000000000..d7acefdbad +--- /dev/null ++++ b/src/cmd/go/testdata/script/darwin_lto_library_ldflag.txt +@@ -0,0 +1,17 @@ ++[!GOOS:darwin] skip ++[!cgo] skip ++ ++! go build ++stderr 'invalid flag in #cgo LDFLAGS: -lto_library' ++ ++-- go.mod -- ++module ldflag ++ ++-- main.go -- ++package main ++ ++// #cgo CFLAGS: -flto ++// #cgo LDFLAGS: -lto_library bad.dylib ++import "C" ++ ++func main() {} +\ No newline at end of file +--  +2.33.0 + diff --git a/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch b/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch new file mode 100644 index 0000000..261dbe0 --- /dev/null +++ b/backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch @@ -0,0 +1,221 @@ +From 051bdf3fd12a40307606ff9381138039c5f452f0 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker <bracewell@google.com> +Date: Tue, 28 May 2024 13:26:31 -0700 +Subject: [PATCH] [release-branch.go1.21] net/netip: check if address is v6 + mapped in Is methods + +In all of the Is* methods, check if the address is a v6 mapped v4 +address, and unmap it if so. + +Thanks to Enze Wang of Alioth (@zer0yu) and Jianjun Chen of Zhongguancun +Lab (@chenjj) for reporting this issue. + +Fixes #67680 +Fixes #67681 +Fixes CVE-2024-24790 + +Change-Id: I6bd03ca1a5d93a0b59027d861c84060967b265b0 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1460 +Reviewed-by: Russ Cox <rsc@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +(cherry picked from commit f7f270c1621fdc7ee48e0487b2fac0356947d19b) +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1500 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/590315 +Auto-Submit: Michael Knyszek <mknyszek@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: David Chase <drchase@google.com> +--- + src/net/netip/inlining_test.go |  2 -- + src/net/netip/netip.go         | 26 +++++++++++++++++- + src/net/netip/netip_test.go    | 50 +++++++++++++++++++++++++++++++--- + 3 files changed, 71 insertions(+), 7 deletions(-) + +diff --git a/src/net/netip/inlining_test.go b/src/net/netip/inlining_test.go +index b521eeebfd8f3..98584b098df1b 100644 +--- a/src/net/netip/inlining_test.go ++++ b/src/net/netip/inlining_test.go +@@ -36,8 +36,6 @@ func TestInlining(t *testing.T) { + 		"Addr.Is4", + 		"Addr.Is4In6", + 		"Addr.Is6", +-		"Addr.IsLoopback", +-		"Addr.IsMulticast", + 		"Addr.IsInterfaceLocalMulticast", + 		"Addr.IsValid", + 		"Addr.IsUnspecified", +diff --git a/src/net/netip/netip.go b/src/net/netip/netip.go +index a44b09495549d..9e4d41f8fb7b9 100644 +--- a/src/net/netip/netip.go ++++ b/src/net/netip/netip.go +@@ -507,6 +507,10 @@ func (ip Addr) hasZone() bool { +  + // IsLinkLocalUnicast reports whether ip is a link-local unicast address. + func (ip Addr) IsLinkLocalUnicast() bool { ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// Dynamic Configuration of IPv4 Link-Local Addresses + 	// https://datatracker.ietf.org/doc/html/rfc3927#section-2.1 + 	if ip.Is4() { +@@ -522,6 +526,10 @@ func (ip Addr) IsLinkLocalUnicast() bool { +  + // IsLoopback reports whether ip is a loopback address. + func (ip Addr) IsLoopback() bool { ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// Requirements for Internet Hosts -- Communication Layers (3.2.1.3 Addressing) + 	// https://datatracker.ietf.org/doc/html/rfc1122#section-3.2.1.3 + 	if ip.Is4() { +@@ -537,6 +545,10 @@ func (ip Addr) IsLoopback() bool { +  + // IsMulticast reports whether ip is a multicast address. + func (ip Addr) IsMulticast() bool { ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// Host Extensions for IP Multicasting (4. HOST GROUP ADDRESSES) + 	// https://datatracker.ietf.org/doc/html/rfc1112#section-4 + 	if ip.Is4() { +@@ -555,7 +567,7 @@ func (ip Addr) IsMulticast() bool { + func (ip Addr) IsInterfaceLocalMulticast() bool { + 	// IPv6 Addressing Architecture (2.7.1. Pre-Defined Multicast Addresses) + 	// https://datatracker.ietf.org/doc/html/rfc4291#section-2.7.1 +-	if ip.Is6() { ++	if ip.Is6() && !ip.Is4In6() { + 		return ip.v6u16(0)&0xff0f == 0xff01 + 	} + 	return false // zero value +@@ -563,6 +575,10 @@ func (ip Addr) IsInterfaceLocalMulticast() bool { +  + // IsLinkLocalMulticast reports whether ip is a link-local multicast address. + func (ip Addr) IsLinkLocalMulticast() bool { ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// IPv4 Multicast Guidelines (4. Local Network Control Block (224.0.0/24)) + 	// https://datatracker.ietf.org/doc/html/rfc5771#section-4 + 	if ip.Is4() { +@@ -591,6 +607,10 @@ func (ip Addr) IsGlobalUnicast() bool { + 		return false + 	} +  ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// Match package net's IsGlobalUnicast logic. Notably private IPv4 addresses + 	// and ULA IPv6 addresses are still considered "global unicast". + 	if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) { +@@ -608,6 +628,10 @@ func (ip Addr) IsGlobalUnicast() bool { + // ip is in 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, or fc00::/7. This is the + // same as net.IP.IsPrivate. + func (ip Addr) IsPrivate() bool { ++	if ip.Is4In6() { ++		ip = ip.Unmap() ++	} ++ + 	// Match the stdlib's IsPrivate logic. + 	if ip.Is4() { + 		// RFC 1918 allocates 10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16 as +diff --git a/src/net/netip/netip_test.go b/src/net/netip/netip_test.go +index 0f80bb0ab0e56..5c7ad14c5c702 100644 +--- a/src/net/netip/netip_test.go ++++ b/src/net/netip/netip_test.go +@@ -589,10 +589,13 @@ func TestIPProperties(t *testing.T) { + 		ilm6     = mustIP("ff01::1") + 		ilmZone6 = mustIP("ff01::1%eth0") +  +-		private4a = mustIP("10.0.0.1") +-		private4b = mustIP("172.16.0.1") +-		private4c = mustIP("192.168.1.1") +-		private6  = mustIP("fd00::1") ++		private4a        = mustIP("10.0.0.1") ++		private4b        = mustIP("172.16.0.1") ++		private4c        = mustIP("192.168.1.1") ++		private6         = mustIP("fd00::1") ++		private6mapped4a = mustIP("::ffff:10.0.0.1") ++		private6mapped4b = mustIP("::ffff:172.16.0.1") ++		private6mapped4c = mustIP("::ffff:192.168.1.1") + 	) +  + 	tests := []struct { +@@ -616,6 +619,11 @@ func TestIPProperties(t *testing.T) { + 			ip:            unicast4, + 			globalUnicast: true, + 		}, ++		{ ++			name:          "unicast v6 mapped v4Addr", ++			ip:            AddrFrom16(unicast4.As16()), ++			globalUnicast: true, ++		}, + 		{ + 			name:          "unicast v6Addr", + 			ip:            unicast6, +@@ -637,6 +645,12 @@ func TestIPProperties(t *testing.T) { + 			linkLocalMulticast: true, + 			multicast:          true, + 		}, ++		{ ++			name:               "multicast v6 mapped v4Addr", ++			ip:                 AddrFrom16(multicast4.As16()), ++			linkLocalMulticast: true, ++			multicast:          true, ++		}, + 		{ + 			name:               "multicast v6Addr", + 			ip:                 multicast6, +@@ -654,6 +668,11 @@ func TestIPProperties(t *testing.T) { + 			ip:               llu4, + 			linkLocalUnicast: true, + 		}, ++		{ ++			name:             "link-local unicast v6 mapped v4Addr", ++			ip:               AddrFrom16(llu4.As16()), ++			linkLocalUnicast: true, ++		}, + 		{ + 			name:             "link-local unicast v6Addr", + 			ip:               llu6, +@@ -679,6 +698,11 @@ func TestIPProperties(t *testing.T) { + 			ip:       IPv6Loopback(), + 			loopback: true, + 		}, ++		{ ++			name:     "loopback v6 mapped v4Addr", ++			ip:       AddrFrom16(IPv6Loopback().As16()), ++			loopback: true, ++		}, + 		{ + 			name:                    "interface-local multicast v6Addr", + 			ip:                      ilm6, +@@ -715,6 +739,24 @@ func TestIPProperties(t *testing.T) { + 			globalUnicast: true, + 			private:       true, + 		}, ++		{ ++			name:          "private v6 mapped v4Addr 10/8", ++			ip:            private6mapped4a, ++			globalUnicast: true, ++			private:       true, ++		}, ++		{ ++			name:          "private v6 mapped v4Addr 172.16/12", ++			ip:            private6mapped4b, ++			globalUnicast: true, ++			private:       true, ++		}, ++		{ ++			name:          "private v6 mapped v4Addr 192.168/16", ++			ip:            private6mapped4c, ++			globalUnicast: true, ++			private:       true, ++		}, + 		{ + 			name:        "unspecified v4Addr", + 			ip:          IPv4Unspecified(), diff --git a/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch b/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch new file mode 100644 index 0000000..fb5d4bb --- /dev/null +++ b/backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch @@ -0,0 +1,108 @@ +From 558cbc498c70278bea8297272f2d4fc50d67893b Mon Sep 17 00:00:00 2001 +From: "Bryan C. Mills" <bcmills@google.com> +Date: Thu, 2 Nov 2023 15:06:35 -0400 +Subject: [PATCH] [Backport] cmd/go/internal/vcs: error out if the requested + repo does not support a secure protocol + +CVE: CVE-2023-45285 +Reference: https://go-review.googlesource.com/c/go/+/540335 + +Updates #63845. +Fixes #63972. + +Change-Id: If86d6b13d3b55877b35c087112bd76388c9404b8 +Reviewed-on: https://go-review.googlesource.com/c/go/+/539321 +Reviewed-by: Michael Matloob <matloob@golang.org> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: Roland Shoemaker <roland@golang.org> +Auto-Submit: Bryan Mills <bcmills@google.com> +(cherry picked from commit be26ae18caf7ddffca4073333f80d0d9e76483c3) +Reviewed-on: https://go-review.googlesource.com/c/go/+/540335 +Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +Signed-off-by: wangbingyao 00557526 <wangbingyao5@huawei.com> +--- + src/cmd/go/internal/vcs/vcs.go                | 25 +++++++++++++---- + .../script/mod_insecure_issue63845.txt        | 28 +++++++++++++++++++ + 2 files changed, 47 insertions(+), 6 deletions(-) + create mode 100644 src/cmd/go/testdata/script/mod_insecure_issue63845.txt + +diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go +index c65dd0f624..dbf16d1de7 100644 +--- a/src/cmd/go/internal/vcs/vcs.go ++++ b/src/cmd/go/internal/vcs/vcs.go +@@ -1204,18 +1204,31 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths + 			var ok bool + 			repoURL, ok = interceptVCSTest(repo, vcs, security) + 			if !ok { +-				scheme := vcs.Scheme[0] // default to first scheme +-				if vcs.PingCmd != "" { +-					// If we know how to test schemes, scan to find one. ++				scheme, err := func() (string, error) { + 					for _, s := range vcs.Scheme { + 						if security == web.SecureOnly && !vcs.isSecureScheme(s) { + 							continue + 						} +-						if vcs.Ping(s, repo) == nil { +-							scheme = s +-							break ++ ++						// If we know how to ping URL schemes for this VCS, ++						// check that this repo works. ++						// Otherwise, default to the first scheme ++						// that meets the requested security level. ++						if vcs.PingCmd == "" { ++							return s, nil ++						} ++						if err := vcs.Ping(s, repo); err == nil { ++							return s, nil + 						} + 					} ++					securityFrag := "" ++					if security == web.SecureOnly { ++						securityFrag = "secure " ++					} ++					return "", fmt.Errorf("no %sprotocol found for repository", securityFrag) ++				}() ++				if err != nil { ++					return nil, err + 				} + 				repoURL = scheme + "://" + repo + 			} +diff --git a/src/cmd/go/testdata/script/mod_insecure_issue63845.txt b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt +new file mode 100644 +index 0000000000..5fa6a4f12b +--- /dev/null ++++ b/src/cmd/go/testdata/script/mod_insecure_issue63845.txt +@@ -0,0 +1,28 @@ ++# Regression test for https://go.dev/issue/63845: ++# If 'git ls-remote' fails for all secure protocols, ++# we should fail instead of falling back to an arbitrary protocol. ++# ++# Note that this test does not use the local vcweb test server ++# (vcs-test.golang.org), because the hook for redirecting to that ++# server bypasses the "ping to determine protocol" logic ++# in cmd/go/internal/vcs. ++ ++[!net] skip ++[!git] skip ++[short] skip 'tries to access a nonexistent external Git repo' ++ ++env GOPRIVATE=golang.org ++env CURLOPT_TIMEOUT_MS=100 ++env GIT_SSH_COMMAND=false ++ ++! go get -x golang.org/nonexist.git@latest ++stderr '^git ls-remote https://golang.org/nonexist$' ++stderr '^git ls-remote git\+ssh://golang.org/nonexist' ++stderr '^git ls-remote ssh://golang.org/nonexist$' ++! stderr 'git://' ++stderr '^go: golang.org/nonexist.git@latest: no secure protocol found for repository$' ++ ++-- go.mod -- ++module example ++ ++go 1.19 +--  +2.33.0 + diff --git a/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch b/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch new file mode 100644 index 0000000..67367a4 --- /dev/null +++ b/backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch @@ -0,0 +1,175 @@ +From 43c0e9116f26416de7454855852eba9083d94d03 Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Tue, 7 Nov 2023 10:47:56 -0800 +Subject: [PATCH 1/2] [release-branch.go1.21] net/http: limit chunked data + overhead + +The chunked transfer encoding adds some overhead to +the content transferred. When writing one byte per +chunk, for example, there are five bytes of overhead +per byte of data transferred: "1\r\nX\r\n" to send "X". + +Chunks may include "chunk extensions", +which we skip over and do not use. +For example: "1;chunk extension here\r\nX\r\n". + +A malicious sender can use chunk extensions to add +about 4k of overhead per byte of data. +(The maximum chunk header line size we will accept.) + +Track the amount of overhead read in chunked data, +and produce an error if it seems excessive. + +Updates #64433 +Fixes #64435 +Fixes CVE-2023-39326 + +Change-Id: I40f8d70eb6f9575fb43f506eb19132ccedafcf39 +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2076135 +Reviewed-by: Tatiana Bradley <tatianabradley@google.com> +Reviewed-by: Roland Shoemaker <bracewell@google.com> +(cherry picked from commit 3473ae72ee66c60744665a24b2fde143e8964d4f) +Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2095408 +Run-TryBot: Roland Shoemaker <bracewell@google.com> +Reviewed-by: Damien Neil <dneil@google.com> +Reviewed-on: https://go-review.googlesource.com/c/go/+/547356 +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +--- + src/net/http/internal/chunked.go      | 34 ++++++++++++--- + src/net/http/internal/chunked_test.go | 59 +++++++++++++++++++++++++++ + 2 files changed, 87 insertions(+), 6 deletions(-) + +diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go +index 5a174415dc4..aad8e5aa09e 100644 +--- a/src/net/http/internal/chunked.go ++++ b/src/net/http/internal/chunked.go +@@ -39,7 +39,8 @@ type chunkedReader struct { + 	n        uint64 // unread bytes in chunk + 	err      error + 	buf      [2]byte +-	checkEnd bool // whether need to check for \r\n chunk footer ++	checkEnd bool  // whether need to check for \r\n chunk footer ++	excess   int64 // "excessive" chunk overhead, for malicious sender detection + } +  + func (cr *chunkedReader) beginChunk() { +@@ -49,10 +50,36 @@ func (cr *chunkedReader) beginChunk() { + 	if cr.err != nil { + 		return + 	} ++	cr.excess += int64(len(line)) + 2 // header, plus \r\n after the chunk data ++	line = trimTrailingWhitespace(line) ++	line, cr.err = removeChunkExtension(line) ++	if cr.err != nil { ++		return ++	} + 	cr.n, cr.err = parseHexUint(line) + 	if cr.err != nil { + 		return + 	} ++	// A sender who sends one byte per chunk will send 5 bytes of overhead ++	// for every byte of data. ("1\r\nX\r\n" to send "X".) ++	// We want to allow this, since streaming a byte at a time can be legitimate. ++	// ++	// A sender can use chunk extensions to add arbitrary amounts of additional ++	// data per byte read. ("1;very long extension\r\nX\r\n" to send "X".) ++	// We don't want to disallow extensions (although we discard them), ++	// but we also don't want to allow a sender to reduce the signal/noise ratio ++	// arbitrarily. ++	// ++	// We track the amount of excess overhead read, ++	// and produce an error if it grows too large. ++	// ++	// Currently, we say that we're willing to accept 16 bytes of overhead per chunk, ++	// plus twice the amount of real data in the chunk. ++	cr.excess -= 16 + (2 * int64(cr.n)) ++	cr.excess = max(cr.excess, 0) ++	if cr.excess > 16*1024 { ++		cr.err = errors.New("chunked encoding contains too much non-data") ++	} + 	if cr.n == 0 { + 		cr.err = io.EOF + 	} +@@ -140,11 +167,6 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { + 	if len(p) >= maxLineLength { + 		return nil, ErrLineTooLong + 	} +-	p = trimTrailingWhitespace(p) +-	p, err = removeChunkExtension(p) +-	if err != nil { +-		return nil, err +-	} + 	return p, nil + } +  +diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go +index 5e29a786dd6..b99090c1f8a 100644 +--- a/src/net/http/internal/chunked_test.go ++++ b/src/net/http/internal/chunked_test.go +@@ -239,3 +239,62 @@ func TestChunkEndReadError(t *testing.T) { + 		t.Errorf("expected %v, got %v", readErr, err) + 	} + } ++ ++func TestChunkReaderTooMuchOverhead(t *testing.T) { ++	// If the sender is sending 100x as many chunk header bytes as chunk data, ++	// we should reject the stream at some point. ++	chunk := []byte("1;") ++	for i := 0; i < 100; i++ { ++		chunk = append(chunk, 'a') // chunk extension ++	} ++	chunk = append(chunk, "\r\nX\r\n"...) ++	const bodylen = 1 << 20 ++	r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) { ++		if i < bodylen { ++			return chunk, nil ++		} ++		return []byte("0\r\n"), nil ++	}}) ++	_, err := io.ReadAll(r) ++	if err == nil { ++		t.Fatalf("successfully read body with excessive overhead; want error") ++	} ++} ++ ++func TestChunkReaderByteAtATime(t *testing.T) { ++	// Sending one byte per chunk should not trip the excess-overhead detection. ++	const bodylen = 1 << 20 ++	r := NewChunkedReader(&funcReader{f: func(i int) ([]byte, error) { ++		if i < bodylen { ++			return []byte("1\r\nX\r\n"), nil ++		} ++		return []byte("0\r\n"), nil ++	}}) ++	got, err := io.ReadAll(r) ++	if err != nil { ++		t.Errorf("unexpected error: %v", err) ++	} ++	if len(got) != bodylen { ++		t.Errorf("read %v bytes, want %v", len(got), bodylen) ++	} ++} ++ ++type funcReader struct { ++	f   func(iteration int) ([]byte, error) ++	i   int ++	b   []byte ++	err error ++} ++ ++func (r *funcReader) Read(p []byte) (n int, err error) { ++	if len(r.b) == 0 && r.err == nil { ++		r.b, r.err = r.f(r.i) ++		r.i++ ++	} ++	n = copy(p, r.b) ++	r.b = r.b[n:] ++	if len(r.b) > 0 { ++		return n, nil ++	} ++	return n, r.err ++} +--  +2.33.0 + diff --git a/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch b/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch new file mode 100644 index 0000000..55beba5 --- /dev/null +++ b/backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch @@ -0,0 +1,58 @@ +From c69c5c62775d84aa56a43bedaa4fcacbb73d403d Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Tue, 14 May 2024 14:39:10 -0700 +Subject: [PATCH] [Backport] archive/zip: treat truncated EOCDR comment as an + error + +CVE: CVE-2024-24789 +Reference: https://go-review.googlesource.com/c/go/+/588796 + +When scanning for an end of central directory record, +treat an EOCDR signature with a record containing a truncated +comment as an error. Previously, we would skip over the invalid +record and look for another one. Other implementations do not +do this (they either consider this a hard error, or just ignore +the truncated comment). This parser misalignment allowed +presenting entirely different archive contents to Go programs +and other zip decoders. + +For #66869 +Fixes #67554 +Fixes CVE-2024-24789 + +Change-Id: I94e5cb028534bb5704588b8af27f1e22ea49c7c6 +Reviewed-on: https://go-review.googlesource.com/c/go/+/585397 +Reviewed-by: Joseph Tsai <joetsai@digital-static.net> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +(cherry picked from commit 33d725e5758bf1fea62e6c77fc70b57a828a49f5) +Reviewed-on: https://go-review.googlesource.com/c/go/+/588796 +Reviewed-by: Matthew Dempsky <mdempsky@google.com> +Signed-off-by: Ma Chang Wang machangwang@huawei.com +--- + src/archive/zip/reader.go | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go +index 1fde1decc4..20356bde0e 100644 +--- a/src/archive/zip/reader.go ++++ b/src/archive/zip/reader.go +@@ -699,9 +699,13 @@ func findSignatureInBlock(b []byte) int { + 		if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 { + 			// n is length of comment + 			n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8 +-			if n+directoryEndLen+i <= len(b) { +-				return i ++			if n+directoryEndLen+i > len(b) { ++				// Truncated comment. ++				// Some parsers (such as Info-ZIP) ignore the truncated comment ++				// rather than treating it as a hard error. ++				return -1 + 			} ++			return i + 		} + 	} + 	return -1 +--  +2.33.0 + diff --git a/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch b/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch new file mode 100644 index 0000000..30501ff --- /dev/null +++ b/backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch @@ -0,0 +1,353 @@ +From c9be6ae748b7679b644a38182d456cb5a6ac06ee Mon Sep 17 00:00:00 2001 +From: Damien Neil <dneil@google.com> +Date: Thu, 6 Jun 2024 12:50:46 -0700 +Subject: [PATCH] [release-branch.go1.21] net/http: send body or close + connection on expect-100-continue requests + +When sending a request with an "Expect: 100-continue" header, +we must send the request body before sending any further requests +on the connection. + +When receiving a non-1xx response to an "Expect: 100-continue" request, +send the request body if the connection isn't being closed after +processing the response. In other words, if either the request +or response contains a "Connection: close" header, then skip sending +the request body (because the connection will not be used for +further requests), but otherwise send it. + +Correct a comment on the server-side Expect: 100-continue handling +that implied sending the request body is optional. It isn't. + +For #67555 +Fixes #68199 + +Change-Id: Ia2f12091bee697771087f32ac347509ec5922d54 +Reviewed-on: https://go-review.googlesource.com/c/go/+/591255 +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: Jonathan Amsterdam <jba@google.com> +(cherry picked from commit cf501e05e138e6911f759a5db786e90b295499b9) +Reviewed-on: https://go-review.googlesource.com/c/go/+/595096 +Reviewed-by: Joedian Reid <joedian@google.com> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +--- + src/net/http/server.go         |  25 ++-- + src/net/http/transport.go      |  34 ++++-- + src/net/http/transport_test.go | 202 ++++++++++++++++++++------------- + 3 files changed, 164 insertions(+), 97 deletions(-) + +diff --git a/src/net/http/server.go b/src/net/http/server.go +index 8f63a90299..111adb0ecd 100644 +--- a/src/net/http/server.go ++++ b/src/net/http/server.go +@@ -1352,16 +1352,21 @@ func (cw *chunkWriter) writeHeader(p []byte) { +  + 	// If the client wanted a 100-continue but we never sent it to + 	// them (or, more strictly: we never finished reading their +-	// request body), don't reuse this connection because it's now +-	// in an unknown state: we might be sending this response at +-	// the same time the client is now sending its request body +-	// after a timeout.  (Some HTTP clients send Expect: +-	// 100-continue but knowing that some servers don't support +-	// it, the clients set a timer and send the body later anyway) +-	// If we haven't seen EOF, we can't skip over the unread body +-	// because we don't know if the next bytes on the wire will be +-	// the body-following-the-timer or the subsequent request. +-	// See Issue 11549. ++	// request body), don't reuse this connection. ++	// ++	// This behavior was first added on the theory that we don't know ++	// if the next bytes on the wire are going to be the remainder of ++	// the request body or the subsequent request (see issue 11549), ++	// but that's not correct: If we keep using the connection, ++	// the client is required to send the request body whether we ++	// asked for it or not. ++	// ++	// We probably do want to skip reusing the connection in most cases, ++	// however. If the client is offering a large request body that we ++	// don't intend to use, then it's better to close the connection ++	// than to read the body. For now, assume that if we're sending ++	// headers, the handler is done reading the body and we should ++	// drop the connection if we haven't seen EOF. + 	if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF.Load() { + 		w.closeAfterReply = true + 	} +diff --git a/src/net/http/transport.go b/src/net/http/transport.go +index c07352b018..30bce98736 100644 +--- a/src/net/http/transport.go ++++ b/src/net/http/transport.go +@@ -2313,17 +2313,12 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr + 			return + 		} + 		resCode := resp.StatusCode +-		if continueCh != nil { +-			if resCode == 100 { +-				if trace != nil && trace.Got100Continue != nil { +-					trace.Got100Continue() +-				} +-				continueCh <- struct{}{} +-				continueCh = nil +-			} else if resCode >= 200 { +-				close(continueCh) +-				continueCh = nil ++		if continueCh != nil && resCode == StatusContinue { ++			if trace != nil && trace.Got100Continue != nil { ++				trace.Got100Continue() + 			} ++			continueCh <- struct{}{} ++			continueCh = nil + 		} + 		is1xx := 100 <= resCode && resCode <= 199 + 		// treat 101 as a terminal status, see issue 26161 +@@ -2346,6 +2341,25 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr + 	if resp.isProtocolSwitch() { + 		resp.Body = newReadWriteCloserBody(pc.br, pc.conn) + 	} ++	if continueCh != nil { ++		// We send an "Expect: 100-continue" header, but the server ++		// responded with a terminal status and no 100 Continue. ++		// ++		// If we're going to keep using the connection, we need to send the request body. ++		// Tell writeLoop to skip sending the body if we're going to close the connection, ++		// or to send it otherwise. ++		// ++		// The case where we receive a 101 Switching Protocols response is a bit ++		// ambiguous, since we don't know what protocol we're switching to. ++		// Conceivably, it's one that doesn't need us to send the body. ++		// Given that we'll send the body if ExpectContinueTimeout expires, ++		// be consistent and always send it if we aren't closing the connection. ++		if resp.Close || rc.req.Close { ++			close(continueCh) // don't send the body; the connection will close ++		} else { ++			continueCh <- struct{}{} // send the body ++		} ++	} +  + 	resp.TLS = pc.tlsState + 	return +diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go +index 028fecc961..b8c930ab8f 100644 +--- a/src/net/http/transport_test.go ++++ b/src/net/http/transport_test.go +@@ -1135,94 +1135,142 @@ func testTransportGzip(t *testing.T, mode testMode) { + 	} + } +  +-// If a request has Expect:100-continue header, the request blocks sending body until the first response. +-// Premature consumption of the request body should not be occurred. +-func TestTransportExpect100Continue(t *testing.T) { +-	run(t, testTransportExpect100Continue, []testMode{http1Mode}) ++// A transport100Continue test exercises Transport behaviors when sending a ++// request with an Expect: 100-continue header. ++type transport100ContinueTest struct { ++	t *testing.T ++ ++	reqdone chan struct{} ++	resp    *Response ++	respErr error ++ ++	conn   net.Conn ++	reader *bufio.Reader + } +-func testTransportExpect100Continue(t *testing.T, mode testMode) { +-	ts := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) { +-		switch req.URL.Path { +-		case "/100": +-			// This endpoint implicitly responds 100 Continue and reads body. +-			if _, err := io.Copy(io.Discard, req.Body); err != nil { +-				t.Error("Failed to read Body", err) +-			} +-			rw.WriteHeader(StatusOK) +-		case "/200": +-			// Go 1.5 adds Connection: close header if the client expect +-			// continue but not entire request body is consumed. +-			rw.WriteHeader(StatusOK) +-		case "/500": +-			rw.WriteHeader(StatusInternalServerError) +-		case "/keepalive": +-			// This hijacked endpoint responds error without Connection:close. +-			_, bufrw, err := rw.(Hijacker).Hijack() +-			if err != nil { +-				log.Fatal(err) +-			} +-			bufrw.WriteString("HTTP/1.1 500 Internal Server Error\r\n") +-			bufrw.WriteString("Content-Length: 0\r\n\r\n") +-			bufrw.Flush() +-		case "/timeout": +-			// This endpoint tries to read body without 100 (Continue) response. +-			// After ExpectContinueTimeout, the reading will be started. +-			conn, bufrw, err := rw.(Hijacker).Hijack() +-			if err != nil { +-				log.Fatal(err) +-			} +-			if _, err := io.CopyN(io.Discard, bufrw, req.ContentLength); err != nil { +-				t.Error("Failed to read Body", err) +-			} +-			bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n") +-			bufrw.Flush() +-			conn.Close() +-		} +  +-	})).ts ++const transport100ContinueTestBody = "request body" +  +-	tests := []struct { +-		path   string +-		body   []byte +-		sent   int +-		status int +-	}{ +-		{path: "/100", body: []byte("hello"), sent: 5, status: 200},       // Got 100 followed by 200, entire body is sent. +-		{path: "/200", body: []byte("hello"), sent: 0, status: 200},       // Got 200 without 100. body isn't sent. +-		{path: "/500", body: []byte("hello"), sent: 0, status: 500},       // Got 500 without 100. body isn't sent. +-		{path: "/keepalive", body: []byte("hello"), sent: 0, status: 500}, // Although without Connection:close, body isn't sent. +-		{path: "/timeout", body: []byte("hello"), sent: 5, status: 200},   // Timeout exceeded and entire body is sent. ++// newTransport100ContinueTest creates a Transport and sends an Expect: 100-continue ++// request on it. ++func newTransport100ContinueTest(t *testing.T, timeout time.Duration) *transport100ContinueTest { ++	ln := newLocalListener(t) ++	defer ln.Close() ++ ++	test := &transport100ContinueTest{ ++		t:       t, ++		reqdone: make(chan struct{}), + 	} +  +-	c := ts.Client() +-	for i, v := range tests { +-		tr := &Transport{ +-			ExpectContinueTimeout: 2 * time.Second, +-		} +-		defer tr.CloseIdleConnections() +-		c.Transport = tr +-		body := bytes.NewReader(v.body) +-		req, err := NewRequest("PUT", ts.URL+v.path, body) +-		if err != nil { +-			t.Fatal(err) +-		} ++	tr := &Transport{ ++		ExpectContinueTimeout: timeout, ++	} ++	go func() { ++		defer close(test.reqdone) ++		body := strings.NewReader(transport100ContinueTestBody) ++		req, _ := NewRequest("PUT", "http://"+ln.Addr().String(), body) + 		req.Header.Set("Expect", "100-continue") +-		req.ContentLength = int64(len(v.body)) ++		req.ContentLength = int64(len(transport100ContinueTestBody)) ++		test.resp, test.respErr = tr.RoundTrip(req) ++		test.resp.Body.Close() ++	}() +  +-		resp, err := c.Do(req) +-		if err != nil { +-			t.Fatal(err) ++	c, err := ln.Accept() ++	if err != nil { ++		t.Fatalf("Accept: %v", err) ++	} ++	t.Cleanup(func() { ++		c.Close() ++	}) ++	br := bufio.NewReader(c) ++	_, err = ReadRequest(br) ++	if err != nil { ++		t.Fatalf("ReadRequest: %v", err) ++	} ++	test.conn = c ++	test.reader = br ++	t.Cleanup(func() { ++		<-test.reqdone ++		tr.CloseIdleConnections() ++		got, _ := io.ReadAll(test.reader) ++		if len(got) > 0 { ++			t.Fatalf("Transport sent unexpected bytes: %q", got) + 		} +-		resp.Body.Close() ++	}) +  +-		sent := len(v.body) - body.Len() +-		if v.status != resp.StatusCode { +-			t.Errorf("test %d: status code should be %d but got %d. (%s)", i, v.status, resp.StatusCode, v.path) +-		} +-		if v.sent != sent { +-			t.Errorf("test %d: sent body should be %d but sent %d. (%s)", i, v.sent, sent, v.path) ++	return test ++} ++ ++// respond sends response lines from the server to the transport. ++func (test *transport100ContinueTest) respond(lines ...string) { ++	for _, line := range lines { ++		if _, err := test.conn.Write([]byte(line + "\r\n")); err != nil { ++			test.t.Fatalf("Write: %v", err) + 		} + 	} ++	if _, err := test.conn.Write([]byte("\r\n")); err != nil { ++		test.t.Fatalf("Write: %v", err) ++	} ++} ++ ++// wantBodySent ensures the transport has sent the request body to the server. ++func (test *transport100ContinueTest) wantBodySent() { ++	got, err := io.ReadAll(io.LimitReader(test.reader, int64(len(transport100ContinueTestBody)))) ++	if err != nil { ++		test.t.Fatalf("unexpected error reading body: %v", err) ++	} ++	if got, want := string(got), transport100ContinueTestBody; got != want { ++		test.t.Fatalf("unexpected body: got %q, want %q", got, want) ++	} ++} ++ ++// wantRequestDone ensures the Transport.RoundTrip has completed with the expected status. ++func (test *transport100ContinueTest) wantRequestDone(want int) { ++	<-test.reqdone ++	if test.respErr != nil { ++		test.t.Fatalf("unexpected RoundTrip error: %v", test.respErr) ++	} ++	if got := test.resp.StatusCode; got != want { ++		test.t.Fatalf("unexpected response code: got %v, want %v", got, want) ++	} ++} ++ ++func TestTransportExpect100ContinueSent(t *testing.T) { ++	test := newTransport100ContinueTest(t, 1*time.Hour) ++	// Server sends a 100 Continue response, and the client sends the request body. ++	test.respond("HTTP/1.1 100 Continue") ++	test.wantBodySent() ++	test.respond("HTTP/1.1 200", "Content-Length: 0") ++	test.wantRequestDone(200) ++} ++ ++func TestTransportExpect100Continue200ResponseNoConnClose(t *testing.T) { ++	test := newTransport100ContinueTest(t, 1*time.Hour) ++	// No 100 Continue response, no Connection: close header. ++	test.respond("HTTP/1.1 200", "Content-Length: 0") ++	test.wantBodySent() ++	test.wantRequestDone(200) ++} ++ ++func TestTransportExpect100Continue200ResponseWithConnClose(t *testing.T) { ++	test := newTransport100ContinueTest(t, 1*time.Hour) ++	// No 100 Continue response, Connection: close header set. ++	test.respond("HTTP/1.1 200", "Connection: close", "Content-Length: 0") ++	test.wantRequestDone(200) ++} ++ ++func TestTransportExpect100Continue500ResponseNoConnClose(t *testing.T) { ++	test := newTransport100ContinueTest(t, 1*time.Hour) ++	// No 100 Continue response, no Connection: close header. ++	test.respond("HTTP/1.1 500", "Content-Length: 0") ++	test.wantBodySent() ++	test.wantRequestDone(500) ++} ++ ++func TestTransportExpect100Continue500ResponseTimeout(t *testing.T) { ++	test := newTransport100ContinueTest(t, 5*time.Millisecond) // short timeout ++	test.wantBodySent()                                        // after timeout ++	test.respond("HTTP/1.1 200", "Content-Length: 0") ++	test.wantRequestDone(200) + } +  + func TestSOCKS5Proxy(t *testing.T) { +--  +2.41.0 + diff --git a/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch b/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch new file mode 100644 index 0000000..e6db274 --- /dev/null +++ b/backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch @@ -0,0 +1,98 @@ +From 0574d64ad35b51eb770d6cb59b46c9b3d8540999 Mon Sep 17 00:00:00 2001 +From: Dmitri Shuralyov <dmitshur@golang.org> +Date: Fri, 12 Apr 2024 15:46:59 -0400 +Subject: [PATCH] [release-branch.go1.21] net/http: update bundled + golang.org/x/net/http2 + +Reference:https://go-review.googlesource.com/c/go/+/578357 +Conflict:NA +Pull in CL 578336: + +	ef58d90f http2: send correct LastStreamID in stream-caused GOAWAY + +For #66668. +Fixes #66697. + +Change-Id: I91fc8a67f21fadcb1801ff29d5e2b0453db89617 +Reviewed-on: https://go-review.googlesource.com/c/go/+/578357 +Reviewed-by: Carlos Amedee <carlos@golang.org> +Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +--- + src/net/http/h2_bundle.go | 22 +++++++++++++++------- + 1 file changed, 15 insertions(+), 7 deletions(-) + +diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go +index cd95f84269..5ad0c2819b 100644 +--- a/src/net/http/h2_bundle.go ++++ b/src/net/http/h2_bundle.go +@@ -1891,6 +1891,9 @@ func http2terminalReadFrameError(err error) bool { + // returned error is ErrFrameTooLarge. Other errors may be of type + // ConnectionError, StreamError, or anything else from the underlying + // reader. ++// ++// If ReadFrame returns an error and a non-nil Frame, the Frame's StreamID ++// indicates the stream responsible for the error. + func (fr *http2Framer) ReadFrame() (http2Frame, error) { + 	fr.errDetail = nil + 	if fr.lastFrame != nil { +@@ -2923,7 +2926,7 @@ func (fr *http2Framer) maxHeaderStringLen() int { + // readMetaFrame returns 0 or more CONTINUATION frames from fr and + // merge them into the provided hf and returns a MetaHeadersFrame + // with the decoded hpack values. +-func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFrame, error) { ++func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (http2Frame, error) { + 	if fr.AllowIllegalReads { + 		return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders") + 	} +@@ -2993,8 +2996,8 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr + 				log.Printf("http2: header list too large") + 			} + 			// It would be nice to send a RST_STREAM before sending the GOAWAY, +-			// but the struture of the server's frame writer makes this difficult. +-			return nil, http2ConnectionError(http2ErrCodeProtocol) ++			// but the structure of the server's frame writer makes this difficult. ++			return mh, http2ConnectionError(http2ErrCodeProtocol) + 		} +  + 		// Also close the connection after any CONTINUATION frame following an +@@ -3005,12 +3008,12 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr + 				log.Printf("http2: invalid header: %v", invalid) + 			} + 			// It would be nice to send a RST_STREAM before sending the GOAWAY, +-			// but the struture of the server's frame writer makes this difficult. +-			return nil, http2ConnectionError(http2ErrCodeProtocol) ++			// but the structure of the server's frame writer makes this difficult. ++			return mh, http2ConnectionError(http2ErrCodeProtocol) + 		} +  + 		if _, err := hdec.Write(frag); err != nil { +-			return nil, http2ConnectionError(http2ErrCodeCompression) ++			return mh, http2ConnectionError(http2ErrCodeCompression) + 		} +  + 		if hc.HeadersEnded() { +@@ -3027,7 +3030,7 @@ func (fr *http2Framer) readMetaFrame(hf *http2HeadersFrame) (*http2MetaHeadersFr + 	mh.http2HeadersFrame.invalidate() +  + 	if err := hdec.Close(); err != nil { +-		return nil, http2ConnectionError(http2ErrCodeCompression) ++		return mh, http2ConnectionError(http2ErrCodeCompression) + 	} + 	if invalid != nil { + 		fr.errDetail = invalid +@@ -5337,6 +5340,11 @@ func (sc *http2serverConn) processFrameFromReader(res http2readFrameResult) bool + 		sc.goAway(http2ErrCodeFlowControl) + 		return true + 	case http2ConnectionError: ++		if res.f != nil { ++			if id := res.f.Header().StreamID; id > sc.maxClientStreamID { ++				sc.maxClientStreamID = id ++			} ++		} + 		sc.logf("http2: server connection error from %v: %v", sc.conn.RemoteAddr(), ev) + 		sc.goAway(http2ErrCode(ev)) + 		return true // goAway will handle shutdown +--  +2.33.0 + diff --git a/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch b/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch new file mode 100644 index 0000000..80c9bbc --- /dev/null +++ b/backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch @@ -0,0 +1,143 @@ +From 131f773664fa2d0dbc870e11c388a3131a3a2029 Mon Sep 17 00:00:00 2001 +From: Keith Randall <khr@golang.org> +Date: Sun, 29 Oct 2023 21:00:29 -0700 +Subject: cmd/compile: handle constant pointer offsets in dead store elimination + +Conflict:NA +Reference:https://go-review.googlesource.com/c/go/+/538595 + +Update #63657 +Update #45573 + +Change-Id: I163c6038c13d974dc0ca9f02144472bc05331826 +Reviewed-on: https://go-review.googlesource.com/c/go/+/538595 +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: David Chase <drchase@google.com> +Reviewed-by: Keith Randall <khr@google.com> +--- + src/cmd/compile/internal/ssa/deadstore.go | 64 ++++++++++++++++++++--- + src/cmd/compile/internal/ssa/rewrite.go   |  6 +++ + 2 files changed, 62 insertions(+), 8 deletions(-) + +diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go +index 648b68af78b1..7656e45cb9d5 100644 +--- a/src/cmd/compile/internal/ssa/deadstore.go ++++ b/src/cmd/compile/internal/ssa/deadstore.go +@@ -73,9 +73,9 @@ func dse(f *Func) { + 		} +  + 		// Walk backwards looking for dead stores. Keep track of shadowed addresses. +-		// A "shadowed address" is a pointer and a size describing a memory region that +-		// is known to be written. We keep track of shadowed addresses in the shadowed +-		// map, mapping the ID of the address to the size of the shadowed region. ++		// A "shadowed address" is a pointer, offset, and size describing a memory region that ++		// is known to be written. We keep track of shadowed addresses in the shadowed map, ++		// mapping the ID of the address to a shadowRange where future writes will happen. + 		// Since we're walking backwards, writes to a shadowed region are useless, + 		// as they will be immediately overwritten. + 		shadowed.clear() +@@ -88,13 +88,20 @@ func dse(f *Func) { + 			shadowed.clear() + 		} + 		if v.Op == OpStore || v.Op == OpZero { ++			ptr := v.Args[0] ++			var off int64 ++			for ptr.Op == OpOffPtr { // Walk to base pointer ++				off += ptr.AuxInt ++				ptr = ptr.Args[0] ++			} + 			var sz int64 + 			if v.Op == OpStore { + 				sz = v.Aux.(*types.Type).Size() + 			} else { // OpZero + 				sz = v.AuxInt + 			} +-			if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz { ++			sr := shadowRange(shadowed.get(ptr.ID)) ++			if sr.contains(off, off+sz) { + 				// Modify the store/zero into a copy of the memory state, + 				// effectively eliding the store operation. + 				if v.Op == OpStore { +@@ -108,10 +115,8 @@ func dse(f *Func) { + 				v.AuxInt = 0 + 				v.Op = OpCopy + 			} else { +-				if sz > 0x7fffffff { // work around sparseMap's int32 value type +-					sz = 0x7fffffff +-				} +-				shadowed.set(v.Args[0].ID, int32(sz)) ++				// Extend shadowed region. ++				shadowed.set(ptr.ID, int32(sr.merge(off, off+sz))) + 			} + 		} + 		// walk to previous store +@@ -131,6 +136,49 @@ func dse(f *Func) { + 	} + } +  ++// A shadowRange encodes a set of byte offsets [lo():hi()] from ++// a given pointer that will be written to later in the block. ++// A zero shadowRange encodes an empty shadowed range (and so ++// does a -1 shadowRange, which is what sparsemap.get returns ++// on a failed lookup). ++type shadowRange int32 ++ ++func (sr shadowRange) lo() int64 { ++	return int64(sr & 0xffff) ++} ++func (sr shadowRange) hi() int64 { ++	return int64((sr >> 16) & 0xffff) ++} ++ ++// contains reports whether [lo:hi] is completely within sr. ++func (sr shadowRange) contains(lo, hi int64) bool { ++	return lo >= sr.lo() && hi <= sr.hi() ++} ++ ++// merge returns the union of sr and [lo:hi]. ++// merge is allowed to return something smaller than the union. ++func (sr shadowRange) merge(lo, hi int64) shadowRange { ++	if lo < 0 || hi > 0xffff { ++		// Ignore offsets that are too large or small. ++		return sr ++	} ++	if sr.lo() == sr.hi() { ++		// Old range is empty - use new one. ++		return shadowRange(lo + hi<<16) ++	} ++	if hi < sr.lo() || lo > sr.hi() { ++		// The two regions don't overlap or abut, so we would ++		// have to keep track of multiple disjoint ranges. ++		// Because we can only keep one, keep the larger one. ++		if sr.hi()-sr.lo() >= hi-lo { ++			return sr ++		} ++		return shadowRange(lo + hi<<16) ++	} ++	// Regions overlap or abut - compute the union. ++	return shadowRange(min(lo, sr.lo()) + max(hi, sr.hi())<<16) ++} ++ + // elimDeadAutosGeneric deletes autos that are never accessed. To achieve this + // we track the operations that the address of each auto reaches and if it only + // reaches stores then we delete all the stores. The other operations will then +diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go +index 43843bda5536..5c7ed16f12be 100644 +--- a/src/cmd/compile/internal/ssa/rewrite.go ++++ b/src/cmd/compile/internal/ssa/rewrite.go +@@ -1183,6 +1183,12 @@ func min(x, y int64) int64 { + 	} + 	return y + } ++func max(x, y int64) int64 { ++	if x > y { ++		return x ++	} ++	return y ++} +  + func isConstZero(v *Value) bool { + 	switch v.Op { +--  +2.33.0 + diff --git a/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch b/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch new file mode 100644 index 0000000..19223d4 --- /dev/null +++ b/backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch @@ -0,0 +1,650 @@ +From 8aa0b89560d65438d18fb8ed5ea90d7db2e18fa0 Mon Sep 17 00:00:00 2001 +From: Keith Randall <khr@golang.org> +Date: Wed, 25 Oct 2023 13:35:13 -0700 +Subject: [release-branch.go1.21] cmd/compile: ensure pointer arithmetic  + happens after the nil check + +Conflict:NA +Reference:https://go-review.googlesource.com/c/go/+/537775 + +Have nil checks return a pointer that is known non-nil. Users of +that pointer can use the result, ensuring that they are ordered +after the nil check itself. + +The order dependence goes away after scheduling, when we've fixed +an order. At that point we move uses back to the original pointer +so it doesn't change regalloc any. + +This prevents pointer arithmetic on nil from being spilled to the +stack and then observed by a stack scan. + +Fixes #63743 + +Change-Id: I1a5fa4f2e6d9000d672792b4f90dfc1b7b67f6ea +Reviewed-on: https://go-review.googlesource.com/c/go/+/537775 +Reviewed-by: David Chase <drchase@google.com> +LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> +Reviewed-by: Keith Randall <khr@google.com> +(cherry picked from commit 962ccbef91057f91518443b648e02fc3afe8c764) +Reviewed-on: https://go-review.googlesource.com/c/go/+/538717 +Auto-Submit: Heschi Kreinick <heschi@google.com> +Reviewed-by: Heschi Kreinick <heschi@google.com> +--- + .../compile/internal/ssa/_gen/generic.rules   | 14 ++-- + .../compile/internal/ssa/_gen/genericOps.go   |  2 +- + src/cmd/compile/internal/ssa/check.go         | 23 ++++++- + src/cmd/compile/internal/ssa/deadcode.go      |  7 +- + src/cmd/compile/internal/ssa/deadstore.go     |  2 +- + src/cmd/compile/internal/ssa/fuse.go          |  2 +- + src/cmd/compile/internal/ssa/fuse_test.go     |  2 +- + src/cmd/compile/internal/ssa/nilcheck.go      | 42 ++++++------ + src/cmd/compile/internal/ssa/opGen.go         |  7 +- + src/cmd/compile/internal/ssa/rewrite.go       |  3 + + .../compile/internal/ssa/rewritegeneric.go    | 67 ++++++++++--------- + src/cmd/compile/internal/ssa/schedule.go      | 18 ++++- + src/cmd/compile/internal/ssa/value.go         |  6 +- + src/cmd/compile/internal/ssagen/ssa.go        | 17 +++-- + test/fixedbugs/issue63657.go                  | 48 +++++++++++++ + 15 files changed, 179 insertions(+), 81 deletions(-) + create mode 100644 test/fixedbugs/issue63657.go + +diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules +index cdb346321e56..d3af465d0e0d 100644 +--- a/src/cmd/compile/internal/ssa/_gen/generic.rules ++++ b/src/cmd/compile/internal/ssa/_gen/generic.rules +@@ -981,7 +981,7 @@ +     (ConstNil <typ.Uintptr>) +     (ConstNil <typ.BytePtr>)) +  +-(NilCheck (GetG mem) mem) => mem ++(NilCheck ptr:(GetG mem) mem) => ptr +  + (If (Not cond) yes no) => (If cond no yes) + (If (ConstBool [c]) yes no) && c => (First yes no) +@@ -2055,19 +2055,19 @@ + 	&& isSameCall(call.Aux, "runtime.newobject") + 	=> mem +  +-(NilCheck (SelectN [0] call:(StaticLECall _ _)) _) ++(NilCheck ptr:(SelectN [0] call:(StaticLECall _ _)) _) + 	&& isSameCall(call.Aux, "runtime.newobject") + 	&& warnRule(fe.Debug_checknil(), v, "removed nil check") +-	=> (Invalid) ++	=> ptr +  +-(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _) ++(NilCheck ptr:(OffPtr (SelectN [0] call:(StaticLECall _ _))) _) + 	&& isSameCall(call.Aux, "runtime.newobject") + 	&& warnRule(fe.Debug_checknil(), v, "removed nil check") +-	=> (Invalid) ++	=> ptr +  + // Addresses of globals are always non-nil. +-(NilCheck          (Addr {_} (SB))    _) => (Invalid) +-(NilCheck (Convert (Addr {_} (SB)) _) _) => (Invalid) ++(NilCheck          ptr:(Addr {_} (SB))    _) => ptr ++(NilCheck ptr:(Convert (Addr {_} (SB)) _) _) => ptr +  + // for late-expanded calls, recognize memequal applied to a single constant byte + // Support is limited by 1, 2, 4, 8 byte sizes +diff --git a/src/cmd/compile/internal/ssa/_gen/genericOps.go b/src/cmd/compile/internal/ssa/_gen/genericOps.go +index 53ff57f6b12e..aa5fb0e03e66 100644 +--- a/src/cmd/compile/internal/ssa/_gen/genericOps.go ++++ b/src/cmd/compile/internal/ssa/_gen/genericOps.go +@@ -471,7 +471,7 @@ var genericOps = []opData{ + 	{name: "IsNonNil", argLength: 1, typ: "Bool"},        // arg0 != nil + 	{name: "IsInBounds", argLength: 2, typ: "Bool"},      // 0 <= arg0 < arg1. arg1 is guaranteed >= 0. + 	{name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0. +-	{name: "NilCheck", argLength: 2, typ: "Void"},        // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns void. ++	{name: "NilCheck", argLength: 2, nilCheck: true},     // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns the ptr unmodified. +  + 	// Pseudo-ops + 	{name: "GetG", argLength: 1, zeroWidth: true}, // runtime.getg() (read g pointer). arg0=mem +diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go +index f34b9074197b..bbfdaceaad90 100644 +--- a/src/cmd/compile/internal/ssa/check.go ++++ b/src/cmd/compile/internal/ssa/check.go +@@ -317,7 +317,28 @@ func checkFunc(f *Func) { + 				if !v.Aux.(*ir.Name).Type().HasPointers() { + 					f.Fatalf("vardef must have pointer type %s", v.Aux.(*ir.Name).Type().String()) + 				} +- ++			case OpNilCheck: ++				// nil checks have pointer type before scheduling, and ++				// void type after scheduling. ++				if f.scheduled { ++					if v.Uses != 0 { ++						f.Fatalf("nilcheck must have 0 uses %s", v.Uses) ++					} ++					if !v.Type.IsVoid() { ++						f.Fatalf("nilcheck must have void type %s", v.Type.String()) ++					} ++				} else { ++					if !v.Type.IsPtrShaped() && !v.Type.IsUintptr() { ++						f.Fatalf("nilcheck must have pointer type %s", v.Type.String()) ++					} ++				} ++				if !v.Args[0].Type.IsPtrShaped() && !v.Args[0].Type.IsUintptr() { ++					f.Fatalf("nilcheck must have argument of pointer type %s", v.Args[0].Type.String()) ++				} ++				if !v.Args[1].Type.IsMemory() { ++					f.Fatalf("bad arg 1 type to %s: want mem, have %s", ++						v.Op, v.Args[1].Type.String()) ++				} + 			} +  + 			// TODO: check for cycles in values +diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go +index 52cc7f2ca74d..ae9fd2ef2426 100644 +--- a/src/cmd/compile/internal/ssa/deadcode.go ++++ b/src/cmd/compile/internal/ssa/deadcode.go +@@ -110,16 +110,15 @@ func liveValues(f *Func, reachable []bool) (live []bool, liveOrderStmts []*Value + 			} + 		} + 		for _, v := range b.Values { +-			if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects) && !live[v.ID] { ++			if (opcodeTable[v.Op].call || opcodeTable[v.Op].hasSideEffects || opcodeTable[v.Op].nilCheck) && !live[v.ID] { + 				live[v.ID] = true + 				q = append(q, v) + 				if v.Pos.IsStmt() != src.PosNotStmt { + 					liveOrderStmts = append(liveOrderStmts, v) + 				} + 			} +-			if v.Type.IsVoid() && !live[v.ID] { +-				// The only Void ops are nil checks and inline marks.  We must keep these. +-				if v.Op == OpInlMark && !liveInlIdx[int(v.AuxInt)] { ++			if v.Op == OpInlMark { ++				if !liveInlIdx[int(v.AuxInt)] { + 					// We don't need marks for bodies that + 					// have been completely optimized away. + 					// TODO: save marks only for bodies which +diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go +index 7656e45cb9d5..cb3427103c50 100644 +--- a/src/cmd/compile/internal/ssa/deadstore.go ++++ b/src/cmd/compile/internal/ssa/deadstore.go +@@ -249,7 +249,7 @@ func elimDeadAutosGeneric(f *Func) { + 		} +  + 		if v.Uses == 0 && v.Op != OpNilCheck && !v.Op.IsCall() && !v.Op.HasSideEffects() || len(args) == 0 { +-			// Nil check has no use, but we need to keep it. ++			// We need to keep nil checks even if they have no use. + 			// Also keep calls and values that have side effects. + 			return + 		} +diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go +index 6d3fb7078059..68defde7b4b9 100644 +--- a/src/cmd/compile/internal/ssa/fuse.go ++++ b/src/cmd/compile/internal/ssa/fuse.go +@@ -169,7 +169,7 @@ func fuseBlockIf(b *Block) bool { + // There may be false positives. + func isEmpty(b *Block) bool { + 	for _, v := range b.Values { +-		if v.Uses > 0 || v.Op.IsCall() || v.Op.HasSideEffects() || v.Type.IsVoid() { ++		if v.Uses > 0 || v.Op.IsCall() || v.Op.HasSideEffects() || v.Type.IsVoid() || opcodeTable[v.Op].nilCheck { + 			return false + 		} + 	} +diff --git a/src/cmd/compile/internal/ssa/fuse_test.go b/src/cmd/compile/internal/ssa/fuse_test.go +index fa7921a18f6f..2f89938d1d92 100644 +--- a/src/cmd/compile/internal/ssa/fuse_test.go ++++ b/src/cmd/compile/internal/ssa/fuse_test.go +@@ -254,7 +254,7 @@ func TestFuseSideEffects(t *testing.T) { + 			Valu("p", OpArg, c.config.Types.IntPtr, 0, nil), + 			If("c1", "z0", "exit")), + 		Bloc("z0", +-			Valu("nilcheck", OpNilCheck, types.TypeVoid, 0, nil, "p", "mem"), ++			Valu("nilcheck", OpNilCheck, c.config.Types.IntPtr, 0, nil, "p", "mem"), + 			Goto("exit")), + 		Bloc("exit", + 			Exit("mem"), +diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go +index 4f797a473f71..c69cd8c32ed3 100644 +--- a/src/cmd/compile/internal/ssa/nilcheck.go ++++ b/src/cmd/compile/internal/ssa/nilcheck.go +@@ -38,11 +38,14 @@ func nilcheckelim(f *Func) { + 	work := make([]bp, 0, 256) + 	work = append(work, bp{block: f.Entry}) +  +-	// map from value ID to bool indicating if value is known to be non-nil +-	// in the current dominator path being walked. This slice is updated by ++	// map from value ID to known non-nil version of that value ID ++	// (in the current dominator path being walked). This slice is updated by + 	// walkStates to maintain the known non-nil values. +-	nonNilValues := f.Cache.allocBoolSlice(f.NumValues()) +-	defer f.Cache.freeBoolSlice(nonNilValues) ++	// If there is extrinsic information about non-nil-ness, this map ++	// points a value to itself. If a value is known non-nil because we ++	// already did a nil check on it, it points to the nil check operation. ++	nonNilValues := f.Cache.allocValueSlice(f.NumValues()) ++	defer f.Cache.freeValueSlice(nonNilValues) +  + 	// make an initial pass identifying any non-nil values + 	for _, b := range f.Blocks { +@@ -54,7 +57,7 @@ func nilcheckelim(f *Func) { + 			// We assume that SlicePtr is non-nil because we do a bounds check + 			// before the slice access (and all cap>0 slices have a non-nil ptr). See #30366. + 			if v.Op == OpAddr || v.Op == OpLocalAddr || v.Op == OpAddPtr || v.Op == OpOffPtr || v.Op == OpAdd32 || v.Op == OpAdd64 || v.Op == OpSub32 || v.Op == OpSub64 || v.Op == OpSlicePtr { +-				nonNilValues[v.ID] = true ++				nonNilValues[v.ID] = v + 			} + 		} + 	} +@@ -68,16 +71,16 @@ func nilcheckelim(f *Func) { + 				if v.Op == OpPhi { + 					argsNonNil := true + 					for _, a := range v.Args { +-						if !nonNilValues[a.ID] { ++						if nonNilValues[a.ID] == nil { + 							argsNonNil = false + 							break + 						} + 					} + 					if argsNonNil { +-						if !nonNilValues[v.ID] { ++						if nonNilValues[v.ID] == nil { + 							changed = true + 						} +-						nonNilValues[v.ID] = true ++						nonNilValues[v.ID] = v + 					} + 				} + 			} +@@ -103,8 +106,8 @@ func nilcheckelim(f *Func) { + 			if len(b.Preds) == 1 { + 				p := b.Preds[0].b + 				if p.Kind == BlockIf && p.Controls[0].Op == OpIsNonNil && p.Succs[0].b == b { +-					if ptr := p.Controls[0].Args[0]; !nonNilValues[ptr.ID] { +-						nonNilValues[ptr.ID] = true ++					if ptr := p.Controls[0].Args[0]; nonNilValues[ptr.ID] == nil { ++						nonNilValues[ptr.ID] = ptr + 						work = append(work, bp{op: ClearPtr, ptr: ptr}) + 					} + 				} +@@ -117,14 +120,11 @@ func nilcheckelim(f *Func) { + 			pendingLines.clear() +  + 			// Next, process values in the block. +-			i := 0 + 			for _, v := range b.Values { +-				b.Values[i] = v +-				i++ + 				switch v.Op { + 				case OpIsNonNil: + 					ptr := v.Args[0] +-					if nonNilValues[ptr.ID] { ++					if nonNilValues[ptr.ID] != nil { + 						if v.Pos.IsStmt() == src.PosIsStmt { // Boolean true is a terrible statement boundary. + 							pendingLines.add(v.Pos) + 							v.Pos = v.Pos.WithNotStmt() +@@ -135,7 +135,7 @@ func nilcheckelim(f *Func) { + 					} + 				case OpNilCheck: + 					ptr := v.Args[0] +-					if nonNilValues[ptr.ID] { ++					if nilCheck := nonNilValues[ptr.ID]; nilCheck != nil { + 						// This is a redundant implicit nil check. + 						// Logging in the style of the former compiler -- and omit line 1, + 						// which is usually in generated code. +@@ -145,14 +145,13 @@ func nilcheckelim(f *Func) { + 						if v.Pos.IsStmt() == src.PosIsStmt { // About to lose a statement boundary + 							pendingLines.add(v.Pos) + 						} +-						v.reset(OpUnknown) +-						f.freeValue(v) +-						i-- ++						v.Op = OpCopy ++						v.SetArgs1(nilCheck) + 						continue + 					} + 					// Record the fact that we know ptr is non nil, and remember to + 					// undo that information when this dominator subtree is done. +-					nonNilValues[ptr.ID] = true ++					nonNilValues[ptr.ID] = v + 					work = append(work, bp{op: ClearPtr, ptr: ptr}) + 					fallthrough // a non-eliminated nil check might be a good place for a statement boundary. + 				default: +@@ -163,7 +162,7 @@ func nilcheckelim(f *Func) { + 				} + 			} + 			// This reduces the lost statement count in "go" by 5 (out of 500 total). +-			for j := 0; j < i; j++ { // is this an ordering problem? ++			for j := range b.Values { // is this an ordering problem? + 				v := b.Values[j] + 				if v.Pos.IsStmt() != src.PosNotStmt && !isPoorStatementOp(v.Op) && pendingLines.contains(v.Pos) { + 					v.Pos = v.Pos.WithIsStmt() +@@ -174,7 +173,6 @@ func nilcheckelim(f *Func) { + 				b.Pos = b.Pos.WithIsStmt() + 				pendingLines.remove(b.Pos) + 			} +-			b.truncateValues(i) +  + 			// Add all dominated blocks to the work list. + 			for w := sdom[node.block.ID].child; w != nil; w = sdom[w.ID].sibling { +@@ -182,7 +180,7 @@ func nilcheckelim(f *Func) { + 			} +  + 		case ClearPtr: +-			nonNilValues[node.ptr.ID] = false ++			nonNilValues[node.ptr.ID] = nil + 			continue + 		} + 	} +diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go +index 1480fcf45bfd..e7caf9050c15 100644 +--- a/src/cmd/compile/internal/ssa/opGen.go ++++ b/src/cmd/compile/internal/ssa/opGen.go +@@ -39373,9 +39373,10 @@ var opcodeTable = [...]opInfo{ + 		generic: true, + 	}, + 	{ +-		name:    "NilCheck", +-		argLen:  2, +-		generic: true, ++		name:     "NilCheck", ++		argLen:   2, ++		nilCheck: true, ++		generic:  true, + 	}, + 	{ + 		name:      "GetG", +diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go +index 5c7ed16f12be..1cfdc3e10d10 100644 +--- a/src/cmd/compile/internal/ssa/rewrite.go ++++ b/src/cmd/compile/internal/ssa/rewrite.go +@@ -859,6 +859,9 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool { + 			offset += base.AuxInt + 			base = base.Args[0] + 		} ++		if opcodeTable[base.Op].nilCheck { ++			base = base.Args[0] ++		} + 		return base, offset + 	} + 	p1, off1 := baseAndOffset(p1) +diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go +index e5bd8bc36f7d..574ac7a1a3ab 100644 +--- a/src/cmd/compile/internal/ssa/rewritegeneric.go ++++ b/src/cmd/compile/internal/ssa/rewritegeneric.go +@@ -18967,79 +18967,84 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool { + 	v_0 := v.Args[0] + 	b := v.Block + 	fe := b.Func.fe +-	// match: (NilCheck (GetG mem) mem) +-	// result: mem ++	// match: (NilCheck ptr:(GetG mem) mem) ++	// result: ptr + 	for { +-		if v_0.Op != OpGetG { ++		ptr := v_0 ++		if ptr.Op != OpGetG { + 			break + 		} +-		mem := v_0.Args[0] ++		mem := ptr.Args[0] + 		if mem != v_1 { + 			break + 		} +-		v.copyOf(mem) ++		v.copyOf(ptr) + 		return true + 	} +-	// match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) _) ++	// match: (NilCheck ptr:(SelectN [0] call:(StaticLECall _ _)) _) + 	// cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") +-	// result: (Invalid) ++	// result: ptr + 	for { +-		if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 { ++		ptr := v_0 ++		if ptr.Op != OpSelectN || auxIntToInt64(ptr.AuxInt) != 0 { + 			break + 		} +-		call := v_0.Args[0] ++		call := ptr.Args[0] + 		if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { + 			break + 		} +-		v.reset(OpInvalid) ++		v.copyOf(ptr) + 		return true + 	} +-	// match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) _) ++	// match: (NilCheck ptr:(OffPtr (SelectN [0] call:(StaticLECall _ _))) _) + 	// cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check") +-	// result: (Invalid) ++	// result: ptr + 	for { +-		if v_0.Op != OpOffPtr { ++		ptr := v_0 ++		if ptr.Op != OpOffPtr { + 			break + 		} +-		v_0_0 := v_0.Args[0] +-		if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 { ++		ptr_0 := ptr.Args[0] ++		if ptr_0.Op != OpSelectN || auxIntToInt64(ptr_0.AuxInt) != 0 { + 			break + 		} +-		call := v_0_0.Args[0] ++		call := ptr_0.Args[0] + 		if call.Op != OpStaticLECall || len(call.Args) != 2 || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) { + 			break + 		} +-		v.reset(OpInvalid) ++		v.copyOf(ptr) + 		return true + 	} +-	// match: (NilCheck (Addr {_} (SB)) _) +-	// result: (Invalid) ++	// match: (NilCheck ptr:(Addr {_} (SB)) _) ++	// result: ptr + 	for { +-		if v_0.Op != OpAddr { ++		ptr := v_0 ++		if ptr.Op != OpAddr { + 			break + 		} +-		v_0_0 := v_0.Args[0] +-		if v_0_0.Op != OpSB { ++		ptr_0 := ptr.Args[0] ++		if ptr_0.Op != OpSB { + 			break + 		} +-		v.reset(OpInvalid) ++		v.copyOf(ptr) + 		return true + 	} +-	// match: (NilCheck (Convert (Addr {_} (SB)) _) _) +-	// result: (Invalid) ++	// match: (NilCheck ptr:(Convert (Addr {_} (SB)) _) _) ++	// result: ptr + 	for { +-		if v_0.Op != OpConvert { ++		ptr := v_0 ++		if ptr.Op != OpConvert { + 			break + 		} +-		v_0_0 := v_0.Args[0] +-		if v_0_0.Op != OpAddr { ++		ptr_0 := ptr.Args[0] ++		if ptr_0.Op != OpAddr { + 			break + 		} +-		v_0_0_0 := v_0_0.Args[0] +-		if v_0_0_0.Op != OpSB { ++		ptr_0_0 := ptr_0.Args[0] ++		if ptr_0_0.Op != OpSB { + 			break + 		} +-		v.reset(OpInvalid) ++		v.copyOf(ptr) + 		return true + 	} + 	return false +diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go +index 19b98cc4b83b..0a7425c01729 100644 +--- a/src/cmd/compile/internal/ssa/schedule.go ++++ b/src/cmd/compile/internal/ssa/schedule.go +@@ -312,14 +312,21 @@ func schedule(f *Func) { + 	} +  + 	// Remove SPanchored now that we've scheduled. ++	// Also unlink nil checks now that ordering is assured ++	// between the nil check and the uses of the nil-checked pointer. + 	for _, b := range f.Blocks { + 		for _, v := range b.Values { + 			for i, a := range v.Args { +-				if a.Op == OpSPanchored { ++				if a.Op == OpSPanchored || opcodeTable[a.Op].nilCheck { + 					v.SetArg(i, a.Args[0]) + 				} + 			} + 		} ++		for i, c := range b.ControlValues() { ++			if c.Op == OpSPanchored || opcodeTable[c.Op].nilCheck { ++				b.ReplaceControl(i, c.Args[0]) ++			} ++		} + 	} + 	for _, b := range f.Blocks { + 		i := 0 +@@ -332,6 +339,15 @@ func schedule(f *Func) { + 				v.resetArgs() + 				f.freeValue(v) + 			} else { ++				if opcodeTable[v.Op].nilCheck { ++					if v.Uses != 0 { ++						base.Fatalf("nilcheck still has %d uses", v.Uses) ++					} ++					// We can't delete the nil check, but we mark ++					// it as having void type so regalloc won't ++					// try to allocate a register for it. ++					v.Type = types.TypeVoid ++				} + 				b.Values[i] = v + 				i++ + 			} +diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go +index e89024b3c665..9b52da1c58a9 100644 +--- a/src/cmd/compile/internal/ssa/value.go ++++ b/src/cmd/compile/internal/ssa/value.go +@@ -552,7 +552,11 @@ func (v *Value) LackingPos() bool { + // if its use count drops to 0. + func (v *Value) removeable() bool { + 	if v.Type.IsVoid() { +-		// Void ops, like nil pointer checks, must stay. ++		// Void ops (inline marks), must stay. ++		return false ++	} ++	if opcodeTable[v.Op].nilCheck { ++		// Nil pointer checks must stay. + 		return false + 	} + 	if v.Type.IsMemory() { +diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go +index 597a196ba8c4..e994577c641d 100644 +--- a/src/cmd/compile/internal/ssagen/ssa.go ++++ b/src/cmd/compile/internal/ssagen/ssa.go +@@ -1991,7 +1991,8 @@ func (s *state) stmt(n ir.Node) { + 	case ir.OCHECKNIL: + 		n := n.(*ir.UnaryExpr) + 		p := s.expr(n.X) +-		s.nilCheck(p) ++		_ = s.nilCheck(p) ++		// TODO: check that throwing away the nilcheck result is ok. +  + 	case ir.OINLMARK: + 		n := n.(*ir.InlineMarkStmt) +@@ -5621,18 +5622,20 @@ func (s *state) exprPtr(n ir.Node, bounded bool, lineno src.XPos) *ssa.Value { + 		} + 		return p + 	} +-	s.nilCheck(p) ++	p = s.nilCheck(p) + 	return p + } +  + // nilCheck generates nil pointer checking code. + // Used only for automatically inserted nil checks, + // not for user code like 'x != nil'. +-func (s *state) nilCheck(ptr *ssa.Value) { ++// Returns a "definitely not nil" copy of x to ensure proper ordering ++// of the uses of the post-nilcheck pointer. ++func (s *state) nilCheck(ptr *ssa.Value) *ssa.Value { + 	if base.Debug.DisableNil != 0 || s.curfn.NilCheckDisabled() { +-		return ++		return ptr + 	} +-	s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem()) ++	return s.newValue2(ssa.OpNilCheck, ptr.Type, ptr, s.mem()) + } +  + // boundsCheck generates bounds checking code. Checks if 0 <= idx <[=] len, branches to exit if not. +@@ -5984,8 +5987,8 @@ func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) + 		if !t.Elem().IsArray() { + 			s.Fatalf("bad ptr to array in slice %v\n", t) + 		} +-		s.nilCheck(v) +-		ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), v) ++		nv := s.nilCheck(v) ++		ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), nv) + 		len = s.constInt(types.Types[types.TINT], t.Elem().NumElem()) + 		cap = len + 	default: +diff --git a/test/fixedbugs/issue63657.go b/test/fixedbugs/issue63657.go +new file mode 100644 +index 000000000000..e32a4a34fbb6 +--- /dev/null ++++ b/test/fixedbugs/issue63657.go +@@ -0,0 +1,48 @@ ++// run ++ ++// Copyright 2023 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++// Make sure address calculations don't float up before ++// the corresponding nil check. ++ ++package main ++ ++type T struct { ++	a, b int ++} ++ ++//go:noinline ++func f(x *T, p *bool, n int) { ++	*p = n != 0 ++	useStack(1000) ++	g(&x.b) ++} ++ ++//go:noinline ++func g(p *int) { ++} ++ ++func useStack(n int) { ++	if n == 0 { ++		return ++	} ++	useStack(n - 1) ++} ++ ++func main() { ++	mustPanic(func() { ++		var b bool ++		f(nil, &b, 3) ++	}) ++} ++ ++func mustPanic(f func()) { ++	defer func() { ++		if recover() == nil { ++			panic("expected panic, got nil") ++		} ++	}() ++	f() ++} +--  +2.33.0 + diff --git a/golang.spec b/golang.spec new file mode 100644 index 0000000..2af841f --- /dev/null +++ b/golang.spec @@ -0,0 +1,444 @@ +%global debug_package %{nil} +%global _binaries_in_noarch_packages_terminate_build 0 +%global golibdir %{_libdir}/golang +%global goroot /usr/lib/%{name} +%global go_api 1.20 +%global go_version 1.20 +%global __spec_install_post /usr/lib/rpm/check-rpaths /usr/lib/rpm/check-buildroot /usr/lib/rpm/brp-compress +%global __requires_exclude_from ^(%{_datadir}|/usr/lib)/%{name}/(doc|src)/.*$ +%global __strip /bin/true +%global vendor %{?_vendor:%{_vendor}}%{!?_vendor:openEuler} +%define _use_internal_dependency_generator 0 +%define __find_requires %{nil} + +%bcond_with bootstrap +%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le +%bcond_without ignore_tests +%else +%bcond_with ignore_tests +%endif + +%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le +%global external_linker 1 +%else +%global external_linker 0 +%endif + +%ifarch x86_64 aarch64 riscv64 loongarch64 ppc64le +%global cgo_enabled 1 +%else +%global cgo_enabled 0 +%endif + +%if %{with bootstrap} +%global golang_bootstrap 0 +%else +%global golang_bootstrap 1 +%endif + +%if %{with ignore_tests} +%global fail_on_tests 0 +%else +%global fail_on_tests 1 +%endif + +%global shared 0 + +# Pre build std lib with -race enabled +# Disabled due to 1.20 new cache usage, see 1.20 upstream release notes +%global race 0 + +%ifarch x86_64 +%global gohostarch amd64 +%endif +%ifarch aarch64 +%global gohostarch arm64 +%endif +%ifarch riscv64 +%global gohostarch riscv64 +%endif +%ifarch ppc64le +%global gohostarch ppc64le +%endif +%ifarch loongarch64 +%global gohostarch loong64 +%endif + +Name:           golang +Version:        1.21.4 +Release:        17 +Summary:        The Go Programming Language +License:        BSD and Public Domain +URL:            https://golang.org/ +Source0:        https://dl.google.com/go/go%{version}.src.tar.gz + +%if !%{golang_bootstrap} +BuildRequires:  gcc-go >= 5 +%else +BuildRequires:  golang > 1.4 +%endif +BuildRequires:  hostname +# for tests +BuildRequires:  pcre-devel, glibc-static, perl-interpreter, procps-ng + +Provides:       go = %{version}-%{release} +Requires:       %{name}-devel = %{version}-%{release} + +Obsoletes:      %{name}-pkg-bin-linux-386 < 1.4.99 +Obsoletes:      %{name}-pkg-bin-linux-amd64 < 1.4.99 +Obsoletes:      %{name}-pkg-bin-linux-arm < 1.4.99 +Obsoletes:      %{name}-pkg-linux-386 < 1.4.99 +Obsoletes:      %{name}-pkg-linux-amd64 < 1.4.99 +Obsoletes:      %{name}-pkg-linux-arm < 1.4.99 +Obsoletes:      %{name}-vet < 0-12.1 +Obsoletes:      %{name}-cover < 0-12.1 + +Requires(post): %{_sbindir}/update-alternatives +Requires(postun): %{_sbindir}/update-alternatives +Recommends: glibc gcc git subversion + +# Bundled/Vendored provides generated by bundled-deps.sh based on the in tree module data +# - in version filed substituted with . per versioning guidelines +Provides: bundled(golang(github.com/google/pprof)) = 0.0.0.20221118152302.e6195bd50e26 +Provides: bundled(golang(github.com/ianlancetaylor/demangle)) = 0.0.0.20220319035150.800ac71e25c2 +Provides: bundled(golang(golang.org/x/arch)) = 0.4.0 +Provides: bundled(golang(golang.org/x/crypto)) = 0.11.1.0.20230711161743.2e82bdd1719d +Provides: bundled(golang(golang.org/x/mod)) = 0.12.0 +Provides: bundled(golang(golang.org/x/net)) = 0.12.1.0.20231027154334.5ca955b1789c +Provides: bundled(golang(golang.org/x/sync)) = 0.3.0 +Provides: bundled(golang(golang.org/x/sys)) = 0.10.0 +Provides: bundled(golang(golang.org/x/term)) = 0.10.0 +Provides: bundled(golang(golang.org/x/text)) = 0.11.0 +Provides: bundled(golang(golang.org/x/tools)) = 0.11.1.0.20230712164437.1ca21856af7b + +Provides:       %{name}-bin = %{version}-%{release} +Obsoletes:      %{name}-bin +Obsoletes:      %{name}-shared +Obsoletes:      %{name}-docs +Obsoletes:      %{name}-data < 1.1.1-4 +Obsoletes:      %{name}-vim < 1.4 +Obsoletes:      emacs-%{name} < 1.4 +Requires:       %{vendor}-rpm-config + +Patch6001:	backport-0001-release-branch.go1.21-crypto-x509-make-sure-pub-key-.patch +Patch6002:	backport-0002-release-branch.go1.21-html-template-escape-additiona.patch +Patch6003:	backport-0003-release-branch.go1.21-net-textproto-mime-multipart-a.patch +Patch6004:	backport-0004-release-branch.go1.21-net-http-net-http-cookiejar-av.patch +Patch6005:	backport-0005-release-branch.go1.21-net-mail-properly-handle-speci.patch +Patch6006:	backport-0006-Backport-net-http-update-bundled-golang.org-x-net-ht.patch +Patch6007:	backport-0007-Backport-cmd-go-disallow-lto_library-in-LDFLAGS.patch + +Patch6008:	backport-0008-release-branch.go1.21-net-netip-check-if-address-is-v6.patch +Patch6009:	backport-0009-Backport-cmd-go-internal-vcs-error-out-if-the-reques.patch +Patch6010:	backport-0010-release-branch.go1.21-net-http-limit-chunked-data-ov.patch +Patch6011:	backport-0011-Backport-archive-zip-treat-truncated-EOCDR-comment-a.patch +Patch6012:	backport-0012-net-http-send-body-or-close-connection-on-expect-100.patch +Patch6013:	backport-0013-release-branch.go1.21-net-http-update-bundled-golang.patch +Patch6014:	backport-0014-cmd-compile-handle-constant-pointer-offsets-in-dead-.patch +Patch6015:	backport-0015-release-branch.go1.21-cmd-compile-ensure-pointer-ari.patch + +ExclusiveArch:  %{golang_arches} + +%description +%{summary}. + +%package       help +Summary:       Golang compiler helps and manual docs +Requires:      %{name} = %{version}-%{release} +BuildArch:     noarch +Provides:      %{name}-docs = %{version}-%{release} +Obsoletes:     %{name}-docs < %{version}-%{release} +Provides:      %{name}-shared = %{version}-%{release} +Obsoletes:     %{name}-shared < %{version}-%{release} + +%description   help +%{summary}. + +%package       devel +Summary:       Golang compiler devel +BuildArch:     noarch +Requires:      %{name} = %{version}-%{release} +Provides:      %{name}-src  = %{version}-%{release} +Obsoletes:     %{name}-src < %{version}-%{release} +Provides:      %{name}-tests = %{version}-%{release} +Obsoletes:     %{name}-tests < %{version}-%{release} +Provides:      %{name}-misc = %{version}-%{release} +Obsoletes:     %{name}-misc < %{version}-%{release} +Obsoletes:     %{name}-race = %{version}-%{release} + +%description   devel +%{summary}. + +# Workaround old RPM bug of symlink-replaced-with-dir failure +%pretrans -p <lua> +for _,d in pairs({"api", "doc", "include", "lib", "src"}) do +  path = "%{goroot}/" .. d +  if posix.stat(path, "type") == "link" then +    os.remove(path) +    posix.mkdir(path) +  end +end + +%prep +%autosetup -n go -p1 + +%build +uname -a +cat /proc/cpuinfo +cat /proc/meminfo + +%if !%{golang_bootstrap} +export GOROOT_BOOTSTRAP=/ +%else +export GOROOT_BOOTSTRAP=%{goroot} +%endif + +export GOROOT_FINAL=%{goroot} +export GOHOSTOS=linux +export GOHOSTARCH=%{gohostarch} + +pushd src +export CFLAGS="$RPM_OPT_FLAGS" +export LDFLAGS="$RPM_LD_FLAGS" +export CC="gcc" +export CC_FOR_TARGET="gcc" +export GOOS=linux +export GOARCH=%{gohostarch} +%if !%{external_linker} +export GO_LDFLAGS="-linkmode internal" +%endif +%if !%{cgo_enabled} +export CGO_ENABLED=0 +%endif + +%ifarch aarch64 +export GO_LDFLAGS="-s -w" +%endif + +./make.bash --no-clean -v +popd + +%if %{shared} +GOROOT=$(pwd) PATH=$(pwd)/bin:$PATH go install -buildmode=shared -v -x std +%endif + +%if %{race} +GOROOT=$(pwd) PATH=$(pwd)/bin:$PATH go install -race -v -x std +%endif + +%install +rm -rf %{buildroot} +rm -rf pkg/obj/go-build/* + +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{goroot} + +cp -apv api bin doc lib pkg src misc test go.env VERSION \ +   %{buildroot}%{goroot} + +# bz1099206 +find %{buildroot}%{goroot}/src -exec touch -r %{buildroot}%{goroot}/VERSION "{}" \; +# and level out all the built archives +touch %{buildroot}%{goroot}/pkg +find %{buildroot}%{goroot}/pkg -exec touch -r %{buildroot}%{goroot}/pkg "{}" \; +# generate the spec file ownership of this source tree and packages +cwd=$(pwd) +src_list=$cwd/go-src.list +pkg_list=$cwd/go-pkg.list +shared_list=$cwd/go-shared.list +race_list=$cwd/go-race.list +misc_list=$cwd/go-misc.list +docs_list=$cwd/go-docs.list +tests_list=$cwd/go-tests.list +rm -f $src_list $pkg_list $docs_list $misc_list $tests_list $shared_list $race_list +touch $src_list $pkg_list $docs_list $misc_list $tests_list $shared_list $race_list +pushd %{buildroot}%{goroot} +    find src/ -type d -a \( ! -name testdata -a ! -ipath '*/testdata/*' \) -printf '%%%dir %{goroot}/%p\n' >> $src_list +    find src/ ! -type d -a \( ! -ipath '*/testdata/*' -a ! -name '*_test.go' \) -printf '%{goroot}/%p\n' >> $src_list + +    find bin/ pkg/ -type d -a ! -path '*_dynlink/*' -a ! -path '*_race/*' -printf '%%%dir %{goroot}/%p\n' >> $pkg_list +    find bin/ pkg/ ! -type d -a ! -path '*_dynlink/*' -a ! -path '*_race/*' -printf '%{goroot}/%p\n' >> $pkg_list + +    find doc/ -type d -printf '%%%dir %{goroot}/%p\n' >> $docs_list +    find doc/ ! -type d -printf '%{goroot}/%p\n' >> $docs_list + +    find misc/ -type d -printf '%%%dir %{goroot}/%p\n' >> $misc_list +    find misc/ ! -type d -printf '%{goroot}/%p\n' >> $misc_list + +%if %{shared} +    mkdir -p %{buildroot}/%{_libdir}/ +    mkdir -p %{buildroot}/%{golibdir}/ +    for file in $(find .  -iname "*.so" ); do +        chmod 755 $file +        mv  $file %{buildroot}/%{golibdir} +        pushd $(dirname $file) +        ln -fs %{golibdir}/$(basename $file) $(basename $file) +        popd +        echo "%%{goroot}/$file" >> $shared_list +        echo "%%{golibdir}/$(basename $file)" >> $shared_list +    done + +	find pkg/*_dynlink/ -type d -printf '%%%dir %{goroot}/%p\n' >> $shared_list +	find pkg/*_dynlink/ ! -type d -printf '%{goroot}/%p\n' >> $shared_list +%endif + +%if %{race} + +    find pkg/*_race/ -type d -printf '%%%dir %{goroot}/%p\n' >> $race_list +    find pkg/*_race/ ! -type d -printf '%{goroot}/%p\n' >> $race_list + +%endif + +    find test/ -type d -printf '%%%dir %{goroot}/%p\n' >> $tests_list +    find test/ ! -type d -printf '%{goroot}/%p\n' >> $tests_list +    find src/ -type d -a \( -name testdata -o -ipath '*/testdata/*' \) -printf '%%%dir %{goroot}/%p\n' >> $tests_list +    find src/ ! -type d -a \( -ipath '*/testdata/*' -o -name '*_test.go' \) -printf '%{goroot}/%p\n' >> $tests_list +    # this is only the zoneinfo.zip +    find lib/ -type d -printf '%%%dir %{goroot}/%p\n' >> $tests_list +    find lib/ ! -type d -printf '%{goroot}/%p\n' >> $tests_list +popd + +rm -rfv %{buildroot}%{goroot}/doc/Makefile + +mkdir -p %{buildroot}%{goroot}/bin/linux_%{gohostarch} +ln -sf %{goroot}/bin/go %{buildroot}%{goroot}/bin/linux_%{gohostarch}/go +ln -sf %{goroot}/bin/gofmt %{buildroot}%{goroot}/bin/linux_%{gohostarch}/gofmt + +mkdir -p %{buildroot}%{gopath}/src/github.com +mkdir -p %{buildroot}%{gopath}/src/bitbucket.org +mkdir -p %{buildroot}%{gopath}/src/code.google.com/p +mkdir -p %{buildroot}%{gopath}/src/golang.org/x + +%check +export GOROOT=$(pwd -P) +export PATH="$GOROOT"/bin:"$PATH" +cd src + +export CC="gcc" +export CFLAGS="$RPM_OPT_FLAGS" +export LDFLAGS="$RPM_LD_FLAGS" +%if !%{external_linker} +export GO_LDFLAGS="-linkmode internal" +%endif +%if !%{cgo_enabled} || !%{external_linker} +export CGO_ENABLED=0 +%endif + +export GO_TEST_TIMEOUT_SCALE=2 + +%if %{fail_on_tests} +echo tests ignored +%else +./run.bash --no-rebuild -v -k -run='!(cmd/go|go/build|cmd/internal/testdir|cmd/link|cmd/nm|cmd/cgo/internal/testlife|cmd/cgo/internal/teststdio|cmd/cgo/internal/testerrors|tyepparams|race|flag|cgo_stdio|cgo_life|cgo_errors|test:0_1|api)' +%endif +cd .. + +%post +%{_sbindir}/update-alternatives --install %{_bindir}/go \ +    go %{goroot}/bin/go 90 \ +    --slave %{_bindir}/gofmt gofmt %{goroot}/bin/gofmt + +%preun +if [ $1 = 0 ]; then +    %{_sbindir}/update-alternatives --remove go %{goroot}/bin/go +fi + +%if %{shared} +%files -f go-pkg.list -f go-shared.list +%else +%files -f go-pkg.list +%endif + +%doc LICENSE PATENTS +%doc %{goroot}/VERSION +%dir %{goroot}/doc +%doc %{goroot}/doc/* +%dir %{goroot} +%exclude %{goroot}/src/ +%exclude %{goroot}/doc/ +%exclude %{goroot}/misc/ +%exclude %{goroot}/test/ +%exclude %{goroot}/lib/ +%{goroot}/* +%dir %{gopath} +%dir %{gopath}/src +%dir %{gopath}/src/github.com/ +%dir %{gopath}/src/bitbucket.org/ +%dir %{gopath}/src/code.google.com/ +%dir %{gopath}/src/code.google.com/p/ +%dir %{gopath}/src/golang.org +%dir %{gopath}/src/golang.org/x + +%files help -f go-docs.list + +%files devel -f go-tests.list -f go-misc.list -f go-src.list + +%changelog +* Mon Jul 30 2024 jingxiaolu <lujingxiao@huawei.com> - 1.21.4-17 +- cmd/compile: ensure pointer arithmetic happens after the nil check + +* Mon Jul 30 2024 jingxiaolu <lujingxiao@huawei.com> - 1.21.4-16 +- cmd/compile: handle constant pointer offsets in dead store elimination + +* Mon Jul 29 2024 EulerOSWander <314264452@qq.com> - 1.21.4-15 +- fix send correct lastStreamID in stream-caused GOAWAY + +* Wed Jul 03 2024 kywqs <weiqingsong@kylinos.cn.com> - 1.21.4-14 +- fix CVE-2024-24791 + +* Sun Jun 23 2024 hanchao <hanchao63@huawei.com> - 1.21.4-13 +- Type:CVE +- CVE:CVE-2023-39326,CVE-2024-24789 +- SUG:NA +- DESC:fix CVE-2023-39326,CVE-2024-24789 + +* Fri Jun 21 2024  EulerOSWander <314264452@qq.com> - 1.21.4-12 +- fix CVE-2023-45285 + +* Thu May 23 2024 EulerOSWander <314264452@qq.com> - 1.21.4-11 +- fix CVE-2024-24787 + +* Thu Jun 13 2024 Zhao Mengmeng <zhaomengmeng@kylinos.cn> - 1.21.4-10 +- fix CVE-2024-24790 + +* Tue Jun 11 2024 chenguoqi <chenguoqi@loongson.cn> - 1.21.4-9 +- Fix missing go.env file + +* Thu Apr 18 2024 Huang Yang <huangyang@loongson.cn> - 1.21.4-8 +- enable external_linker and cgo on loongarch64 + +* Tue Apr 16 2024 hanchao <hanchao63@huawei.com> - 1.21.4-7 +- fix CVE-2023-45288 + +* Thu Mar 28 2024 hanchao <hanchao63@huawei.com> - 1.21.4-6 +- fix CVE-2024-24784 + +* Thu Mar 28 2024 hanchao <hanchao63@huawei.com> - 1.21.4-5 +- enabling the patches + +* Tue Mar 26 2024 Wenlong Zhang <zhangwenlong@loongson.cn> - 1.21.4-4 +- fix build error for loongarch64 + +* 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 + +* Tue Dec 5 2023 hanchao <hanchao63@huawei.com> - 1.21.4-1 +- upgrade to 1.21.4 + +* Thu Aug 24 2023 wanglimin <wanglimin@xfusion.com> - 1.20.7-2 +- permit invalid host header for docker + +* Mon Aug 7 2023 Funda Wang <fundawang@yeah.net> - 1.20.7-1 +- New version 1.20.7 + +* Sun Jul 30 2023 Funda Wang <fundawang@yeah.net> - 1.20.5-3 +- Use local proxy and sumdb for speed up + +* Tue Jul 11 2023 hanchao <sunchendong@xfusion.com> - 1.20.5-2 +- fix CVE-2023-29406 + +* Wed Jun 21 2023 hanchao <hanchao63@huawei.com> - 1.20.5-1 +- upgrade to 1.20.5 @@ -0,0 +1 @@ +92054b4df78d17ce035c9943a3ed1fec  go1.21.4.src.tar.gz | 
