Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
676e9140f9
!494 [sync] PR-490: fix CVE-2025-22870
From: @openeuler-sync-bot 
Reviewed-by: @hcnbxx 
Signed-off-by: @hcnbxx
2025-04-01 09:27:57 +00:00
changtao
3672fe114c fix CVE-2025-22870
(cherry picked from commit 4a46991579827fc2758c72a618bd81b4661cf0aa)
2025-04-01 09:56:16 +08:00
openeuler-ci-bot
b4d68e2725
!475 [Backport]fix CVE-2024-45341 CVE-2024-45336
From: @wu-jichao123 
Reviewed-by: @hcnbxx 
Signed-off-by: @hcnbxx
2025-02-24 02:56:32 +00:00
wujichao
dbe4d8bce5 [Backport]fix CVE-2024-45341 CVE-2024-45336 2025-02-20 10:40:09 +08:00
openeuler-ci-bot
4d8b952107
!468 [sync] PR-467: [Backport]golang:allow update of system stack bounds on callback from C thread
From: @openeuler-sync-bot 
Reviewed-by: @hcnbxx 
Signed-off-by: @hcnbxx
2025-01-26 09:17:43 +00:00
Vanient
28875f707c [Backport]golang:allow update of system stack bounds on callback from C thread
Conflict:NA
Reference:https://go-review.googlesource.com/c/go/+/527715

Signed-off-by: Vanient <xiadanni1@huawei.com>
(cherry picked from commit 4c90ff3bda0159f2ce04595e25c0ca2f0f881e27)
2025-01-26 10:47:44 +08:00
openeuler-ci-bot
1b23503dc7
!464 [sync] PR-463: [Backport]crypto/tls: fix Config.Time in tests using expired certificates
From: @openeuler-sync-bot 
Reviewed-by: @hcnbxx 
Signed-off-by: @hcnbxx
2025-01-26 01:39:48 +00:00
wangshuo
d7448dbe57 [Backport]crypto/tls: fix Config.Time in tests using expired certificates
(cherry picked from commit 727b3ef66b2fd50d42edc7a99fa3c6dae07fa872)
2025-01-23 15:36:29 +08:00
openeuler-ci-bot
7c5b3dc61e
!457 [sync] PR-456: [Backport]golang:add race annotations in IncNonDefault
From: @openeuler-sync-bot 
Reviewed-by: @hcnbxx 
Signed-off-by: @hcnbxx
2024-12-09 02:19:57 +00:00
Vanient
2ce91ac6b0 [Backport]golang:add race annotations in IncNonDefault
reason:add race annotations in IncNonDefault

Signed-off-by: Vanient <xiadanni1@huawei.com>
(cherry picked from commit 550dafd8720b312651cc44c931484ff205ddd5b6)
2024-12-09 09:45:45 +08:00
7 changed files with 1358 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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())
}

View File

@ -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") }

View 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

View File

@ -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