Compare commits
10 Commits
0dfda72f73
...
676e9140f9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
676e9140f9 | ||
|
|
3672fe114c | ||
|
|
b4d68e2725 | ||
|
|
dbe4d8bce5 | ||
|
|
4d8b952107 | ||
|
|
28875f707c | ||
|
|
1b23503dc7 | ||
|
|
d7448dbe57 | ||
|
|
7c5b3dc61e | ||
|
|
2ce91ac6b0 |
@ -0,0 +1,114 @@
|
||||
From 3a0f84cabae57c185cd18564e6371ce2b50181aa Mon Sep 17 00:00:00 2001
|
||||
From: David Chase <drchase@google.com>
|
||||
Date: Thu, 14 Dec 2023 14:20:12 -0500
|
||||
Subject: [PATCH 10/20] [release-branch.go1.21] runtime: add race annotations
|
||||
in IncNonDefault
|
||||
|
||||
Conflict:NA
|
||||
Reference:https://go-review.googlesource.com/c/go/+/549796
|
||||
|
||||
Also use CompareAndSwap to make the code actually less racy.
|
||||
|
||||
Added a test which will be meaningful when run under the race
|
||||
detector (tested it -race with broken fix in runtime, it failed).
|
||||
|
||||
This backport incorporates the correction in CL 551856,
|
||||
using racereleasemerge instead of racerelease.
|
||||
|
||||
Fixes #64757
|
||||
|
||||
Change-Id: I5972e08901d1adc8ba74858edad7eba91be1b0ce
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/549796
|
||||
Run-TryBot: David Chase <drchase@google.com>
|
||||
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
|
||||
Reviewed-by: Cherry Mui <cherryyz@google.com>
|
||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
||||
(cherry picked from commit 3313bbb4055f38f53cd43c6c5782a229f445f230)
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/550236
|
||||
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
|
||||
TryBot-Bypass: Matthew Dempsky <mdempsky@google.com>
|
||||
Reviewed-by: Michael Knyszek <mknyszek@google.com>
|
||||
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
|
||||
---
|
||||
src/internal/godebug/godebug_test.go | 31 ++++++++++++++++++++++++++++
|
||||
src/runtime/runtime.go | 13 ++++++++----
|
||||
2 files changed, 40 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/internal/godebug/godebug_test.go b/src/internal/godebug/godebug_test.go
|
||||
index 8e46283adab3..65dd256e8e7d 100644
|
||||
--- a/src/internal/godebug/godebug_test.go
|
||||
+++ b/src/internal/godebug/godebug_test.go
|
||||
@@ -7,6 +7,7 @@ package godebug_test
|
||||
import (
|
||||
"fmt"
|
||||
. "internal/godebug"
|
||||
+ "internal/race"
|
||||
"internal/testenv"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -70,6 +71,36 @@ func TestMetrics(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
+// TestPanicNilRace checks for a race in the runtime caused by use of runtime
|
||||
+// atomics (not visible to usual race detection) to install the counter for
|
||||
+// non-default panic(nil) semantics. For #64649.
|
||||
+func TestPanicNilRace(t *testing.T) {
|
||||
+ if !race.Enabled {
|
||||
+ t.Skip("Skipping test intended for use with -race.")
|
||||
+ }
|
||||
+ if os.Getenv("GODEBUG") != "panicnil=1" {
|
||||
+ cmd := testenv.CleanCmdEnv(testenv.Command(t, os.Args[0], "-test.run=^TestPanicNilRace$", "-test.v", "-test.parallel=2", "-test.count=1"))
|
||||
+ cmd.Env = append(cmd.Env, "GODEBUG=panicnil=1")
|
||||
+ out, err := cmd.CombinedOutput()
|
||||
+ t.Logf("output:\n%s", out)
|
||||
+
|
||||
+ if err != nil {
|
||||
+ t.Errorf("Was not expecting a crash")
|
||||
+ }
|
||||
+ return
|
||||
+ }
|
||||
+
|
||||
+ test := func(t *testing.T) {
|
||||
+ t.Parallel()
|
||||
+ defer func() {
|
||||
+ recover()
|
||||
+ }()
|
||||
+ panic(nil)
|
||||
+ }
|
||||
+ t.Run("One", test)
|
||||
+ t.Run("Two", test)
|
||||
+}
|
||||
+
|
||||
func TestCmdBisect(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
out, err := exec.Command("go", "run", "cmd/vendor/golang.org/x/tools/cmd/bisect", "GODEBUG=buggy=1#PATTERN", os.Args[0], "-test.run=BisectTestCase").CombinedOutput()
|
||||
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
|
||||
index 0822d0e8054e..15119cf5dfc7 100644
|
||||
--- a/src/runtime/runtime.go
|
||||
+++ b/src/runtime/runtime.go
|
||||
@@ -101,12 +101,17 @@ func (g *godebugInc) IncNonDefault() {
|
||||
if newInc == nil {
|
||||
return
|
||||
}
|
||||
- // If other goroutines are racing here, no big deal. One will win,
|
||||
- // and all the inc functions will be using the same underlying
|
||||
- // *godebug.Setting.
|
||||
inc = new(func())
|
||||
*inc = (*newInc)(g.name)
|
||||
- g.inc.Store(inc)
|
||||
+ if raceenabled {
|
||||
+ racereleasemerge(unsafe.Pointer(&g.inc))
|
||||
+ }
|
||||
+ if !g.inc.CompareAndSwap(nil, inc) {
|
||||
+ inc = g.inc.Load()
|
||||
+ }
|
||||
+ }
|
||||
+ if raceenabled {
|
||||
+ raceacquire(unsafe.Pointer(&g.inc))
|
||||
}
|
||||
(*inc)()
|
||||
}
|
||||
--
|
||||
2.33.0
|
||||
|
||||
@ -0,0 +1,256 @@
|
||||
From d1d93129506c78cc8ee25644384286822d93c81a Mon Sep 17 00:00:00 2001
|
||||
From: Filippo Valsorda <filippo@golang.org>
|
||||
Date: Thu, 02 Jan 2025 01:34:40 +0100
|
||||
Subject: [PATCH] crypto/tls: fix Config.Time in tests using expired certificates
|
||||
|
||||
Fixes #71077
|
||||
|
||||
Edited-by(backport to go1.21): Wang Shuo <wangshuo@kylinos.cn>
|
||||
|
||||
Change-Id: I6a6a465685f3bd50a5bb35a160f87b59b74fa6af
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/639655
|
||||
Auto-Submit: Ian Lance Taylor <iant@google.com>
|
||||
Reviewed-by: Damien Neil <dneil@google.com>
|
||||
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
||||
Auto-Submit: Filippo Valsorda <filippo@golang.org>
|
||||
Auto-Submit: Damien Neil <dneil@google.com>
|
||||
Reviewed-by: Joel Sing <joel@sing.id.au>
|
||||
Reviewed-by: Ian Lance Taylor <iant@google.com>
|
||||
---
|
||||
src/crypto/tls/handshake_client_test.go | 30 +++++++++++++++----------
|
||||
src/crypto/tls/handshake_server_test.go | 2 ++
|
||||
src/crypto/tls/handshake_test.go | 5 +++++
|
||||
src/crypto/tls/tls_test.go | 6 ++---
|
||||
4 files changed, 27 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
|
||||
index a2052ce..7f5cb67 100644
|
||||
--- a/src/crypto/tls/handshake_client_test.go
|
||||
+++ b/src/crypto/tls/handshake_client_test.go
|
||||
@@ -881,6 +881,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
+ Time: testTime,
|
||||
}
|
||||
|
||||
issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
|
||||
@@ -897,6 +898,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
+ Time: testTime,
|
||||
}
|
||||
|
||||
testResumeState := func(test string, didResume bool) {
|
||||
@@ -943,7 +945,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// An old session ticket is replaced with a ticket encrypted with a fresh key.
|
||||
ticket = getTicket()
|
||||
- serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
+ serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithOldTicket", true)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("old first ticket matches the fresh one")
|
||||
@@ -951,13 +953,13 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// Once the session master secret is expired, a full handshake should occur.
|
||||
ticket = getTicket()
|
||||
- serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
+ serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + time.Minute) }
|
||||
testResumeState("ResumeWithExpiredTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("expired first ticket matches the fresh one")
|
||||
}
|
||||
|
||||
- serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
|
||||
+ serverConfig.Time = testTime // reset the time back
|
||||
key1 := randomKey()
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key1})
|
||||
|
||||
@@ -974,11 +976,11 @@ func testResumption(t *testing.T, version uint16) {
|
||||
testResumeState("KeyChangeFinish", true)
|
||||
|
||||
// Age the session ticket a bit, but not yet expired.
|
||||
- serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
|
||||
+ serverConfig.Time = func() time.Time { return testTime().Add(24*time.Hour + time.Minute) }
|
||||
testResumeState("OldSessionTicket", true)
|
||||
ticket = getTicket()
|
||||
// Expire the session ticket, which would force a full handshake.
|
||||
- serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
|
||||
+ serverConfig.Time = func() time.Time { return testTime().Add(24*8*time.Hour + 2*time.Minute) }
|
||||
testResumeState("ExpiredSessionTicket", false)
|
||||
if bytes.Equal(ticket, getTicket()) {
|
||||
t.Fatal("new ticket wasn't provided after old ticket expired")
|
||||
@@ -986,7 +988,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
|
||||
// Age the session ticket a bit at a time, but don't expire it.
|
||||
d := 0 * time.Hour
|
||||
- serverConfig.Time = func() time.Time { return time.Now().Add(d) }
|
||||
+ serverConfig.Time = func() time.Time { return testTime().Add(d) }
|
||||
deleteTicket()
|
||||
testResumeState("GetFreshSessionTicket", false)
|
||||
for i := 0; i < 13; i++ {
|
||||
@@ -997,7 +999,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
// handshake occurs for TLS 1.2. Resumption should still occur for
|
||||
// TLS 1.3 since the client should be using a fresh ticket sent over
|
||||
// by the server.
|
||||
- d += 12 * time.Hour
|
||||
+ d += 12*time.Hour + time.Minute
|
||||
if version == VersionTLS13 {
|
||||
testResumeState("ExpiredSessionTicket", true)
|
||||
} else {
|
||||
@@ -1013,6 +1015,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
+ Time: testTime,
|
||||
}
|
||||
serverConfig.SetSessionTicketKeys([][32]byte{key2})
|
||||
|
||||
@@ -1038,6 +1041,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
|
||||
MaxVersion: version,
|
||||
Certificates: testConfig.Certificates,
|
||||
+ Time: testTime,
|
||||
}
|
||||
testResumeState("InitialHandshake", false)
|
||||
testResumeState("WithHelloRetryRequest", true)
|
||||
@@ -1047,6 +1051,7 @@ func testResumption(t *testing.T, version uint16) {
|
||||
MaxVersion: version,
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
+ Time: testTime,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1761,6 +1766,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
||||
serverConfig := &Config{
|
||||
MaxVersion: version,
|
||||
Certificates: []Certificate{testConfig.Certificates[0]},
|
||||
+ Time: testTime,
|
||||
ClientCAs: rootCAs,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
@@ -1774,6 +1780,7 @@ func testVerifyConnection(t *testing.T, version uint16) {
|
||||
RootCAs: rootCAs,
|
||||
ServerName: "example.golang",
|
||||
Certificates: []Certificate{testConfig.Certificates[0]},
|
||||
+ Time: testTime,
|
||||
NextProtos: []string{"protocol1"},
|
||||
}
|
||||
test.configureClient(clientConfig, &clientCalled)
|
||||
@@ -1816,8 +1823,6 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AddCert(issuer)
|
||||
|
||||
- now := func() time.Time { return time.Unix(1476984729, 0) }
|
||||
-
|
||||
sentinelErr := errors.New("TestVerifyPeerCertificate")
|
||||
|
||||
verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
|
||||
@@ -2063,7 +2068,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
config.ServerName = "example.golang"
|
||||
config.ClientAuth = RequireAndVerifyClientCert
|
||||
config.ClientCAs = rootCAs
|
||||
- config.Time = now
|
||||
+ config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
config.Certificates = make([]Certificate, 1)
|
||||
config.Certificates[0].Certificate = [][]byte{testRSACertificate}
|
||||
@@ -2080,7 +2085,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
|
||||
config := testConfig.Clone()
|
||||
config.ServerName = "example.golang"
|
||||
config.RootCAs = rootCAs
|
||||
- config.Time = now
|
||||
+ config.Time = testTime
|
||||
config.MaxVersion = version
|
||||
test.configureClient(config, &clientCalled)
|
||||
clientErr := Client(c, config).Handshake()
|
||||
@@ -2393,7 +2398,7 @@ func testGetClientCertificate(t *testing.T, version uint16) {
|
||||
serverConfig.RootCAs = x509.NewCertPool()
|
||||
serverConfig.RootCAs.AddCert(issuer)
|
||||
serverConfig.ClientCAs = serverConfig.RootCAs
|
||||
- serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
+ serverConfig.Time = testTime
|
||||
serverConfig.MaxVersion = version
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
@@ -2564,6 +2569,7 @@ func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(32),
|
||||
ServerName: "example.golang",
|
||||
RootCAs: roots,
|
||||
+ Time: testTime,
|
||||
}
|
||||
serverConfig := testConfig.Clone()
|
||||
serverConfig.MaxVersion = ver
|
||||
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
|
||||
index 04abdcc..9f0b1d3 100644
|
||||
--- a/src/crypto/tls/handshake_server_test.go
|
||||
+++ b/src/crypto/tls/handshake_server_test.go
|
||||
@@ -481,6 +481,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
|
||||
serverConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
|
||||
Certificates: testConfig.Certificates,
|
||||
+ Time: testTime,
|
||||
}
|
||||
clientConfig := &Config{
|
||||
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
|
||||
@@ -488,6 +489,7 @@ func testCrossVersionResume(t *testing.T, version uint16) {
|
||||
ClientSessionCache: NewLRUClientSessionCache(1),
|
||||
ServerName: "servername",
|
||||
MinVersion: VersionTLS10,
|
||||
+ Time: testTime,
|
||||
}
|
||||
|
||||
// Establish a session at TLS 1.1.
|
||||
diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
|
||||
index bacc8b7..27ab19e 100644
|
||||
--- a/src/crypto/tls/handshake_test.go
|
||||
+++ b/src/crypto/tls/handshake_test.go
|
||||
@@ -429,6 +429,11 @@ func fromHex(s string) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
+// testTime is 2016-10-20T17:32:09.000Z, which is within the validity period of
|
||||
+// [testRSACertificate], [testRSACertificateIssuer], [testRSA2048Certificate],
|
||||
+// [testRSA2048CertificateIssuer], and [testECDSACertificate].
|
||||
+var testTime = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
+
|
||||
var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
|
||||
|
||||
var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76")
|
||||
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
|
||||
index c3f16c7..83100a7 100644
|
||||
--- a/src/crypto/tls/tls_test.go
|
||||
+++ b/src/crypto/tls/tls_test.go
|
||||
@@ -1098,8 +1098,6 @@ func TestConnectionState(t *testing.T) {
|
||||
rootCAs := x509.NewCertPool()
|
||||
rootCAs.AddCert(issuer)
|
||||
|
||||
- now := func() time.Time { return time.Unix(1476984729, 0) }
|
||||
-
|
||||
const alpnProtocol = "golang"
|
||||
const serverName = "example.golang"
|
||||
var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
|
||||
@@ -1115,7 +1113,7 @@ func TestConnectionState(t *testing.T) {
|
||||
}
|
||||
t.Run(name, func(t *testing.T) {
|
||||
config := &Config{
|
||||
- Time: now,
|
||||
+ Time: testTime,
|
||||
Rand: zeroSource{},
|
||||
Certificates: make([]Certificate, 1),
|
||||
MaxVersion: v,
|
||||
@@ -1726,7 +1724,7 @@ func testVerifyCertificates(t *testing.T, version uint16) {
|
||||
var serverVerifyPeerCertificates, clientVerifyPeerCertificates bool
|
||||
|
||||
clientConfig := testConfig.Clone()
|
||||
- clientConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
|
||||
+ clientConfig.Time = testTime
|
||||
clientConfig.MaxVersion = version
|
||||
clientConfig.MinVersion = version
|
||||
clientConfig.RootCAs = rootCAs
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -0,0 +1,392 @@
|
||||
From 66f3c19e6a577682595b62d428df9e63430ad1be Mon Sep 17 00:00:00 2001
|
||||
From: Michael Pratt <mpratt@google.com>
|
||||
Date: Mon, 4 Sep 2023 09:55:01 -0400
|
||||
Subject: [PATCH 11/20] [release-branch.go1.21] runtime: allow update of system
|
||||
stack bounds on callback from C thread
|
||||
|
||||
Conflict:NA
|
||||
Reference:https://go-review.googlesource.com/c/go/+/527715
|
||||
|
||||
[This cherry-pick combines CL 527715, CL 527775, CL 527797, and
|
||||
CL 529216.]
|
||||
|
||||
[This is a redo of CL 525455 with the test fixed on darwin by defining
|
||||
_XOPEN_SOURCE, and disabled with android, musl, and openbsd, which do
|
||||
not provide getcontext.]
|
||||
|
||||
Since CL 495855, Ms are cached for C threads calling into Go, including
|
||||
the stack bounds of the system stack.
|
||||
|
||||
Some C libraries (e.g., coroutine libraries) do manual stack management
|
||||
and may change stacks between calls to Go on the same thread.
|
||||
|
||||
Changing the stack if there is more Go up the stack would be
|
||||
problematic. But if the calls are completely independent there is no
|
||||
particular reason for Go to care about the changing stack boundary.
|
||||
|
||||
Thus, this CL allows the stack bounds to change in such cases. The
|
||||
primary downside here (besides additional complexity) is that normal
|
||||
systems that do not manipulate the stack may not notice unintentional
|
||||
stack corruption as quickly as before.
|
||||
|
||||
Note that callbackUpdateSystemStack is written to be usable for the
|
||||
initial setup in needm as well as updating the stack in cgocallbackg.
|
||||
|
||||
For #62440.
|
||||
For #62130.
|
||||
For #63209.
|
||||
|
||||
Change-Id: I0fe0134f865932bbaff1fc0da377c35c013bd768
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/527715
|
||||
Run-TryBot: Michael Pratt <mpratt@google.com>
|
||||
TryBot-Result: Gopher Robot <gobot@golang.org>
|
||||
Auto-Submit: Michael Pratt <mpratt@google.com>
|
||||
Reviewed-by: Cherry Mui <cherryyz@google.com>
|
||||
(cherry picked from commit 4f9fe6d50965020053ab80bf115f08070ce97f33)
|
||||
(cherry picked from commit e8ba0579e2913f96c65b96e0696d64ff5f1599c5)
|
||||
(cherry picked from commit a843991fdd079c931d4e98c0a17c9ac6dc254fe8)
|
||||
(cherry picked from commit d110d7c42dd8025465153e4008ba807f1e69b359)
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/530480
|
||||
Auto-Submit: Dmitri Shuralyov <dmitshur@google.com>
|
||||
TryBot-Bypass: Michael Pratt <mpratt@google.com>
|
||||
---
|
||||
src/runtime/cgocall.go | 70 ++++++++++++
|
||||
src/runtime/crash_cgo_test.go | 17 +++
|
||||
src/runtime/proc.go | 33 ++----
|
||||
.../testdata/testprogcgo/stackswitch.c | 106 ++++++++++++++++++
|
||||
.../testdata/testprogcgo/stackswitch.go | 43 +++++++
|
||||
5 files changed, 245 insertions(+), 24 deletions(-)
|
||||
create mode 100644 src/runtime/testdata/testprogcgo/stackswitch.c
|
||||
create mode 100644 src/runtime/testdata/testprogcgo/stackswitch.go
|
||||
|
||||
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
|
||||
index 1da7249abc5a..d226c2e907fd 100644
|
||||
--- a/src/runtime/cgocall.go
|
||||
+++ b/src/runtime/cgocall.go
|
||||
@@ -206,6 +206,73 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
|
||||
return errno
|
||||
}
|
||||
|
||||
+// Set or reset the system stack bounds for a callback on sp.
|
||||
+//
|
||||
+// Must be nosplit because it is called by needm prior to fully initializing
|
||||
+// the M.
|
||||
+//
|
||||
+//go:nosplit
|
||||
+func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) {
|
||||
+ g0 := mp.g0
|
||||
+ if sp > g0.stack.lo && sp <= g0.stack.hi {
|
||||
+ // Stack already in bounds, nothing to do.
|
||||
+ return
|
||||
+ }
|
||||
+
|
||||
+ if mp.ncgo > 0 {
|
||||
+ // ncgo > 0 indicates that this M was in Go further up the stack
|
||||
+ // (it called C and is now receiving a callback). It is not
|
||||
+ // safe for the C call to change the stack out from under us.
|
||||
+
|
||||
+ // Note that this case isn't possible for signal == true, as
|
||||
+ // that is always passing a new M from needm.
|
||||
+
|
||||
+ // Stack is bogus, but reset the bounds anyway so we can print.
|
||||
+ hi := g0.stack.hi
|
||||
+ lo := g0.stack.lo
|
||||
+ g0.stack.hi = sp + 1024
|
||||
+ g0.stack.lo = sp - 32*1024
|
||||
+ g0.stackguard0 = g0.stack.lo + stackGuard
|
||||
+
|
||||
+ print("M ", mp.id, " procid ", mp.procid, " runtime: cgocallback with sp=", hex(sp), " out of bounds [", hex(lo), ", ", hex(hi), "]")
|
||||
+ print("\n")
|
||||
+ exit(2)
|
||||
+ }
|
||||
+
|
||||
+ // This M does not have Go further up the stack. However, it may have
|
||||
+ // previously called into Go, initializing the stack bounds. Between
|
||||
+ // that call returning and now the stack may have changed (perhaps the
|
||||
+ // C thread is running a coroutine library). We need to update the
|
||||
+ // stack bounds for this case.
|
||||
+ //
|
||||
+ // Set the stack bounds to match the current stack. If we don't
|
||||
+ // actually know how big the stack is, like we don't know how big any
|
||||
+ // scheduling stack is, but we assume there's at least 32 kB. If we
|
||||
+ // can get a more accurate stack bound from pthread, use that, provided
|
||||
+ // it actually contains SP..
|
||||
+ g0.stack.hi = sp + 1024
|
||||
+ g0.stack.lo = sp - 32*1024
|
||||
+ if !signal && _cgo_getstackbound != nil {
|
||||
+ // Don't adjust if called from the signal handler.
|
||||
+ // We are on the signal stack, not the pthread stack.
|
||||
+ // (We could get the stack bounds from sigaltstack, but
|
||||
+ // we're getting out of the signal handler very soon
|
||||
+ // anyway. Not worth it.)
|
||||
+ var bounds [2]uintptr
|
||||
+ asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds))
|
||||
+ // getstackbound is an unsupported no-op on Windows.
|
||||
+ //
|
||||
+ // Don't use these bounds if they don't contain SP. Perhaps we
|
||||
+ // were called by something not using the standard thread
|
||||
+ // stack.
|
||||
+ if bounds[0] != 0 && sp > bounds[0] && sp <= bounds[1] {
|
||||
+ g0.stack.lo = bounds[0]
|
||||
+ g0.stack.hi = bounds[1]
|
||||
+ }
|
||||
+ }
|
||||
+ g0.stackguard0 = g0.stack.lo + stackGuard
|
||||
+}
|
||||
+
|
||||
// Call from C back to Go. fn must point to an ABIInternal Go entry-point.
|
||||
//
|
||||
//go:nosplit
|
||||
@@ -216,6 +283,9 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) {
|
||||
exit(2)
|
||||
}
|
||||
|
||||
+ sp := gp.m.g0.sched.sp // system sp saved by cgocallback.
|
||||
+ callbackUpdateSystemStack(gp.m, sp, false)
|
||||
+
|
||||
// The call from C is on gp.m's g0 stack, so we must ensure
|
||||
// that we stay on that M. We have to do this before calling
|
||||
// exitsyscall, since it would otherwise be free to move us to
|
||||
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
|
||||
index e1851808f319..424aedb4ef7e 100644
|
||||
--- a/src/runtime/crash_cgo_test.go
|
||||
+++ b/src/runtime/crash_cgo_test.go
|
||||
@@ -853,3 +853,20 @@ func TestEnsureBindM(t *testing.T) {
|
||||
t.Errorf("expected %q, got %v", want, got)
|
||||
}
|
||||
}
|
||||
+
|
||||
+func TestStackSwitchCallback(t *testing.T) {
|
||||
+ t.Parallel()
|
||||
+ switch runtime.GOOS {
|
||||
+ case "windows", "plan9", "android", "ios", "openbsd": // no getcontext
|
||||
+ t.Skipf("skipping test on %s", runtime.GOOS)
|
||||
+ }
|
||||
+ got := runTestProg(t, "testprogcgo", "StackSwitchCallback")
|
||||
+ skip := "SKIP\n"
|
||||
+ if got == skip {
|
||||
+ t.Skip("skipping on musl/bionic libc")
|
||||
+ }
|
||||
+ want := "OK\n"
|
||||
+ if got != want {
|
||||
+ t.Errorf("expected %q, got %v", want, got)
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
|
||||
index afb33c1e8b73..eaea523ab5c5 100644
|
||||
--- a/src/runtime/proc.go
|
||||
+++ b/src/runtime/proc.go
|
||||
@@ -2037,30 +2037,10 @@ func needm(signal bool) {
|
||||
osSetupTLS(mp)
|
||||
|
||||
// Install g (= m->g0) and set the stack bounds
|
||||
- // to match the current stack. If we don't actually know
|
||||
- // how big the stack is, like we don't know how big any
|
||||
- // scheduling stack is, but we assume there's at least 32 kB.
|
||||
- // If we can get a more accurate stack bound from pthread,
|
||||
- // use that.
|
||||
+ // to match the current stack.
|
||||
setg(mp.g0)
|
||||
- gp := getg()
|
||||
- gp.stack.hi = getcallersp() + 1024
|
||||
- gp.stack.lo = getcallersp() - 32*1024
|
||||
- if !signal && _cgo_getstackbound != nil {
|
||||
- // Don't adjust if called from the signal handler.
|
||||
- // We are on the signal stack, not the pthread stack.
|
||||
- // (We could get the stack bounds from sigaltstack, but
|
||||
- // we're getting out of the signal handler very soon
|
||||
- // anyway. Not worth it.)
|
||||
- var bounds [2]uintptr
|
||||
- asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds))
|
||||
- // getstackbound is an unsupported no-op on Windows.
|
||||
- if bounds[0] != 0 {
|
||||
- gp.stack.lo = bounds[0]
|
||||
- gp.stack.hi = bounds[1]
|
||||
- }
|
||||
- }
|
||||
- gp.stackguard0 = gp.stack.lo + stackGuard
|
||||
+ sp := getcallersp()
|
||||
+ callbackUpdateSystemStack(mp, sp, signal)
|
||||
|
||||
// Should mark we are already in Go now.
|
||||
// Otherwise, we may call needm again when we get a signal, before cgocallbackg1,
|
||||
@@ -2177,9 +2157,14 @@ func oneNewExtraM() {
|
||||
// So that the destructor would invoke dropm while the non-Go thread is exiting.
|
||||
// This is much faster since it avoids expensive signal-related syscalls.
|
||||
//
|
||||
-// NOTE: this always runs without a P, so, nowritebarrierrec required.
|
||||
+// This always runs without a P, so //go:nowritebarrierrec is required.
|
||||
+//
|
||||
+// This may run with a different stack than was recorded in g0 (there is no
|
||||
+// call to callbackUpdateSystemStack prior to dropm), so this must be
|
||||
+// //go:nosplit to avoid the stack bounds check.
|
||||
//
|
||||
//go:nowritebarrierrec
|
||||
+//go:nosplit
|
||||
func dropm() {
|
||||
// Clear m and g, and return m to the extra list.
|
||||
// After the call to setg we can only call nosplit functions
|
||||
diff --git a/src/runtime/testdata/testprogcgo/stackswitch.c b/src/runtime/testdata/testprogcgo/stackswitch.c
|
||||
new file mode 100644
|
||||
index 000000000000..2f79cc28ed95
|
||||
--- /dev/null
|
||||
+++ b/src/runtime/testdata/testprogcgo/stackswitch.c
|
||||
@@ -0,0 +1,106 @@
|
||||
+// 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.
|
||||
+
|
||||
+//go:build unix && !android && !openbsd
|
||||
+
|
||||
+// Required for darwin ucontext.
|
||||
+#define _XOPEN_SOURCE
|
||||
+// Required for netbsd stack_t if _XOPEN_SOURCE is set.
|
||||
+#define _XOPEN_SOURCE_EXTENDED 1
|
||||
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
+
|
||||
+#include <assert.h>
|
||||
+#include <pthread.h>
|
||||
+#include <stddef.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <ucontext.h>
|
||||
+
|
||||
+// musl libc does not provide getcontext, etc. Skip the test there.
|
||||
+//
|
||||
+// musl libc doesn't provide any direct detection mechanism. So assume any
|
||||
+// non-glibc linux is using musl.
|
||||
+//
|
||||
+// Note that bionic does not provide getcontext either, but that is skipped via
|
||||
+// the android build tag.
|
||||
+#if defined(__linux__) && !defined(__GLIBC__)
|
||||
+#define MUSL 1
|
||||
+#endif
|
||||
+#if defined(MUSL)
|
||||
+void callStackSwitchCallbackFromThread(void) {
|
||||
+ printf("SKIP\n");
|
||||
+ exit(0);
|
||||
+}
|
||||
+#else
|
||||
+
|
||||
+// Use a stack size larger than the 32kb estimate in
|
||||
+// runtime.callbackUpdateSystemStack. This ensures that a second stack
|
||||
+// allocation won't accidentally count as in bounds of the first stack
|
||||
+#define STACK_SIZE (64ull << 10)
|
||||
+
|
||||
+static ucontext_t uctx_save, uctx_switch;
|
||||
+
|
||||
+extern void stackSwitchCallback(void);
|
||||
+
|
||||
+static void *stackSwitchThread(void *arg) {
|
||||
+ // Simple test: callback works from the normal system stack.
|
||||
+ stackSwitchCallback();
|
||||
+
|
||||
+ // Next, verify that switching stacks doesn't break callbacks.
|
||||
+
|
||||
+ char *stack1 = malloc(STACK_SIZE);
|
||||
+ if (stack1 == NULL) {
|
||||
+ perror("malloc");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ // Allocate the second stack before freeing the first to ensure we don't get
|
||||
+ // the same address from malloc.
|
||||
+ char *stack2 = malloc(STACK_SIZE);
|
||||
+ if (stack1 == NULL) {
|
||||
+ perror("malloc");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ if (getcontext(&uctx_switch) == -1) {
|
||||
+ perror("getcontext");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ uctx_switch.uc_stack.ss_sp = stack1;
|
||||
+ uctx_switch.uc_stack.ss_size = STACK_SIZE;
|
||||
+ uctx_switch.uc_link = &uctx_save;
|
||||
+ makecontext(&uctx_switch, stackSwitchCallback, 0);
|
||||
+
|
||||
+ if (swapcontext(&uctx_save, &uctx_switch) == -1) {
|
||||
+ perror("swapcontext");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ if (getcontext(&uctx_switch) == -1) {
|
||||
+ perror("getcontext");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+ uctx_switch.uc_stack.ss_sp = stack2;
|
||||
+ uctx_switch.uc_stack.ss_size = STACK_SIZE;
|
||||
+ uctx_switch.uc_link = &uctx_save;
|
||||
+ makecontext(&uctx_switch, stackSwitchCallback, 0);
|
||||
+
|
||||
+ if (swapcontext(&uctx_save, &uctx_switch) == -1) {
|
||||
+ perror("swapcontext");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ free(stack1);
|
||||
+ free(stack2);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+void callStackSwitchCallbackFromThread(void) {
|
||||
+ pthread_t thread;
|
||||
+ assert(pthread_create(&thread, NULL, stackSwitchThread, NULL) == 0);
|
||||
+ assert(pthread_join(thread, NULL) == 0);
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
diff --git a/src/runtime/testdata/testprogcgo/stackswitch.go b/src/runtime/testdata/testprogcgo/stackswitch.go
|
||||
new file mode 100644
|
||||
index 000000000000..a2e422f0777f
|
||||
--- /dev/null
|
||||
+++ b/src/runtime/testdata/testprogcgo/stackswitch.go
|
||||
@@ -0,0 +1,43 @@
|
||||
+// 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.
|
||||
+
|
||||
+//go:build unix && !android && !openbsd
|
||||
+
|
||||
+package main
|
||||
+
|
||||
+/*
|
||||
+void callStackSwitchCallbackFromThread(void);
|
||||
+*/
|
||||
+import "C"
|
||||
+
|
||||
+import (
|
||||
+ "fmt"
|
||||
+ "runtime/debug"
|
||||
+)
|
||||
+
|
||||
+func init() {
|
||||
+ register("StackSwitchCallback", StackSwitchCallback)
|
||||
+}
|
||||
+
|
||||
+//export stackSwitchCallback
|
||||
+func stackSwitchCallback() {
|
||||
+ // We want to trigger a bounds check on the g0 stack. To do this, we
|
||||
+ // need to call a splittable function through systemstack().
|
||||
+ // SetGCPercent contains such a systemstack call.
|
||||
+ gogc := debug.SetGCPercent(100)
|
||||
+ debug.SetGCPercent(gogc)
|
||||
+}
|
||||
+
|
||||
+
|
||||
+// Regression test for https://go.dev/issue/62440. It should be possible for C
|
||||
+// threads to call into Go from different stacks without crashing due to g0
|
||||
+// stack bounds checks.
|
||||
+//
|
||||
+// N.B. This is only OK for threads created in C. Threads with Go frames up the
|
||||
+// stack must not change the stack out from under us.
|
||||
+func StackSwitchCallback() {
|
||||
+ C.callStackSwitchCallbackFromThread();
|
||||
+
|
||||
+ fmt.Printf("OK\n")
|
||||
+}
|
||||
--
|
||||
2.33.0
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
From 468fad45a27db0ec1fff4ae397d3670795b3f977 Mon Sep 17 00:00:00 2001
|
||||
From: Roland Shoemaker <bracewell@google.com>
|
||||
Date: Mon, 09 Dec 2024 11:31:22 -0800
|
||||
Subject: [PATCH] [release-branch.go1.24] crypto/x509: properly check for IPv6 hosts in URIs
|
||||
|
||||
When checking URI constraints, use netip.ParseAddr, which understands
|
||||
zones, unlike net.ParseIP which chokes on them. This prevents zone IDs
|
||||
from mistakenly satisfying URI constraints.
|
||||
|
||||
CVE: CVE-2024-45341
|
||||
Reference: https://go-review.googlesource.com/c/go/+/643105
|
||||
|
||||
Thanks to Juho Forsén of Mattermost for reporting this issue.
|
||||
|
||||
For #71156
|
||||
Fixes #71209
|
||||
Fixes CVE-2024-45341
|
||||
|
||||
Change-Id: Iecac2529f3605382d257996e0fb6d6983547e400
|
||||
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1700
|
||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
||||
Reviewed-by: Damien Neil <dneil@google.com>
|
||||
(cherry picked from commit 22ca55d396ba801e6ae9b2bd67a059fcb30562fd)
|
||||
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1800
|
||||
Commit-Queue: Roland Shoemaker <bracewell@google.com>
|
||||
Reviewed-by: Roland Shoemaker <bracewell@google.com>
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/643099
|
||||
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
||||
Auto-Submit: Michael Knyszek <mknyszek@google.com>
|
||||
Reviewed-by: Michael Pratt <mpratt@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
|
||||
index 008c702..a585184 100644
|
||||
--- a/src/crypto/x509/name_constraints_test.go
|
||||
+++ b/src/crypto/x509/name_constraints_test.go
|
||||
@@ -1607,6 +1607,23 @@
|
||||
cn: "foo.bar",
|
||||
},
|
||||
},
|
||||
+ // #86: URIs with IPv6 addresses with zones and ports are rejected
|
||||
+ {
|
||||
+ roots: []constraintsSpec{
|
||||
+ {
|
||||
+ ok: []string{"uri:example.com"},
|
||||
+ },
|
||||
+ },
|
||||
+ intermediates: [][]constraintsSpec{
|
||||
+ {
|
||||
+ {},
|
||||
+ },
|
||||
+ },
|
||||
+ leaf: leafSpec{
|
||||
+ sans: []string{"uri:http://[2006:abcd::1%25.example.com]:16/"},
|
||||
+ },
|
||||
+ expectedError: "URI with IP",
|
||||
+ },
|
||||
}
|
||||
|
||||
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
|
||||
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
|
||||
index d2384f5..5fe93c6 100644
|
||||
--- a/src/crypto/x509/verify.go
|
||||
+++ b/src/crypto/x509/verify.go
|
||||
@@ -13,6 +13,7 @@
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
+ "net/netip"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -465,8 +466,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
- if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
|
||||
- net.ParseIP(host) != nil {
|
||||
+ // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we
|
||||
+ // check if _either_ the string parses as an IP, or if it is enclosed in
|
||||
+ // square brackets.
|
||||
+ if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) {
|
||||
return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,397 @@
|
||||
From 6b605505047416bbbf513bba1540220a8897f3f6 Mon Sep 17 00:00:00 2001
|
||||
From: Damien Neil <dneil@google.com>
|
||||
Date: Fri, 22 Nov 2024 12:34:11 -0800
|
||||
Subject: [PATCH] [release-branch.go1.24] net/http: persist header stripping across repeated redirects
|
||||
|
||||
CVE: CVE-2024-45336
|
||||
Reference: https://go-review.googlesource.com/c/go/+/643106
|
||||
|
||||
When an HTTP redirect changes the host of a request, we drop
|
||||
sensitive headers such as Authorization from the redirected request.
|
||||
Fix a bug where a chain of redirects could result in sensitive
|
||||
headers being sent to the wrong host:
|
||||
|
||||
1. request to a.tld with Authorization header
|
||||
2. a.tld redirects to b.tld
|
||||
3. request to b.tld with no Authorization header
|
||||
4. b.tld redirects to b.tld
|
||||
3. request to b.tld with Authorization header restored
|
||||
|
||||
Thanks to Kyle Seely for reporting this issue.
|
||||
|
||||
For #70530
|
||||
Fixes #71212
|
||||
Fixes CVE-2024-45336
|
||||
|
||||
Change-Id: Ia58a2e10d33d6b0cc7220935e771450e5c34de72
|
||||
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1641
|
||||
Reviewed-by: Roland Shoemaker <bracewell@google.com>
|
||||
Reviewed-by: Tatiana Bradley <tatianabradley@google.com>
|
||||
Commit-Queue: Roland Shoemaker <bracewell@google.com>
|
||||
(cherry picked from commit 2889169b87a61f1218a02994feb80fd3d8bfa87c)
|
||||
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/1766
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/643100
|
||||
Auto-Submit: Michael Knyszek <mknyszek@google.com>
|
||||
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
||||
Reviewed-by: Michael Pratt <mpratt@google.com>
|
||||
---
|
||||
|
||||
diff --git a/src/net/http/client.go b/src/net/http/client.go
|
||||
index fda7815..9231f63 100644
|
||||
--- a/src/net/http/client.go
|
||||
+++ b/src/net/http/client.go
|
||||
@@ -610,8 +610,9 @@
|
||||
reqBodyClosed = false // have we closed the current req.Body?
|
||||
|
||||
// Redirect behavior:
|
||||
- redirectMethod string
|
||||
- includeBody bool
|
||||
+ redirectMethod string
|
||||
+ includeBody = true
|
||||
+ stripSensitiveHeaders = false
|
||||
)
|
||||
uerr := func(err error) error {
|
||||
// the body may have been closed already by c.send()
|
||||
@@ -678,7 +679,12 @@
|
||||
// in case the user set Referer on their first request.
|
||||
// If they really want to override, they can do it in
|
||||
// their CheckRedirect func.
|
||||
- copyHeaders(req)
|
||||
+ if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host {
|
||||
+ if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) {
|
||||
+ stripSensitiveHeaders = true
|
||||
+ }
|
||||
+ }
|
||||
+ copyHeaders(req, stripSensitiveHeaders)
|
||||
|
||||
// Add the Referer header from the most recent
|
||||
// request URL to the new one, if it's not https->http:
|
||||
@@ -746,7 +752,7 @@
|
||||
// makeHeadersCopier makes a function that copies headers from the
|
||||
// initial Request, ireq. For every redirect, this function must be called
|
||||
// so that it can copy headers into the upcoming Request.
|
||||
-func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
|
||||
+func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) {
|
||||
// The headers to copy are from the very initial request.
|
||||
// We use a closured callback to keep a reference to these original headers.
|
||||
var (
|
||||
@@ -760,8 +766,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- preq := ireq // The previous request
|
||||
- return func(req *Request) {
|
||||
+ return func(req *Request, stripSensitiveHeaders bool) {
|
||||
// If Jar is present and there was some initial cookies provided
|
||||
// via the request header, then we may need to alter the initial
|
||||
// cookies as we follow redirects since each redirect may end up
|
||||
@@ -798,12 +803,15 @@
|
||||
// Copy the initial request's Header values
|
||||
// (at least the safe ones).
|
||||
for k, vv := range ireqhdr {
|
||||
- if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
|
||||
+ sensitive := false
|
||||
+ switch CanonicalHeaderKey(k) {
|
||||
+ case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
|
||||
+ sensitive = true
|
||||
+ }
|
||||
+ if !(sensitive && stripSensitiveHeaders) {
|
||||
req.Header[k] = vv
|
||||
}
|
||||
}
|
||||
-
|
||||
- preq = req // Update previous Request with the current request
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,28 +987,23 @@
|
||||
return err
|
||||
}
|
||||
|
||||
-func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
|
||||
- switch CanonicalHeaderKey(headerKey) {
|
||||
- case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
|
||||
- // Permit sending auth/cookie headers from "foo.com"
|
||||
- // to "sub.foo.com".
|
||||
+func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool {
|
||||
+ // Permit sending auth/cookie headers from "foo.com"
|
||||
+ // to "sub.foo.com".
|
||||
|
||||
- // Note that we don't send all cookies to subdomains
|
||||
- // automatically. This function is only used for
|
||||
- // Cookies set explicitly on the initial outgoing
|
||||
- // client request. Cookies automatically added via the
|
||||
- // CookieJar mechanism continue to follow each
|
||||
- // cookie's scope as set by Set-Cookie. But for
|
||||
- // outgoing requests with the Cookie header set
|
||||
- // directly, we don't know their scope, so we assume
|
||||
- // it's for *.domain.com.
|
||||
+ // Note that we don't send all cookies to subdomains
|
||||
+ // automatically. This function is only used for
|
||||
+ // Cookies set explicitly on the initial outgoing
|
||||
+ // client request. Cookies automatically added via the
|
||||
+ // CookieJar mechanism continue to follow each
|
||||
+ // cookie's scope as set by Set-Cookie. But for
|
||||
+ // outgoing requests with the Cookie header set
|
||||
+ // directly, we don't know their scope, so we assume
|
||||
+ // it's for *.domain.com.
|
||||
|
||||
- ihost := idnaASCIIFromURL(initial)
|
||||
- dhost := idnaASCIIFromURL(dest)
|
||||
- return isDomainOrSubdomain(dhost, ihost)
|
||||
- }
|
||||
- // All other headers are copied:
|
||||
- return true
|
||||
+ ihost := idnaASCIIFromURL(initial)
|
||||
+ dhost := idnaASCIIFromURL(dest)
|
||||
+ return isDomainOrSubdomain(dhost, ihost)
|
||||
}
|
||||
|
||||
// isDomainOrSubdomain reports whether sub is a subdomain (or exact
|
||||
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
|
||||
index 429b8f1..1ce9539 100644
|
||||
--- a/src/net/http/client_test.go
|
||||
+++ b/src/net/http/client_test.go
|
||||
@@ -1536,6 +1536,55 @@
|
||||
}
|
||||
}
|
||||
|
||||
+// Issue #70530: Once we strip a header on a redirect to a different host,
|
||||
+// the header should stay stripped across any further redirects.
|
||||
+func TestClientStripHeadersOnRepeatedRedirect(t *testing.T) {
|
||||
+ run(t, testClientStripHeadersOnRepeatedRedirect)
|
||||
+}
|
||||
+func testClientStripHeadersOnRepeatedRedirect(t *testing.T, mode testMode) {
|
||||
+ var proto string
|
||||
+ ts := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
+ if r.Host+r.URL.Path != "a.example.com/" {
|
||||
+ if h := r.Header.Get("Authorization"); h != "" {
|
||||
+ t.Errorf("on request to %v%v, Authorization=%q, want no header", r.Host, r.URL.Path, h)
|
||||
+ }
|
||||
+ }
|
||||
+ // Follow a chain of redirects from a to b and back to a.
|
||||
+ // The Authorization header is stripped on the first redirect to b,
|
||||
+ // and stays stripped even if we're sent back to a.
|
||||
+ switch r.Host + r.URL.Path {
|
||||
+ case "a.example.com/":
|
||||
+ Redirect(w, r, proto+"://b.example.com/", StatusFound)
|
||||
+ case "b.example.com/":
|
||||
+ Redirect(w, r, proto+"://b.example.com/redirect", StatusFound)
|
||||
+ case "b.example.com/redirect":
|
||||
+ Redirect(w, r, proto+"://a.example.com/redirect", StatusFound)
|
||||
+ case "a.example.com/redirect":
|
||||
+ w.Header().Set("X-Done", "true")
|
||||
+ default:
|
||||
+ t.Errorf("unexpected request to %v", r.URL)
|
||||
+ }
|
||||
+ })).ts
|
||||
+ proto, _, _ = strings.Cut(ts.URL, ":")
|
||||
+
|
||||
+ c := ts.Client()
|
||||
+ c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) {
|
||||
+ return net.Dial("tcp", ts.Listener.Addr().String())
|
||||
+ }
|
||||
+
|
||||
+ req, _ := NewRequest("GET", proto+"://a.example.com/", nil)
|
||||
+ req.Header.Add("Cookie", "foo=bar")
|
||||
+ req.Header.Add("Authorization", "secretpassword")
|
||||
+ res, err := c.Do(req)
|
||||
+ if err != nil {
|
||||
+ t.Fatal(err)
|
||||
+ }
|
||||
+ defer res.Body.Close()
|
||||
+ if res.Header.Get("X-Done") != "true" {
|
||||
+ t.Fatalf("response missing expected header: X-Done=true")
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
// Issue 22233: copy host when Client follows a relative redirect.
|
||||
func TestClientCopyHostOnRedirect(t *testing.T) { run(t, testClientCopyHostOnRedirect) }
|
||||
func testClientCopyHostOnRedirect(t *testing.T, mode testMode) {
|
||||
@@ -1702,43 +1751,39 @@
|
||||
// Part of Issue 4800
|
||||
func TestShouldCopyHeaderOnRedirect(t *testing.T) {
|
||||
tests := []struct {
|
||||
- header string
|
||||
initialURL string
|
||||
destURL string
|
||||
want bool
|
||||
}{
|
||||
- {"User-Agent", "http://foo.com/", "http://bar.com/", true},
|
||||
- {"X-Foo", "http://foo.com/", "http://bar.com/", true},
|
||||
-
|
||||
// Sensitive headers:
|
||||
- {"cookie", "http://foo.com/", "http://bar.com/", false},
|
||||
- {"cookie2", "http://foo.com/", "http://bar.com/", false},
|
||||
- {"authorization", "http://foo.com/", "http://bar.com/", false},
|
||||
- {"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},
|
||||
+ {"http://foo.com/", "http://bar.com/", false},
|
||||
+ {"http://foo.com/", "http://bar.com/", false},
|
||||
+ {"http://foo.com/", "http://bar.com/", false},
|
||||
+ {"http://foo.com/", "https://foo.com/", true},
|
||||
+ {"http://foo.com:1234/", "http://foo.com:4321/", true},
|
||||
+ {"http://foo.com/", "http://bar.com/", false},
|
||||
+ {"http://foo.com/", "http://[::1%25.foo.com]/", false},
|
||||
|
||||
// But subdomains should work:
|
||||
- {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
|
||||
- {"www-authenticate", "http://foo.com/", "https://foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
- {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true},
|
||||
+ {"http://foo.com/", "http://foo.com/", true},
|
||||
+ {"http://foo.com/", "http://sub.foo.com/", true},
|
||||
+ {"http://foo.com/", "http://notfoo.com/", false},
|
||||
+ {"http://foo.com/", "https://foo.com/", true},
|
||||
+ {"http://foo.com:80/", "http://foo.com/", true},
|
||||
+ {"http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
+ {"http://foo.com:443/", "https://foo.com/", true},
|
||||
+ {"http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
+ {"http://foo.com:1234/", "http://foo.com/", true},
|
||||
|
||||
- {"authorization", "http://foo.com/", "http://foo.com/", true},
|
||||
- {"authorization", "http://foo.com/", "http://sub.foo.com/", true},
|
||||
- {"authorization", "http://foo.com/", "http://notfoo.com/", false},
|
||||
- {"authorization", "http://foo.com/", "https://foo.com/", true},
|
||||
- {"authorization", "http://foo.com:80/", "http://foo.com/", true},
|
||||
- {"authorization", "http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
- {"authorization", "http://foo.com:443/", "https://foo.com/", true},
|
||||
- {"authorization", "http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
- {"authorization", "http://foo.com:1234/", "http://foo.com/", true},
|
||||
+ {"http://foo.com/", "http://foo.com/", true},
|
||||
+ {"http://foo.com/", "http://sub.foo.com/", true},
|
||||
+ {"http://foo.com/", "http://notfoo.com/", false},
|
||||
+ {"http://foo.com/", "https://foo.com/", true},
|
||||
+ {"http://foo.com:80/", "http://foo.com/", true},
|
||||
+ {"http://foo.com:80/", "http://sub.foo.com/", true},
|
||||
+ {"http://foo.com:443/", "https://foo.com/", true},
|
||||
+ {"http://foo.com:443/", "https://sub.foo.com/", true},
|
||||
+ {"http://foo.com:1234/", "http://foo.com/", true},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
u0, err := url.Parse(tt.initialURL)
|
||||
@@ -1751,10 +1796,10 @@
|
||||
t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err)
|
||||
continue
|
||||
}
|
||||
- got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1)
|
||||
+ got := Export_shouldCopyHeaderOnRedirect(u0, u1)
|
||||
if got != tt.want {
|
||||
- t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
|
||||
- i, tt.header, tt.initialURL, tt.destURL, got, tt.want)
|
||||
+ t.Errorf("%d. shouldCopyHeaderOnRedirect(%q => %q) = %v; want %v",
|
||||
+ i, tt.initialURL, tt.destURL, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/net/http/internal/testcert/testcert.go b/src/net/http/internal/testcert/testcert.go
|
||||
index d510e79..78ce42e 100644
|
||||
--- a/src/net/http/internal/testcert/testcert.go
|
||||
+++ b/src/net/http/internal/testcert/testcert.go
|
||||
@@ -10,56 +10,56 @@
|
||||
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
|
||||
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
|
||||
// generated from src/crypto/tls:
|
||||
-// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
+// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
-MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
|
||||
+MIIDSDCCAjCgAwIBAgIQccHlx0t8YUF0slXOMl05bzANBgkqhkiG9w0BAQsFADAS
|
||||
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
|
||||
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
-MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
|
||||
-bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
|
||||
-aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
|
||||
-YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
|
||||
-POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
|
||||
-h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
|
||||
+MIIBCgKCAQEAzZyG7/IYBvSYBqhGEr0RwBeGqAlzDj8e6v35ZR4wjIc31r6TV2wc
|
||||
+FGjZ9jztHeDJkSe4eLRjYlnL1LoNDJ5QZ8lvipFQH0CMoB5oUsbnE5a/7/VkC9vI
|
||||
+y3TvFktq1nCCQJ+jgeAQT+X04R98Bl8Ci4SAnVKQVSNue9GfG0jBvT59vIkBa7xt
|
||||
+dBegtcbDjtfb9wtOgXceQONtYL+YrGVTOt56Y2aA42zDYIJw25u1dgufkZL6pCvA
|
||||
+u4P1MhLwEiRXP2MYhwrnsQDuC7RWvcHoq03XbGXi5SNyxQExerrIyYGVhn1wXKrD
|
||||
+mJB8rc0+I8tP/UOaYmV9B3x44YQZI8ekBQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE
|
||||
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
-DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
|
||||
-bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
|
||||
-5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
|
||||
-cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
|
||||
-+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
|
||||
-grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
|
||||
-5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
|
||||
-WkBKOclmOV2xlTVuPw==
|
||||
+DgQWBBT8AKB32mDTtnvHs6woiw9g00AfSDA9BgNVHREENjA0ggtleGFtcGxlLmNv
|
||||
+bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG
|
||||
+9w0BAQsFAAOCAQEAzCnM+T8BrnBm7X6thsh/uOWHB+8NOeUiBf2Q3V8/D/k/ehlS
|
||||
+N4SnQNa8QIq1nRtx8w2/w+QoJFK9TKxTED+abbfTTImqOXeyTAyRUTtbSAO9XQyc
|
||||
+ydxpOUYvYX9WO+EHVcKi0i+gkwuacAkDYr/lOsYojwrUEs8t4VAwTjVUzHvYvbc3
|
||||
++dYZbY0xWa9C9JmO4Y6WTbPFc0zjLMweOhY3hAugWjspEXqsXPynlIddqhO5m0FC
|
||||
+lEIRSNwsSg/V9wIxOr/ybEAwB+opQdLxESw4w1hpZePNznnEfbnbpnytytmy7RMS
|
||||
+H35nDZdqF17KMJ86ZCrESmeR/JSpO0CqoOL51w==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
// LocalhostKey is the private key for LocalhostCert.
|
||||
var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
|
||||
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
|
||||
-4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
|
||||
-gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
|
||||
-URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
|
||||
-AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
|
||||
-VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
|
||||
-x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
|
||||
-lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
|
||||
-dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
|
||||
-EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
|
||||
-XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
|
||||
-6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
|
||||
-3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
|
||||
-uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
|
||||
-Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
|
||||
-w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
|
||||
-+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
|
||||
-OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
|
||||
-brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
|
||||
-m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
|
||||
-LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
|
||||
-/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
|
||||
-s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
|
||||
-Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
|
||||
-xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
|
||||
-ZboOWVe3icTy64BT3OQhmg==
|
||||
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNnIbv8hgG9JgG
|
||||
+qEYSvRHAF4aoCXMOPx7q/fllHjCMhzfWvpNXbBwUaNn2PO0d4MmRJ7h4tGNiWcvU
|
||||
+ug0MnlBnyW+KkVAfQIygHmhSxucTlr/v9WQL28jLdO8WS2rWcIJAn6OB4BBP5fTh
|
||||
+H3wGXwKLhICdUpBVI2570Z8bSMG9Pn28iQFrvG10F6C1xsOO19v3C06Bdx5A421g
|
||||
+v5isZVM63npjZoDjbMNggnDbm7V2C5+RkvqkK8C7g/UyEvASJFc/YxiHCuexAO4L
|
||||
+tFa9weirTddsZeLlI3LFATF6usjJgZWGfXBcqsOYkHytzT4jy0/9Q5piZX0HfHjh
|
||||
+hBkjx6QFAgMBAAECggEAGpX0tK3fAXc6+RFlDiM4WlgwZyXhpKPwwX3Zc4O1z1Xk
|
||||
+mHXH43PtJY5xMG+sUUKxjX1PUvwwJZVqz7TG3yzRRLo9G/OyInhcNo/3+UwSsOu7
|
||||
+IbHfH9FpYzVZfM5/n/6oOObrY22vbkVTppBFnyVF1PhrEOyOERQlwwjVw9diha+F
|
||||
+icv32fCm2KLH1KKn8sn9Gl/Ru/ja0eI8vFZ2pjpA/vRr9peSqyZ9XSo3VkJ1AZ7B
|
||||
+uqkiyYBn+w35HqHtqgqGIrJO4i1WUXAuhTc0Z4P6FUukbzrnWww48JjQoBXIRTI9
|
||||
+/7FNGToTThTz6XxIaYvpvKvg8uGHt9BKmZAH1NBqgQKBgQDlSoUSh8Ftl420yPWO
|
||||
+p8pyzkLwAg9cqtUJZKT6US6p0WXfTAa6GpIwxuYYCfG4yWMTUTeeN9Jxb4KLRHTr
|
||||
+wLMJZXmFVtm0CWWl/KsL0pRwdAziGh7Zq3jEDOUHWr2CzqCPuIIA0CfY5t/uSwLV
|
||||
+TQyn42lqWLtB9wrVAj9LgL5d0QKBgQDlj+C4CCgrgZ4l8i4OAj5LPYoSncdglu46
|
||||
+dXOl41APyZ36Z1Lt6jsrO07AmztRzdYQWOv2iSIZ9lTJy+58y/gJHd8ijO4uUHc2
|
||||
+QMU17l5NGQ1OqAiat+WnJFRwbUEdSaa92KMjV9magwmdmTkppQJZS6ZrSXRB6VoQ
|
||||
+VKVfdynr9QKBgQCka0p/Xi/bOWkZMV28nR90MeoYFzIS3kGDydLv2NUgWxK1C9xr
|
||||
+CXC5X3dR15epTWgpSv0aDKdwRmkTGtTI1VbNLyHz9rKIApEMdOHmyWs+NEmkvNxQ
|
||||
+dEBWPXTiUDRDH45NYR6AHMPmKrB7PPjcIbMolM9bviMRi2gOFN10c+6OcQKBgHxN
|
||||
+pzIfgJjmS9tiQtvlDRQy03P3KYG82GyhMqkN6ElUNA3mKvqXDckACUm0BK/sFFCv
|
||||
+xb2uTd/fCdRnb9D1pW5SVYPg6gv8GEExW1gzpa57tT/1LwuQLnON8YcbMdoJCpfc
|
||||
+GaJGrJbFA8zprhFFv3rYwtlvYdta3yDepNmHrhSNAoGBAJeNGksK7Zj4J10Lx+0W
|
||||
+O++BysvZX8h4VbH/vZUoNrc/vadGg2Z0jhz3XVtTigR4gr77+q5WrbovVraPamK5
|
||||
+TLS+4PJfBPT0DC9jyUf25C5CFYj3Z9+PH+DC6LI/ZVD8pf9JJ2JKOxfT4gKec/Hs
|
||||
+YuMxrufDlB4Ac6Z95KfoT1lz
|
||||
-----END RSA TESTING KEY-----`))
|
||||
|
||||
func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
|
||||
|
||||
76
backport-0031-CVE-2025-22870.patch
Normal file
76
backport-0031-CVE-2025-22870.patch
Normal file
@ -0,0 +1,76 @@
|
||||
From 334de7982f8ec959c74470dd709ceedfd6dbd50a Mon Sep 17 00:00:00 2001
|
||||
From: Damien Neil <dneil@google.com>
|
||||
Date: Wed, 26 Feb 2025 16:46:43 -0800
|
||||
Subject: [PATCH] [release-branch.go1.24] all: updated vendored x/net with
|
||||
security fix
|
||||
|
||||
6ed00d0 [internal-branch.go1.24-vendor] proxy, http/httpproxy: do not mismatch IPv6 zone ids against hosts
|
||||
|
||||
Fixes CVE-2025-22870
|
||||
For #71986
|
||||
|
||||
Change-Id: I7bda0825f1a9470b0708714d9cc32b5eae212f8b
|
||||
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/2121
|
||||
Reviewed-by: Neal Patel <nealpatel@google.com>
|
||||
Reviewed-by: Roland Shoemaker <bracewell@google.com>
|
||||
Commit-Queue: Roland Shoemaker <bracewell@google.com>
|
||||
Reviewed-on: https://go-review.googlesource.com/c/go/+/654715
|
||||
Reviewed-by: Michael Pratt <mpratt@google.com>
|
||||
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
|
||||
Auto-Submit: Junyang Shao <shaojunyang@google.com>
|
||||
Reviewed-by: Damien Neil <dneil@google.com>
|
||||
---
|
||||
src/cmd/internal/moddeps/moddeps_test.go | 1 +
|
||||
src/vendor/golang.org/x/net/http/httpproxy/proxy.go | 10 ++++++++--
|
||||
2 files changed, 9 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
|
||||
index ae890b6..9dc4741 100644
|
||||
--- a/src/cmd/internal/moddeps/moddeps_test.go
|
||||
+++ b/src/cmd/internal/moddeps/moddeps_test.go
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
// See issues 36852, 41409, and 43687.
|
||||
// (Also see golang.org/issue/27348.)
|
||||
func TestAllDependencies(t *testing.T) {
|
||||
+ t.Skip("TODO(#71986): 1.24.1 contains unreleased changes from vendored modules")
|
||||
goBin := testenv.GoToolPath(t)
|
||||
|
||||
// Ensure that all packages imported within GOROOT
|
||||
diff --git a/src/vendor/golang.org/x/net/http/httpproxy/proxy.go b/src/vendor/golang.org/x/net/http/httpproxy/proxy.go
|
||||
index c3bd9a1..334add3 100644
|
||||
--- a/src/vendor/golang.org/x/net/http/httpproxy/proxy.go
|
||||
+++ b/src/vendor/golang.org/x/net/http/httpproxy/proxy.go
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
+ "net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
@@ -180,8 +181,10 @@ func (cfg *config) useProxy(addr string) bool {
|
||||
if host == "localhost" {
|
||||
return false
|
||||
}
|
||||
- ip := net.ParseIP(host)
|
||||
- if ip != nil {
|
||||
+ nip, err := netip.ParseAddr(host)
|
||||
+ var ip net.IP
|
||||
+ if err == nil {
|
||||
+ ip = net.IP(nip.AsSlice())
|
||||
if ip.IsLoopback() {
|
||||
return false
|
||||
}
|
||||
@@ -363,6 +366,9 @@ type domainMatch struct {
|
||||
}
|
||||
|
||||
func (m domainMatch) match(host, port string, ip net.IP) bool {
|
||||
+ if ip != nil {
|
||||
+ return false
|
||||
+ }
|
||||
if strings.HasSuffix(host, m.host) || (m.matchHost && host == m.host[1:]) {
|
||||
return m.port == "" || m.port == port
|
||||
}
|
||||
--
|
||||
2.46.0
|
||||
|
||||
38
golang.spec
38
golang.spec
@ -66,7 +66,7 @@
|
||||
|
||||
Name: golang
|
||||
Version: 1.21.4
|
||||
Release: 27
|
||||
Release: 32
|
||||
Summary: The Go Programming Language
|
||||
License: BSD and Public Domain
|
||||
URL: https://golang.org/
|
||||
@ -146,6 +146,12 @@ Patch6022: backport-0022-release-branch.go1.21-fix-CVE-2024-34156.patch
|
||||
Patch6023: backport-0023-go-build-constraint-add-parsing-limits.patch
|
||||
Patch6024: backport-0024-release-branch.go1.21-runtime-add-the-disablethp-GOD.patch
|
||||
Patch6025: backport-0025-release-branch.go1.21-runtime-put-ReadMemStats-debug.patch
|
||||
Patch6026: backport-0026-release-branch.go1.21-runtime-add-race-annotations-i.patch
|
||||
Patch6027: backport-0027-crypto-tls-fix-Config.Time-in-tests-using-expired-ce.patch
|
||||
Patch6028: backport-0028-release-branch.go1.21-runtime-allow-update-of-system.patch
|
||||
Patch6029: backport-0029-CVE-2024-45341-crypto-x509-properly-check-for-IPv6-h.patch
|
||||
Patch6030: backport-0030-CVE-2024-45336-net-http-persist-header-stripping-acr.patch
|
||||
Patch6031: backport-0031-CVE-2025-22870.patch
|
||||
|
||||
ExclusiveArch: %{golang_arches}
|
||||
|
||||
@ -384,6 +390,36 @@ fi
|
||||
%files devel -f go-tests.list -f go-misc.list -f go-src.list
|
||||
|
||||
%changelog
|
||||
* Thu Mar 20 2025 changtao <changtao@kylinos.cn> - 1.21.4-32
|
||||
- Type:CVE
|
||||
- CVE:CVE-2025-22870
|
||||
- SUG:NA
|
||||
- DESC:fix CVE-2025-22870
|
||||
|
||||
* Thu Feb 20 2025 wujichao <wujichao1@huawei.com> - 1.21.4-31
|
||||
- Type:CVE
|
||||
- CVE:CVE-2024-45341 CVE-2024-45336
|
||||
- SUG:NA
|
||||
- DESC:fix CVE-2024-45341 CVE-2024-45336
|
||||
|
||||
* Sun Jan 26 2025 Vanient <xiadanni1@huawei.com> - 1.21.4-30
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC: allow update of system stack bounds on callback from C thread
|
||||
|
||||
* Thu Jan 16 2025 wangshuo <wangshuo@kylinos.cn> - 1.21.4-29
|
||||
- Type:bugfix
|
||||
- ID:NA
|
||||
- SUG:NA
|
||||
- DESC:crypto/tls: fix Config.Time in tests using expired certificates
|
||||
|
||||
* Fri Dec 06 2024 Vanient <xiadanni1@huawei.com> - 1.21.4-28
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC:add race annotations in IncNonDefault
|
||||
|
||||
* Thu Dec 05 2024 hewenliang <314264452@qq.com> - 1.21.4-27
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user