From patchwork Thu Feb 12 04:58:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 80945 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2419FEDF034 for ; Thu, 12 Feb 2026 04:59:02 +0000 (UTC) Received: from alln-iport-5.cisco.com (alln-iport-5.cisco.com [173.37.142.92]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.38401.1770872334994029811 for ; Wed, 11 Feb 2026 20:58:55 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=iBha0SlP; spf=pass (domain: cisco.com, ip: 173.37.142.92, mailfrom: deeratho@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=19877; q=dns/txt; s=iport01; t=1770872335; x=1772081935; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=QS1JpkG+Sro42mg7o03YdBJ6O/38+ssJKYVq82gvbZI=; b=iBha0SlPgmuN5uILosbXywl/NN6r2tV6S3Y+kd9IBg86s4KZVi6tgUS8 yZjgaG6yLuAyM4kfoI6QtxqfoTFyY65poXG0ntVKCutzXdTUhnDxV+dxh haor9gp+sUP/90TRSjj2JKjhiPaMklogV3q2RxuErVw1jcCrpmPcPkcuA AWNmUXC2O0QKYHu8nWsr2fV6Vx2tvKIjl96bHbZgyPhSnOs9lMFfPsFSK aoKHCcu86/AwDMP7ByGz1MnXGMdlBhs28YySDktHV0hPjalDSiqHWWZkC YFsbYrit8dorrrgO/2ulgXmDdxX+cujjty1KoiUNKnLLx855c2cEFarOD Q==; X-CSE-ConnectionGUID: 74V4lFNbRKeire/1FiwYDQ== X-CSE-MsgGUID: px0FOccCSByE8oT/5zTHEw== X-IPAS-Result: A0CgBgCfXI1p/47/Ja1aglmCSA9xX0JJA5QngiGBFopRkjaBfw8BAQEPPRQEAQGFBwKNHQImNAkOAQIEAQEBAQMCAwEBAQEBAQEBAQEBCwEBBQEBAQIBBwWBDhOGTw2GWgE4AXIDAQJPCyMhgwIBgjoDNgIBEahQgiyBAYNiAQUCQ0/YRw2CUgELFAGBOIU7gnmFH1sYAYNZgR8IHxsbgXKBFYJydoEFgRpCAQGBSIZcBIIigQ6BZDaRVEiBHgNZLAFVEw0KCwcFgWYDNRIqFW4yHYEjPheBCxsHBYgVD4kPeHCBIHIDCxgNSBEsNxQbBD5uB45LQYEvERtGEQEBFV4HEwErBBMYJUc/Eh0KARgGSJJXEAOSPKAdcQoog3SMHo8+hXwaM4QElBWSUguYe44JhAmEcIxnJkqEaIFoPDmBDgsHcBWDIglJGQ+OLAwLg16BBHu/YyI1AgQ2AgcLAQEDCZNnAQE IronPort-Data: A9a23:ld77gaj/pWG1xzrEmoPk5HPoX161MREKZh0ujC45NGQN5FlHY01je htvXjqFM/yCY2KgfIx/YNu/9U4Hu5LWyYI2HFc5r3wxRi5jpJueD7x1DKtf0wB+jyHnZBg6h ynLQoCYdKjYdleF+FH1dOOn9SUgvU2xbuKUIPbePSxsThNTRi4kiBZy88Y0mYcAbeKRW2thg vus5ZeGULOZ82QsaDxMsfvZ8EoHUMna4Vv0gHRvPZing3eG/5UlJMp3Db28KXL+Xr5VEoaSL 87fzKu093/u5BwkDNWoiN7TKiXmlZaLYGBiIlIPM0STqkAqSh4ai87XB9JAAatjsAhlqvgqo Dl7WTNcfi9yVkHEsLx1vxC1iEiSN4UekFPMCSDXXcB+UyQqflO0q8iCAn3aMqVHptgrBU9o/ 8Y7JTEXY1faqeOp8Z6CH7wEasQLdKEHPasFsX1miDWcBvE8TNWbHuPB5MRT23E7gcUm8fT2P pVCL2EwKk6dPlsWZg1/5JEWxI9EglHzfjBCoU6VooI84nPYy0p6172F3N/9JILXFJQFxBfFz o7A13zpWj89P9e08hCU3yKruqiSjx/bdZ1HQdVU8dYv2jV/3Fc7DwUbU1a+q/S1hkOyHtlYM UE8/is1sbN081SmSNT4VRC0rHOI+BkGVLJt//YS8gqBzO/Qpg2eHGVBFmMHY909v8hwTjsvv rOUo+7U6fVUmOX9YRqgGn289Fte5QB9wbc+WBI5 IronPort-HdrOrdr: A9a23:useDu67fyh0W5W9/1QPXwN3XdLJyesId70hD6qkXc202TiX2ra 6TdZgguCMc6wxhO03I++rgBEDoexq1nvRICOIqUotKMjOLhILRFuFfBU+I+UyFJ8U4ndQtsJ tdTw== X-Talos-CUID: 9a23:yZiP5G9VJDmSoGOLJ/GVvxFIJJwhXFvX9lTdIlW1Tj9HSaKkZWbFrQ== X-Talos-MUID: 9a23:H5U7ww6vH9yf5gqGbsAxTbq5xoxw8/yAL0sGuq4squTUMhA3ZiWhrBmoF9o= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.21,286,1763424000"; d="scan'208";a="665998295" Received: from rcdn-l-core-05.cisco.com ([173.37.255.142]) by alln-iport-5.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 12 Feb 2026 04:58:53 +0000 Received: from sjc-ads-3552.cisco.com (sjc-ads-3552.cisco.com [171.68.249.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-05.cisco.com (Postfix) with ESMTPS id 742F518000223 for ; Thu, 12 Feb 2026 04:58:53 +0000 (GMT) Received: by sjc-ads-3552.cisco.com (Postfix, from userid 1795984) id 1B838CC12B5; Wed, 11 Feb 2026 20:58:53 -0800 (PST) From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Subject: [openembedded-core] [scarthgap] [PATCH 1/5] go 1.22.12: Fix CVE-2025-61730 Date: Wed, 11 Feb 2026 20:58:01 -0800 Message-ID: <20260212045843.4046769-1-deeratho@cisco.com> X-Mailer: git-send-email 2.44.4 MIME-Version: 1.0 X-Outbound-SMTP-Client: 171.68.249.250, sjc-ads-3552.cisco.com X-Outbound-Node: rcdn-l-core-05.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 12 Feb 2026 04:59:02 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/231005 From: Deepak Rathore Upstream Repository: https://github.com/golang/go.git Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-61730 Type: Security Fix CVE: CVE-2025-61730 Score: 4.2 Patch: https://github.com/golang/go/commit/ad2cd043db66 Signed-off-by: Deepak Rathore diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index ca5016c2f5..e9a1803252 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -31,6 +31,7 @@ SRC_URI += "\ file://CVE-2025-61724.patch \ file://CVE-2025-61727.patch \ file://CVE-2025-61729.patch \ + file://CVE-2025-61730.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61730.patch b/meta/recipes-devtools/go/go/CVE-2025-61730.patch new file mode 100644 index 0000000000..b7234e6bf2 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61730.patch @@ -0,0 +1,460 @@ +From 2cfa797798cc982973d194eca3be19fb1f092556 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker +Date: Mon, 24 Nov 2025 14:03:10 -0800 +Subject: [PATCH] [release-branch.go1.24] crypto/tls: reject trailing messages + after client/server hello + +For TLS 1.3, after procesesing the server/client hello, if there isn't a +CCS message, reject the trailing messages which were appended to the +hello messages. This prevents an on-path attacker from injecting +plaintext messages into the handshake. + +Additionally, check that we don't have any buffered messages before we +switch the read traffic secret regardless, since any buffered messages +would have been under an old key which is no longer appropriate. + +We also invert the ordering of setting the read/write secrets so that if +we fail when changing the read secret we send the alert using the +correct write secret. + +Updates #76443 +Fixes #76854 +Fixes CVE-2025-61730 + +CVE: CVE-2025-61730 +Upstream-Status: Backport [https://github.com/golang/go/commit/ad2cd043db66] + +Backport Changes: +- In version 1.24, the doHelloRetryRequest function defined in handshake_server_tls13.go + returns keyshare and error, but in version 1.22 it only returns error. The backport + was adjusted accordingly and These changes were introduced by commit + https://github.com/golang/go/commit/d0edd9acc80a in version 1.24. +- In file src/crypto/tls/handshake_server_tls13.go, Replaced the function call + hs.handshakeSecret.ClientHandshakeTrafficSecret(hs.transcript) with + hs.suite.deriveSecret(hs.handshakeSecret, clientHandshakeTrafficLabel, hs.transcript). + This change is not present in version v1.22 and it was introduced by commit + https://github.com/golang/go/commit/743746a3a52d in version 1.24. + +Change-Id: If6ba8ad16f48d5cd5db5574824062ad4244a5b52 +Reviewed-on: https://go-review.googlesource.com/c/go/+/724120 +LUCI-TryBot-Result: Go LUCI +Reviewed-by: Michael Knyszek +Reviewed-by: Daniel McCarney +Reviewed-by: Coia Prant +(cherry picked from commit 5046bdf8a612b35a2c1a9e168054c1d5c65e7dd7) +Reviewed-on: https://go-review.googlesource.com/c/go/+/731961 +Reviewed-by: Damien Neil +(cherry picked from commit ad2cd043db66cd36e1f55359638729d2c8ff3d99) +Signed-off-by: Deepak Rathore +--- + src/crypto/tls/conn.go | 39 ++++++- + src/crypto/tls/handshake_client_tls13.go | 22 ++-- + src/crypto/tls/handshake_server_tls13.go | 39 ++++--- + src/crypto/tls/handshake_test.go | 140 +++++++++++++++++++++++ + src/crypto/tls/quic.go | 11 +- + 5 files changed, 219 insertions(+), 32 deletions(-) + +diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go +index 0e4669866e..08609ce17b 100644 +--- a/src/crypto/tls/conn.go ++++ b/src/crypto/tls/conn.go +@@ -225,6 +225,9 @@ func (hc *halfConn) changeCipherSpec() error { + return nil + } + ++// setTrafficSecret sets the traffic secret for the given encryption level. setTrafficSecret ++// should not be called directly, but rather through the Conn setWriteTrafficSecret and ++// setReadTrafficSecret wrapper methods. + func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) { + hc.trafficSecret = secret + hc.level = level +@@ -1321,9 +1324,6 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error { + return c.in.setErrorLocked(c.sendAlert(alertInternalError)) + } + +- newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret) +- c.in.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret) +- + if keyUpdate.updateRequested { + c.out.Lock() + defer c.out.Unlock() +@@ -1341,7 +1341,12 @@ func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error { + } + + newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret) +- c.out.setTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret) ++ c.setWriteTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret) ++ } ++ ++ newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret) ++ if err := c.setReadTrafficSecret(cipherSuite, QUICEncryptionLevelInitial, newSecret); err != nil { ++ return err + } + + return nil +@@ -1572,7 +1577,9 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) { + // Provide the 1-RTT read secret now that the handshake is complete. + // The QUIC layer MUST NOT decrypt 1-RTT packets prior to completing + // the handshake (RFC 9001, Section 5.7). +- c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret) ++ if err := c.quicSetReadSecret(QUICEncryptionLevelApplication, c.cipherSuite, c.in.trafficSecret); err != nil { ++ return err ++ } + } else { + var a alert + c.out.Lock() +@@ -1664,3 +1671,25 @@ func (c *Conn) VerifyHostname(host string) error { + } + return c.peerCertificates[0].VerifyHostname(host) + } ++ ++// setReadTrafficSecret sets the read traffic secret for the given encryption level. If ++// being called at the same time as setWriteTrafficSecret, the caller must ensure the call ++// to setWriteTrafficSecret happens first so any alerts are sent at the write level. ++func (c *Conn) setReadTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) error { ++ // Ensure that there are no buffered handshake messages before changing the ++ // read keys, since that can cause messages to be parsed that were encrypted ++ // using old keys which are no longer appropriate. ++ if c.hand.Len() != 0 { ++ c.sendAlert(alertUnexpectedMessage) ++ return errors.New("tls: handshake buffer not empty before setting read traffic secret") ++ } ++ c.in.setTrafficSecret(suite, level, secret) ++ return nil ++} ++ ++// setWriteTrafficSecret sets the write traffic secret for the given encryption level. If ++// being called at the same time as setReadTrafficSecret, the caller must ensure the call ++// to setWriteTrafficSecret happens first so any alerts are sent at the write level. ++func (c *Conn) setWriteTrafficSecret(suite *cipherSuiteTLS13, level QUICEncryptionLevel, secret []byte) { ++ c.out.setTrafficSecret(suite, level, secret) ++} +diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go +index 2f59f6888c..68ff92beda 100644 +--- a/src/crypto/tls/handshake_client_tls13.go ++++ b/src/crypto/tls/handshake_client_tls13.go +@@ -393,17 +393,18 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { + + clientSecret := hs.suite.deriveSecret(handshakeSecret, + clientHandshakeTrafficLabel, hs.transcript) +- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret) ++ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret) + serverSecret := hs.suite.deriveSecret(handshakeSecret, + serverHandshakeTrafficLabel, hs.transcript) +- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret) ++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret); err != nil { ++ return err ++ } + + if c.quic != nil { +- if c.hand.Len() != 0 { +- c.sendAlert(alertUnexpectedMessage) +- } + c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret) +- c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret) ++ if err := c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret); err != nil { ++ return err ++ } + } + + err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret) +@@ -606,7 +607,9 @@ func (hs *clientHandshakeStateTLS13) readServerFinished() error { + clientApplicationTrafficLabel, hs.transcript) + serverSecret := hs.suite.deriveSecret(hs.masterSecret, + serverApplicationTrafficLabel, hs.transcript) +- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret) ++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret); err != nil { ++ return err ++ } + + err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret) + if err != nil { +@@ -702,7 +705,7 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error { + return err + } + +- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret) ++ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret) + + if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil { + c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret, +@@ -710,9 +713,6 @@ func (hs *clientHandshakeStateTLS13) sendClientFinished() error { + } + + if c.quic != nil { +- if c.hand.Len() != 0 { +- c.sendAlert(alertUnexpectedMessage) +- } + c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, hs.trafficSecret) + } + +diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go +index 21d798de37..5aa69e9640 100644 +--- a/src/crypto/tls/handshake_server_tls13.go ++++ b/src/crypto/tls/handshake_server_tls13.go +@@ -380,7 +380,9 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error { + return err + } + earlyTrafficSecret := hs.suite.deriveSecret(hs.earlySecret, clientEarlyTrafficLabel, transcript) +- c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret) ++ if err := c.quicSetReadSecret(QUICEncryptionLevelEarly, hs.suite.id, earlyTrafficSecret); err != nil { ++ return err ++ } + } + + c.didResume = true +@@ -477,6 +479,14 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { + func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { + c := hs.c + ++ // Make sure the client didn't send extra handshake messages alongside ++ // their initial client_hello. If they sent two client_hello messages, ++ // we will consume the second before they respond to the server_hello. ++ if c.hand.Len() != 0 { ++ c.sendAlert(alertUnexpectedMessage) ++ return errors.New("tls: handshake buffer not empty before HelloRetryRequest") ++ } ++ + // The first ClientHello gets double-hashed into the transcript upon a + // HelloRetryRequest. See RFC 8446, Section 4.4.1. + if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { +@@ -615,19 +625,20 @@ func (hs *serverHandshakeStateTLS13) sendServerParameters() error { + hs.handshakeSecret = hs.suite.extract(hs.sharedKey, + hs.suite.deriveSecret(earlySecret, "derived", nil)) + +- clientSecret := hs.suite.deriveSecret(hs.handshakeSecret, +- clientHandshakeTrafficLabel, hs.transcript) +- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret) + serverSecret := hs.suite.deriveSecret(hs.handshakeSecret, + serverHandshakeTrafficLabel, hs.transcript) +- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret) ++ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, serverSecret) ++ clientSecret := hs.suite.deriveSecret(hs.handshakeSecret, ++ clientHandshakeTrafficLabel, hs.transcript) ++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelHandshake, clientSecret); err != nil { ++ return err ++ } + + if c.quic != nil { +- if c.hand.Len() != 0 { +- c.sendAlert(alertUnexpectedMessage) +- } + c.quicSetWriteSecret(QUICEncryptionLevelHandshake, hs.suite.id, serverSecret) +- c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret) ++ if err := c.quicSetReadSecret(QUICEncryptionLevelHandshake, hs.suite.id, clientSecret); err != nil { ++ return err ++ } + } + + err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret) +@@ -751,13 +762,9 @@ func (hs *serverHandshakeStateTLS13) sendServerFinished() error { + clientApplicationTrafficLabel, hs.transcript) + serverSecret := hs.suite.deriveSecret(hs.masterSecret, + serverApplicationTrafficLabel, hs.transcript) +- c.out.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret) ++ c.setWriteTrafficSecret(hs.suite, QUICEncryptionLevelApplication, serverSecret) + + if c.quic != nil { +- if c.hand.Len() != 0 { +- // TODO: Handle this in setTrafficSecret? +- c.sendAlert(alertUnexpectedMessage) +- } + c.quicSetWriteSecret(QUICEncryptionLevelApplication, hs.suite.id, serverSecret) + } + +@@ -992,7 +999,9 @@ func (hs *serverHandshakeStateTLS13) readClientFinished() error { + return errors.New("tls: invalid client finished hash") + } + +- c.in.setTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret) ++ if err := c.setReadTrafficSecret(hs.suite, QUICEncryptionLevelApplication, hs.trafficSecret); err != nil { ++ return err ++ } + + return nil + } +diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go +index 27ab19ef31..4991a0e69b 100644 +--- a/src/crypto/tls/handshake_test.go ++++ b/src/crypto/tls/handshake_test.go +@@ -6,6 +6,7 @@ package tls + + import ( + "bufio" ++ "context" + "crypto/ed25519" + "crypto/x509" + "encoding/hex" +@@ -533,3 +534,142 @@ var clientEd25519KeyPEM = testingKey(` + -----BEGIN TESTING KEY----- + MC4CAQAwBQYDK2VwBCIEINifzf07d9qx3d44e0FSbV4mC/xQxT644RRbpgNpin7I + -----END TESTING KEY-----`) ++ ++func TestServerHelloTrailingMessage(t *testing.T) { ++ // In TLS 1.3 the change cipher spec message is optional. If a CCS message ++ // is not sent, after reading the ServerHello, the read traffic secret is ++ // set, and all following messages must be encrypted. If the server sends ++ // additional unencrypted messages in a record with the ServerHello, the ++ // client must either fail or ignore the additional messages. ++ ++ c, s := localPipe(t) ++ go func() { ++ ctx := context.Background() ++ srv := Server(s, testConfig) ++ clientHello, _, err := srv.readClientHello(ctx) ++ if err != nil { ++ testFatal(t, err) ++ } ++ ++ hs := serverHandshakeStateTLS13{ ++ c: srv, ++ ctx: ctx, ++ clientHello: clientHello, ++ } ++ if err := hs.processClientHello(); err != nil { ++ testFatal(t, err) ++ } ++ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { ++ testFatal(t, err) ++ } ++ ++ record, err := concatHandshakeMessages(hs.hello, &encryptedExtensionsMsg{alpnProtocol: "h2"}) ++ if err != nil { ++ testFatal(t, err) ++ } ++ ++ if _, err := s.Write(record); err != nil { ++ testFatal(t, err) ++ } ++ srv.Close() ++ }() ++ ++ cli := Client(c, testConfig) ++ expectedErr := "tls: handshake buffer not empty before setting read traffic secret" ++ if err := cli.Handshake(); err == nil { ++ t.Fatal("expected error from incomplete handshake, got nil") ++ } else if err.Error() != expectedErr { ++ t.Fatalf("expected error %q, got %q", expectedErr, err.Error()) ++ } ++} ++ ++func TestClientHelloTrailingMessage(t *testing.T) { ++ // Same as TestServerHelloTrailingMessage but for the client side. ++ ++ c, s := localPipe(t) ++ go func() { ++ cli := Client(c, testConfig) ++ ++ hello, _, _, err := cli.makeClientHello() ++ if err != nil { ++ testFatal(t, err) ++ } ++ ++ record, err := concatHandshakeMessages(hello, &certificateMsgTLS13{}) ++ if err != nil { ++ testFatal(t, err) ++ } ++ ++ if _, err := c.Write(record); err != nil { ++ testFatal(t, err) ++ } ++ cli.Close() ++ }() ++ ++ srv := Server(s, testConfig) ++ expectedErr := "tls: handshake buffer not empty before setting read traffic secret" ++ if err := srv.Handshake(); err == nil { ++ t.Fatal("expected error from incomplete handshake, got nil") ++ } else if err.Error() != expectedErr { ++ t.Fatalf("expected error %q, got %q", expectedErr, err.Error()) ++ } ++} ++ ++func TestDoubleClientHelloHRR(t *testing.T) { ++ // If a client sends two ClientHello messages in a single record, and the ++ // server sends a HRR after reading the first ClientHello, the server must ++ // either fail or ignore the trailing ClientHello. ++ ++ c, s := localPipe(t) ++ ++ go func() { ++ cli := Client(c, testConfig) ++ ++ hello, _, _, err := cli.makeClientHello() ++ if err != nil { ++ testFatal(t, err) ++ } ++ hello.keyShares = nil ++ ++ record, err := concatHandshakeMessages(hello, hello) ++ if err != nil { ++ testFatal(t, err) ++ } ++ ++ if _, err := c.Write(record); err != nil { ++ testFatal(t, err) ++ } ++ cli.Close() ++ }() ++ ++ srv := Server(s, testConfig) ++ expectedErr := "tls: handshake buffer not empty before HelloRetryRequest" ++ if err := srv.Handshake(); err == nil { ++ t.Fatal("expected error from incomplete handshake, got nil") ++ } else if err.Error() != expectedErr { ++ t.Fatalf("expected error %q, got %q", expectedErr, err.Error()) ++ } ++} ++ ++// concatHandshakeMessages marshals and concatenates the given handshake ++// messages into a single record. ++func concatHandshakeMessages(msgs ...handshakeMessage) ([]byte, error) { ++ var marshalled []byte ++ for _, msg := range msgs { ++ data, err := msg.marshal() ++ if err != nil { ++ return nil, err ++ } ++ marshalled = append(marshalled, data...) ++ } ++ m := len(marshalled) ++ outBuf := make([]byte, recordHeaderLen) ++ outBuf[0] = byte(recordTypeHandshake) ++ vers := VersionTLS12 ++ outBuf[1] = byte(vers >> 8) ++ outBuf[2] = byte(vers) ++ outBuf[3] = byte(m >> 8) ++ outBuf[4] = byte(m) ++ outBuf = append(outBuf, marshalled...) ++ return outBuf, nil ++} +diff --git a/src/crypto/tls/quic.go b/src/crypto/tls/quic.go +index 3518169bf7..aa14f1dadb 100644 +--- a/src/crypto/tls/quic.go ++++ b/src/crypto/tls/quic.go +@@ -323,13 +323,22 @@ func (c *Conn) quicReadHandshakeBytes(n int) error { + return nil + } + +-func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { ++func (c *Conn) quicSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) error { ++ // Ensure that there are no buffered handshake messages before changing the ++ // read keys, since that can cause messages to be parsed that were encrypted ++ // using old keys which are no longer appropriate. ++ // TODO(roland): we should merge this check with the similar one in setReadTrafficSecret. ++ if c.hand.Len() != 0 { ++ c.sendAlert(alertUnexpectedMessage) ++ return errors.New("tls: handshake buffer not empty before setting read traffic secret") ++ } + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICSetReadSecret, + Level: level, + Suite: suite, + Data: secret, + }) ++ return nil + } + + func (c *Conn) quicSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { +-- +2.35.6 From patchwork Thu Feb 12 04:59:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 80946 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1FE8BEDF035 for ; Thu, 12 Feb 2026 04:59:42 +0000 (UTC) Received: from alln-iport-2.cisco.com (alln-iport-2.cisco.com [173.37.142.89]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.38643.1770872374736070173 for ; Wed, 11 Feb 2026 20:59:34 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=Bf4QhoCR; spf=pass (domain: cisco.com, ip: 173.37.142.89, mailfrom: deeratho@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=8271; q=dns/txt; s=iport01; t=1770872374; x=1772081974; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=WUQSXzkRn8VpgrGOY9XMKtBm090zSDIDLCVRAJk8IOE=; b=Bf4QhoCRsed4sZOjbLKYCyTSWcodleuWCyqCApJLqIiE0m6kEzONiww3 i5o05JGDa5QxCu3DvjukdAtcrxzK0nD/YVvaEIaigfV8RrAybw6rLdh16 I8l0jHiWCzaS2fMRYtxdSVAor9yUS2bg4Slq0Dfmtb7xcNxptbIfBmJzf 9P8Vo7rDFrLmovZUexlbuWsJZbZYxroL0H0hBy/Dc8cQxQD3EUvk/uejt AVaUFpkf/YySGP3TfZ0jbX/QqJoh0++4lhZuPhQh50C5T0JnNpELf5Khy 1UA6Gu0KtW0rmkWK9Eunt5cUU7DTPjJDRRu8jXtjAcv9xW9PdAaMaNLDn w==; X-CSE-ConnectionGUID: jqshLIhPTomLuJEn8Fp2Cw== X-CSE-MsgGUID: WKk2k7K8RaO63bSBD/uwfg== X-IPAS-Result: A0DrAwAcXY1p/4r/Ja1aglmCSA9xX0JJlCqCIZ4dgX8PAQEBDz0UBAEBkiYCJjQJDgECBAEBAQEDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBOAFyAwECWiMhgwIBgnMCARGoT4IsgQGCZnwBBQJDT9smAQsUAYE4hTuIGFsYAYNZgR8nGxuBcoR9gQWBXAEBgS0LhmwEgiKBDoFkNolOiAZIgR4DWSwBVRMNCgsHBYFmAzUSKhVuMh2BIz4XgQsbBwWIFQ+JD3hwgSByAwsYDUgRLDcUGwQ+bgeOS0GBZkwBLSYHIRMBCiABIFsKFngBGJMRFBMRkAqCIZ9QgT4KKIN0jB6VOhozhVulEAuYe44JlgBQhGiBaDw5gQ4LB3AVO4JnCUkZD444g2mBf4IIvVsiNTwCBwsBAQMJkWuBfAEB IronPort-Data: A9a23:wlN3WK+DpmVekCM48DuGDrUD0X+TJUtcMsCJ2f8bNWPcYEJGY0x3y WFODW6FOvffZzP8L4wlPorl9x9Vu5bTnNJrTQBuqylEQiMRo6IpJzg2wmQcns+2BpeeJK6yx 5xGMrEsFOhtEDmE4EzrauS9xZVF/fngbqLmD+LZMTxGSwZhSSMw4TpugOdRbrRA2bBVOCvT/ 4mryyHjEAX9gWAsaDtOs/vrRC5H5ZwehhtJ5jTSWtgT1LPuvyF9JI4SI6i3M0z5TuF8dsamR /zOxa2O5WjQ+REgELuNyt4XpWVTH9Y+lSDX4pZnc/DKbipq/0Te4Y5nXBYoUnq7vh3S9zxHJ HqhgrTrIeshFvWkdO3wyHC0GQkmVUFN0OevzXRSLaV/wmWeG0YAzcmCA2k0JJYY3sd3OV1J8 NgFCh0LPj6b3cmplefTpulE3qzPLeHxN48Z/3UlxjbDALN+GNbIQr7B4plT2zJYasJmRKmFI ZFGL2AyMVKZOE0n1lQ/UPrSmM+ki3TleiFYr3qepLE85C7YywkZPL3FboSPIoDVGZoE9qqej l3l/D76XTJKDtW4l2GPyViAwfLQkyyuDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0W5Qd93L 00P5jFoqrA/8kGuRNTxUxC05nmesXYht8F4CeY27kSJj6HT+QvcXjFCRT9aY9tgv8gzLdA36 mK0cxrSLWQHmNWopbi1r994cRva1fApEFI/ IronPort-HdrOrdr: A9a23:J0Hai6vojJyuAf4BqMcDWQWK7skDY9V00zEX/kB9WHVpm6uj5q KTdZsguyMc5Ax9ZJhCo6HiBEDjexLhHPdOiOF7V4tKNzOIhILHFu1fBPPZowEJ30bFh4pgPW AKSdkaNOHN X-Talos-CUID: 9a23:jXxcxGMeWEtU1+5DWjB89Go1GvgZdXj50VX9JR+WETxCV+jA X-Talos-MUID: 9a23:r1y2AAsafE7dUzr4+82nuxJhbsQ3wPSUAWdTyp89keXDKDN+NGLI X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.21,286,1763424000"; d="scan'208";a="662047479" Received: from rcdn-l-core-01.cisco.com ([173.37.255.138]) by alln-iport-2.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 12 Feb 2026 04:59:33 +0000 Received: from sjc-ads-3552.cisco.com (sjc-ads-3552.cisco.com [171.68.249.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-01.cisco.com (Postfix) with ESMTPS id 708DF180001C1 for ; Thu, 12 Feb 2026 04:59:33 +0000 (GMT) Received: by sjc-ads-3552.cisco.com (Postfix, from userid 1795984) id 060A0CC12B5; Wed, 11 Feb 2026 20:59:33 -0800 (PST) From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Subject: [openembedded-core] [scarthgap] [PATCH 2/5] go 1.22.12: Fix CVE-2025-61726 Date: Wed, 11 Feb 2026 20:59:00 -0800 Message-ID: <20260212045921.4067482-1-deeratho@cisco.com> X-Mailer: git-send-email 2.44.4 MIME-Version: 1.0 X-Outbound-SMTP-Client: 171.68.249.250, sjc-ads-3552.cisco.com X-Outbound-Node: rcdn-l-core-01.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 12 Feb 2026 04:59:42 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/231006 From: Deepak Rathore Upstream Repository: https://github.com/golang/go.git Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-61726 Type: Security Fix CVE: CVE-2025-61726 Score: 7.5 Patch: https://github.com/golang/go/commit/85c794ddce26 Signed-off-by: Deepak Rathore diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index e9a1803252..46f6ef5d8f 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -32,6 +32,7 @@ SRC_URI += "\ file://CVE-2025-61727.patch \ file://CVE-2025-61729.patch \ file://CVE-2025-61730.patch \ + file://CVE-2025-61726.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61726.patch b/meta/recipes-devtools/go/go/CVE-2025-61726.patch new file mode 100644 index 0000000000..ab053ff55c --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61726.patch @@ -0,0 +1,196 @@ +From 85050ca6146f3edb50ded0a352ab9edbd635effc Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Mon, 3 Nov 2025 14:28:47 -0800 +Subject: [PATCH] [release-branch.go1.24] net/url: add urlmaxqueryparams + GODEBUG to limit the number of query parameters + +net/url does not currently limit the number of query parameters parsed by +url.ParseQuery or URL.Query. + +When parsing a application/x-www-form-urlencoded form, +net/http.Request.ParseForm will parse up to 10 MB of query parameters. +An input consisting of a large number of small, unique parameters can +cause excessive memory consumption. + +We now limit the number of query parameters parsed to 10000 by default. +The limit can be adjusted by setting GODEBUG=urlmaxqueryparams=. +Setting urlmaxqueryparams to 0 disables the limit. + +Thanks to jub0bs for reporting this issue. + +Fixes #77101 +Fixes CVE-2025-61726 + +CVE: CVE-2025-61726 +Upstream-Status: Backport [https://github.com/golang/go/commit/85c794ddce26] + +Change-Id: Iee3374c7ee2d8586dbf158536d3ade424203ff66 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3020 +Reviewed-by: Nicholas Husin +Reviewed-by: Neal Patel +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3326 +Reviewed-by: Roland Shoemaker +Reviewed-on: https://go-review.googlesource.com/c/go/+/736702 +Auto-Submit: Michael Pratt +Reviewed-by: Junyang Shao +TryBot-Bypass: Michael Pratt +(cherry picked from commit 85c794ddce26a092b0ea68d0fca79028b5069d5a) +Signed-off-by: Deepak Rathore +--- + doc/godebug.md | 7 +++++ + src/internal/godebugs/table.go | 1 + + src/net/url/url.go | 24 +++++++++++++++++ + src/net/url/url_test.go | 48 ++++++++++++++++++++++++++++++++++ + src/runtime/metrics/doc.go | 5 ++++ + 5 files changed, 85 insertions(+) + +diff --git a/doc/godebug.md b/doc/godebug.md +index ae4f0576b4..635597ea42 100644 +--- a/doc/godebug.md ++++ b/doc/godebug.md +@@ -126,6 +126,13 @@ for example, + see the [runtime documentation](/pkg/runtime#hdr-Environment_Variables) + and the [go command documentation](/cmd/go#hdr-Build_and_test_caching). + ++Go 1.26 added a new `urlmaxqueryparams` setting that controls the maximum number ++of query parameters that net/url will accept when parsing a URL-encoded query string. ++If the number of parameters exceeds the number set in `urlmaxqueryparams`, ++parsing will fail early. The default value is `urlmaxqueryparams=10000`. ++Setting `urlmaxqueryparams=0`bles the limit. To avoid denial of service attacks, ++this setting and default was backported to Go 1.25.4 and Go 1.24.10. ++ + Go 1.23.11 disabled build information stamping when multiple VCS are detected due + to concerns around VCS injection attacks. This behavior can be renabled with the + setting `allowmultiplevcs=1`. +diff --git a/src/internal/godebugs/table.go b/src/internal/godebugs/table.go +index 33dcd81fc3..4ae043053c 100644 +--- a/src/internal/godebugs/table.go ++++ b/src/internal/godebugs/table.go +@@ -52,6 +52,7 @@ var All = []Info{ + {Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "x509sha1", Package: "crypto/x509"}, ++ {Name: "urlmaxqueryparams", Package: "net/url", Changed: 24, Old: "0"}, + {Name: "x509usefallbackroots", Package: "crypto/x509"}, + {Name: "x509usepolicies", Package: "crypto/x509"}, + {Name: "zipinsecurepath", Package: "archive/zip"}, +diff --git a/src/net/url/url.go b/src/net/url/url.go +index d2ae03232f..5219e3c130 100644 +--- a/src/net/url/url.go ++++ b/src/net/url/url.go +@@ -13,6 +13,7 @@ package url + import ( + "errors" + "fmt" ++ "internal/godebug" + "net/netip" + "path" + "sort" +@@ -958,7 +959,30 @@ func ParseQuery(query string) (Values, error) { + return m, err + } + ++var urlmaxqueryparams = godebug.New("urlmaxqueryparams") ++ ++const defaultMaxParams = 10000 ++ ++func urlParamsWithinMax(params int) bool { ++ withinDefaultMax := params <= defaultMaxParams ++ if urlmaxqueryparams.Value() == "" { ++ return withinDefaultMax ++ } ++ customMax, err := strconv.Atoi(urlmaxqueryparams.Value()) ++ if err != nil { ++ return withinDefaultMax ++ } ++ withinCustomMax := customMax == 0 || params < customMax ++ if withinDefaultMax != withinCustomMax { ++ urlmaxqueryparams.IncNonDefault() ++ } ++ return withinCustomMax ++} ++ + func parseQuery(m Values, query string) (err error) { ++ if !urlParamsWithinMax(strings.Count(query, "&") + 1) { ++ return errors.New("number of URL query parameters exceeded limit") ++ } + for query != "" { + var key string + key, query, _ = strings.Cut(query, "&") +diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go +index fef236e40a..b2f8bd95fc 100644 +--- a/src/net/url/url_test.go ++++ b/src/net/url/url_test.go +@@ -1488,6 +1488,54 @@ func TestParseQuery(t *testing.T) { + } + } + ++func TestParseQueryLimits(t *testing.T) { ++ for _, test := range []struct { ++ params int ++ godebug string ++ wantErr bool ++ }{{ ++ params: 10, ++ wantErr: false, ++ }, { ++ params: defaultMaxParams, ++ wantErr: false, ++ }, { ++ params: defaultMaxParams + 1, ++ wantErr: true, ++ }, { ++ params: 10, ++ godebug: "urlmaxqueryparams=9", ++ wantErr: true, ++ }, { ++ params: defaultMaxParams + 1, ++ godebug: "urlmaxqueryparams=0", ++ wantErr: false, ++ }} { ++ t.Setenv("GODEBUG", test.godebug) ++ want := Values{} ++ var b strings.Builder ++ for i := range test.params { ++ if i > 0 { ++ b.WriteString("&") ++ } ++ p := fmt.Sprintf("p%v", i) ++ b.WriteString(p) ++ want[p] = []string{""} ++ } ++ query := b.String() ++ got, err := ParseQuery(query) ++ if gotErr, wantErr := err != nil, test.wantErr; gotErr != wantErr { ++ t.Errorf("GODEBUG=%v ParseQuery(%v params) = %v, want error: %v", test.godebug, test.params, err, wantErr) ++ } ++ if err != nil { ++ continue ++ } ++ if got, want := len(got), test.params; got != want { ++ t.Errorf("GODEBUG=%v ParseQuery(%v params): got %v params, want %v", test.godebug, test.params, got, want) ++ } ++ } ++} ++ + type RequestURITest struct { + url *URL + out string +diff --git a/src/runtime/metrics/doc.go b/src/runtime/metrics/doc.go +index 517ec0e0a4..335f7873b3 100644 +--- a/src/runtime/metrics/doc.go ++++ b/src/runtime/metrics/doc.go +@@ -328,6 +328,11 @@ Below is the full list of supported metrics, ordered lexicographically. + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tlsunsafeekm=... setting. + ++ /godebug/non-default-behavior/urlmaxqueryparams:events ++ The number of non-default behaviors executed by the net/url ++ package due to a non-default GODEBUG=urlmaxqueryparams=... ++ setting. ++ + /godebug/non-default-behavior/x509sha1:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509sha1=... setting. +-- +2.35.6 From patchwork Thu Feb 12 04:59:43 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 80947 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2377AEDF036 for ; Thu, 12 Feb 2026 05:00:22 +0000 (UTC) Received: from alln-iport-6.cisco.com (alln-iport-6.cisco.com [173.37.142.93]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.38435.1770872418020270786 for ; Wed, 11 Feb 2026 21:00:18 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=LztVWgSW; spf=pass (domain: cisco.com, ip: 173.37.142.93, mailfrom: deeratho@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5772; q=dns/txt; s=iport01; t=1770872418; x=1772082018; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=Hc0lQcYiZDA+FtqvbtUfE8dKRnahrV/zDdA+QrCXqTQ=; b=LztVWgSW8M9CFN8BNeIf+wezdKZCIP4ONyuqDjL3Vxr5XGFmDhQjdNPY rHevvxP9I/hTC9+7pGMk84vGqqRHOgzi3aJL2PHza8Y/KwRbbGQsGmYAQ MfWHMczG9cWTg6+02RTFn8EdqVrrFHIVNhQGQ2JhycN1Lba6P/wgfXbtU /YBARRQgMV+niiP16j8sbFmlOwF+4kTAniyjjO4F0R5CWEZrY2vphFYwx jlVaDKx06SFffe86rXK9rKjxCPslVe0Bb3hUYEXJTzZxc4OBMkB7cEEge Oh34+Po9ym8hGrgTO7d8FXLWwTvoOwfVRyjf4F+7KzYWYaHReNFQSTbk/ Q==; X-CSE-ConnectionGUID: 5yujJAsESLWB6dexFSGaRg== X-CSE-MsgGUID: 7a7J1lYbTgWDVhPAo/c/Jg== X-IPAS-Result: A0DxAwAcXY1p/47/Ja1agQmBUIJID3FfQkmEV49TgiGeHYF/DwEBAQ89FAQBAZImAiY0CQ4BAgQBAQEBAwIDAQEBAQEBAQEBAQELAQEFAQEBAgEHBYEOE4ZPDYZaASkPAXIDAQIDAiYCLSMYCYMCAYJzAgERqE96gTKBAYNiAQUCQ0/bJgEFBhQBgQouhTuDGAGEf1sYAYR4JxsbgXKBFYE7gi2BBYFcAQGBJ4QUgmkEgiKBDoFkNpFUSIECHANZLAFVEw0KCwcFgWYDNRIqFW4yHYEjPhczWBsHBYgVD4kPeHCBIHIDCxgNSBEsNxQbBD0BbgeOS0GBZAJMAS1hASsgcYECARiTJRKQHIIhoQ4KKIN0jB6VOhozqmsLmHuOCZZQhGiBaDw5gQ4LB3AVgyJSGQ+OKg4Lg16Bf79jIjU8AgcBCgEBAwmRaoF9AQE IronPort-Data: A9a23:ck0Kl64/XXI28KtJnKI4MQxRtGnGchMFZxGqfqrLsTDasY5as4F+v mNLC22EM/qIa2r9LY10Pornpk9Q7MLTm4NiSgpopCwyZn8b8sCt6fZ1gavT04J+CuWZESqLO u1HMoGowPgcFyGa/lH2dOC98RGQ7InQLpLkEunIJyttcgFtTSYlmHpLlvUw6mJSqYDR7zil5 5Wo+qUzBHf/g2QqajhNsfrawP9SlK2aVA0w7wRWic9j5Dcyp1FNZLoDKKe4KWfPQ4U8NoaSW +bZwbilyXjS9hErB8nNuu6TnpoiG+O60aCm0xK6aoD66vRwjnVaPpUTaJLwXXxqZwChxLid/ jniWauYEm/FNoWU8AgUvoIx/ytWZcWq85efSZSzXFD6I0DuKxPRL/tS4E4eYJwF+MReGkx10 cMydjwAfj64qOuMz+fuIgVsrpxLwMjDJogTvDRkiDreF/tjGc2FSKTR7tge1zA17ixMNa+BP IxCNnw1MUmGOkEVUrsUIMpWcOOAinTyaTREqFW9rqss6G+Vxwt0uFToGISLIYzaGJsLxy50o EqZ9jvbWxUrPuCQ9ha78kqFgajE2gH0Ddd6+LqQs6QCbEeo7msLBRsbUFG2rfW0hgu1XMhSA 0gV4TY1668q+UqmS9PwUxG1rDiDpBF0ZjZLO/cx5AfIzu/f5ByUQzBZCDVAc9ch8sQxQFTGy 2O0oj8gPhQ32JX9dJ5X3u78Qe+aUcTNEVI/WA== IronPort-HdrOrdr: A9a23:EbDV6qE5qJii9YEZpLqE48eALOsnbusQ8zAXPidKOHlom62j5q KTdZsguyMc5Ax9ZJhCo6HiBEDjexLhHPdOiOF7V4tKNzOIhILHFu1fBPPZowEJ30bFh4lgPW AKSdkbNOHN X-Talos-CUID: 9a23:/LtZ4mui7KhveCahI/nO3j+46It4Y2Df7l7LDnScNkw3RLCFZ2S/8Zlrxp8= X-Talos-MUID: 9a23:8zMiJgYkYpJpieBT6DazpmhmBc1U7JuCNkA1uJJBsI6mOnkl X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.21,286,1763424000"; d="scan'208";a="663885661" Received: from rcdn-l-core-05.cisco.com ([173.37.255.142]) by alln-iport-6.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 12 Feb 2026 05:00:17 +0000 Received: from sjc-ads-3552.cisco.com (sjc-ads-3552.cisco.com [171.68.249.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-05.cisco.com (Postfix) with ESMTPS id E8F4B18000D20 for ; Thu, 12 Feb 2026 05:00:16 +0000 (GMT) Received: by sjc-ads-3552.cisco.com (Postfix, from userid 1795984) id 8BBB1CC12B5; Wed, 11 Feb 2026 21:00:16 -0800 (PST) From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Subject: [openembedded-core] [scarthgap] [PATCH 3/5] go 1.22.12: Fix CVE-2025-61728 Date: Wed, 11 Feb 2026 20:59:43 -0800 Message-ID: <20260212050011.4080605-1-deeratho@cisco.com> X-Mailer: git-send-email 2.44.4 MIME-Version: 1.0 X-Outbound-SMTP-Client: 171.68.249.250, sjc-ads-3552.cisco.com X-Outbound-Node: rcdn-l-core-05.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 12 Feb 2026 05:00:22 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/231007 From: Deepak Rathore Upstream Repository: https://github.com/golang/go.git Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-61728 Type: Security Fix CVE: CVE-2025-61728 Score: 6.5 Patch: https://github.com/golang/go/commit/3235ef3db85c Signed-off-by: Deepak Rathore diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 46f6ef5d8f..04e380c821 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -33,6 +33,7 @@ SRC_URI += "\ file://CVE-2025-61729.patch \ file://CVE-2025-61730.patch \ file://CVE-2025-61726.patch \ + file://CVE-2025-61728.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61728.patch b/meta/recipes-devtools/go/go/CVE-2025-61728.patch new file mode 100644 index 0000000000..99266ed7a8 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61728.patch @@ -0,0 +1,171 @@ +From 727c39f7e6c9dc9d4a40d67f39f68ae8867a2abd Mon Sep 17 00:00:00 2001 +From: Damien Neil +Date: Tue, 4 Nov 2025 17:00:33 -0800 +Subject: [PATCH] [release-branch.go1.24] archive/zip: reduce CPU usage in + index construction +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Constructing the zip index (which is done once when first opening +a file in an archive) can consume large amounts of CPU when +processing deeply-nested directory paths. + +Switch to a less inefficient algorithm. + +Thanks to Jakub Ciolek for reporting this issue. + + goos: darwin + goarch: arm64 + pkg: archive/zip + cpu: Apple M4 Pro + │ /tmp/bench.0 │ /tmp/bench.1 │ + │ sec/op │ sec/op vs base │ + ReaderOneDeepDir-14 25983.62m ± 2% 46.01m ± 2% -99.82% (p=0.000 n=8) + ReaderManyDeepDirs-14 16.221 ± 1% 2.763 ± 6% -82.96% (p=0.000 n=8) + ReaderManyShallowFiles-14 130.3m ± 1% 128.8m ± 2% -1.20% (p=0.003 n=8) + geomean 3.801 253.9m -93.32% + +Fixes #77102 +Fixes CVE-2025-61728 + +CVE: CVE-2025-61728 +Upstream-Status: Backport [https://github.com/golang/go/commit/3235ef3db85c] + +Change-Id: I2c9c864be01b2a2769eb67fbab1b250aeb8f6c42 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3060 +Reviewed-by: Nicholas Husin +Reviewed-by: Neal Patel +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3328 +Reviewed-by: Damien Neil +Reviewed-on: https://go-review.googlesource.com/c/go/+/736703 +TryBot-Bypass: Michael Pratt +Auto-Submit: Michael Pratt +Reviewed-by: Junyang Shao +(cherry picked from commit 3235ef3db85c2d7e797b976822a7addaf6d5ca2a) +Signed-off-by: Deepak Rathore +--- + src/archive/zip/reader.go | 11 ++++- + src/archive/zip/reader_test.go | 81 ++++++++++++++++++++++++++++++++++ + 2 files changed, 91 insertions(+), 1 deletion(-) + +diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go +index 60b34b76ee..8a79f5d140 100644 +--- a/src/archive/zip/reader.go ++++ b/src/archive/zip/reader.go +@@ -830,7 +830,16 @@ func (r *Reader) initFileList() { + continue + } + +- for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) { ++ dir := name ++ for { ++ if idx := strings.LastIndex(dir, "/"); idx < 0 { ++ break ++ } else { ++ dir = dir[:idx] ++ } ++ if dirs[dir] { ++ break ++ } + dirs[dir] = true + } + +diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go +index 9a77c1aa62..278714bf49 100644 +--- a/src/archive/zip/reader_test.go ++++ b/src/archive/zip/reader_test.go +@@ -8,6 +8,7 @@ import ( + "bytes" + "encoding/binary" + "encoding/hex" ++ "fmt" + "internal/obscuretestdata" + "io" + "io/fs" +@@ -1834,3 +1835,83 @@ func TestBaseOffsetPlusOverflow(t *testing.T) { + // as the section reader offset & size were < 0. + NewReader(bytes.NewReader(data), int64(len(data))+1875) + } ++ ++func BenchmarkReaderOneDeepDir(b *testing.B) { ++ var buf bytes.Buffer ++ zw := NewWriter(&buf) ++ ++ for i := range 4000 { ++ name := strings.Repeat("a/", i) + "data" ++ zw.CreateHeader(&FileHeader{ ++ Name: name, ++ Method: Store, ++ }) ++ } ++ ++ if err := zw.Close(); err != nil { ++ b.Fatal(err) ++ } ++ data := buf.Bytes() ++ ++ for b.Loop() { ++ zr, err := NewReader(bytes.NewReader(data), int64(len(data))) ++ if err != nil { ++ b.Fatal(err) ++ } ++ zr.Open("does-not-exist") ++ } ++} ++ ++func BenchmarkReaderManyDeepDirs(b *testing.B) { ++ var buf bytes.Buffer ++ zw := NewWriter(&buf) ++ ++ for i := range 2850 { ++ name := fmt.Sprintf("%x", i) ++ name = strings.Repeat("/"+name, i+1)[1:] ++ ++ zw.CreateHeader(&FileHeader{ ++ Name: name, ++ Method: Store, ++ }) ++ } ++ ++ if err := zw.Close(); err != nil { ++ b.Fatal(err) ++ } ++ data := buf.Bytes() ++ ++ for b.Loop() { ++ zr, err := NewReader(bytes.NewReader(data), int64(len(data))) ++ if err != nil { ++ b.Fatal(err) ++ } ++ zr.Open("does-not-exist") ++ } ++} ++ ++func BenchmarkReaderManyShallowFiles(b *testing.B) { ++ var buf bytes.Buffer ++ zw := NewWriter(&buf) ++ ++ for i := range 310000 { ++ name := fmt.Sprintf("%v", i) ++ zw.CreateHeader(&FileHeader{ ++ Name: name, ++ Method: Store, ++ }) ++ } ++ ++ if err := zw.Close(); err != nil { ++ b.Fatal(err) ++ } ++ data := buf.Bytes() ++ ++ for b.Loop() { ++ zr, err := NewReader(bytes.NewReader(data), int64(len(data))) ++ if err != nil { ++ b.Fatal(err) ++ } ++ zr.Open("does-not-exist") ++ } ++} +-- +2.35.6 From patchwork Thu Feb 12 05:01:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 80948 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 34DB0EDF037 for ; Thu, 12 Feb 2026 05:01:52 +0000 (UTC) Received: from alln-iport-1.cisco.com (alln-iport-1.cisco.com [173.37.142.88]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.38744.1770872505576773904 for ; Wed, 11 Feb 2026 21:01:45 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=Zc2oXaUW; spf=pass (domain: cisco.com, ip: 173.37.142.88, mailfrom: deeratho@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=3910; q=dns/txt; s=iport01; t=1770872505; x=1772082105; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=cLYuLLMrfS1GonCSg682H3MP7lGc5PlYatwRsSudkHQ=; b=Zc2oXaUWMieqXhvglUgl0JOaqoda/NEBX4AZI/lqEu+BcvmkRcwr/Zth dC/lrErJeT+Yl06eLwT/Vd2VCOXfC6ZnjzPqNdOboqrWhFf7SxT/gFVRj 37wByHbzu5TPyJJSvBTYq43tMj4PQi5uTaQRAnzfBNNcJwuBxeoHKWjDz 7bptucJOJ2G+70alorq6KEJqRRGb4Si7feoq7Z+7viC694enTaQW5q35c C99OKS4krpLOYbd8urcX/uDaDF1YuRwwa+T0GK9LIb5VzLLlTqyI/Hnx/ 0fBb+fpt7y3YvN7EvAyYcFVblieTzlq13HbKaISGt+URjoe1mxReSI1zA g==; X-CSE-ConnectionGUID: cnDBecMJSu6gzdcnZHZKeg== X-CSE-MsgGUID: g2NAPs/UTGeB4V7jIeFthg== X-IPAS-Result: A0DcBgAcXY1p/4v/Ja1aHQEBPAEFBQECAQkBgWUCgkYPcV9CSZQqgiGeHYF/DwEBAQ8UAicUBAEBkiYCJjQJDgECBAEBAQEDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBOAFyAwECWiMhgwIBgnMCARGoT4IsgQGCZnwBBQJDT9smAQUGFAGBOAGFOogYWxgBhHgnGxuBcoR9gQWBXAEBiCQEgiKBDoFkNpFUSIEeA1ksAVUTDQoLBwWBZgM1EioVbjIdgSM+F4ELGwcFiBUPiQ94cIEgcgMLGA1IESw3FBsEPm4HjktBgTd7AXQaASsXCXsoUAEYJCeSWpAugiGhDgoog3SMHpU6GjOqawuYe44JllCEaIFoPDmBDgsHcBWDIlIZD444g2mBf4JZvQoiNTwCBwsBAQMJkWwtgU4BAQ IronPort-Data: A9a23:4xFFvKok4SDQz99HoWfZhyx1dkleBmJJZBIvgKrLsJaIsI4StFCzt garIBmCMvmIMDTzf492YYS+9hgGvZOAydM1TAFlrigxRHkV9uPIVI+TRqvS04x+DSFioGZPt Zh2hgzodZhsJpPkjk7zdOCn9j8kif3gqoPUUIbsIjp2SRJvVBAvgBdin/9RqoNziLBVOSvV0 T/Ji5OZYgbNNwJcaDpOtfrZ8Uk35ZwehRtB1rAATaET1LPhvyF94KI3fcmZM3b+S49IKe+2L 86r5K255G7Q4yA2AdqjlLvhGmVSKlIFFVHT4pb+c/HKbilq/kTe4I5iXBYvQRs/ZwGyojxE4 I4lWapc5useFvakdOw1C3G0GszlVEFM0OevzXOX6aR/w6BaGpfh660GMa04AWEX0u1xLUtD/ tk6Ey1TYQKPjOSE4ICYR+Y506zPLOGzVG8ekmtrwTecCbMtRorOBv2Qo9RZxzw3wMtJGJ4yZ eJANmEpN0uGOUASfA5MWfrSn8/w7pX7WzFVpUicuaowy2PS1wd2lrPqNbI5f/TUGp0NwBvI/ zmuE2LRDUs8HeSEjge53X+G2tGQnwL2dp4SG+jtnhJtqBjJroAJMzURTVa9rPyzh0KyVt4aI EsO9wIqrLMu7wqsVtT7UhiyrXKIsxJaXMBfe9DW8ymXwabSpgLcDW8eQ3sZMpottdQ9Qnoh0 Vrhc87VOAGDeYa9ERq1nop4ZxvrUcTJBQfuvRM5cDY= IronPort-HdrOrdr: A9a23:pq4ncKhI+MhJs9mAidmg4sAlf3BQXs8ji2hC6mlwRA09TyX+rb HNoB1173HJYVoqNU3I+urwW5VoI0m8yXcd2+B4Vt2ftWLd11dAQrsP0WKb+V3d8+mUzJ846U +mGJIObeHNMQ== X-Talos-CUID: 9a23:KiUrJW9sRiuM8b4izDiVv0USNuooeVj/92qOLF20AmBbaI+2RFDFrQ== X-Talos-MUID: 9a23:eDKzbQoEnX9JduxcNvAezz44Eu5Q+OOTNG8Au8k45MulOAJsOzjI2Q== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.21,286,1763424000"; d="scan'208";a="670065813" Received: from rcdn-l-core-02.cisco.com ([173.37.255.139]) by alln-iport-1.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 12 Feb 2026 05:01:44 +0000 Received: from sjc-ads-3552.cisco.com (sjc-ads-3552.cisco.com [171.68.249.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-02.cisco.com (Postfix) with ESMTPS id 5D5E41800037E for ; Thu, 12 Feb 2026 05:01:44 +0000 (GMT) Received: by sjc-ads-3552.cisco.com (Postfix, from userid 1795984) id 092A9CC12B5; Wed, 11 Feb 2026 21:01:44 -0800 (PST) From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Subject: [openembedded-core] [scarthgap] [PATCH 4/5] go 1.22.12: Fix CVE-2025-61731 Date: Wed, 11 Feb 2026 21:01:25 -0800 Message-ID: <20260212050140.4087428-1-deeratho@cisco.com> X-Mailer: git-send-email 2.44.4 MIME-Version: 1.0 X-Outbound-SMTP-Client: 171.68.249.250, sjc-ads-3552.cisco.com X-Outbound-Node: rcdn-l-core-02.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 12 Feb 2026 05:01:52 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/231008 From: Deepak Rathore Upstream Repository: https://github.com/golang/go.git Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-61731 Type: Security Fix CVE: CVE-2025-61731 Score: 7.8 Patch: https://github.com/golang/go/commit/00b7309387a1 Signed-off-by: Deepak Rathore diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 04e380c821..82019f25dd 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -34,6 +34,7 @@ SRC_URI += "\ file://CVE-2025-61730.patch \ file://CVE-2025-61726.patch \ file://CVE-2025-61728.patch \ + file://CVE-2025-61731.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61731.patch b/meta/recipes-devtools/go/go/CVE-2025-61731.patch new file mode 100644 index 0000000000..a4589daade --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61731.patch @@ -0,0 +1,70 @@ +From ab266ccbc19789c52dcb1dc6e8e71d2f4fd545ff Mon Sep 17 00:00:00 2001 +From: Neal Patel +Date: Thu, 4 Dec 2025 12:30:39 -0500 +Subject: [PATCH] [release-branch.go1.24] cmd/go/internal/work: sanitize flags + before invoking 'pkg-config' + +The addition of CgoPkgConfig allowed execution with flags not +matching the safelist. In order to prevent potential arbitrary +code execution at build time, ensure that flags are validated +prior to invoking the 'pkg-config' binary. + +Thank you to RyotaK (https://ryotak.net) of GMO Flatt Security Inc. +for reporting this issue. + +Fixes CVE-2025-61731 +Fixes #77100 + +CVE: CVE-2025-61731 +Upstream-Status: Backport [https://github.com/golang/go/commit/00b7309387a1] + +Change-Id: Ic51b41f1f7e697ab98c9c32c6fae35f217f7f364 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3240 +Reviewed-by: Nicholas Husin +Reviewed-by: Damien Neil +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3344 +Reviewed-by: Neal Patel +Reviewed-on: https://go-review.googlesource.com/c/go/+/736701 +Auto-Submit: Michael Pratt +TryBot-Bypass: Michael Pratt +Reviewed-by: Junyang Shao +(cherry picked from commit 00b7309387a171bcba37382e7ed96b473df04917) +Signed-off-by: Deepak Rathore +--- + src/cmd/go/internal/work/exec.go | 8 ++++++++ + src/cmd/go/internal/work/security.go | 1 + + 2 files changed, 9 insertions(+) + +diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go +index c8f297cbe9..815942a703 100644 +--- a/src/cmd/go/internal/work/exec.go ++++ b/src/cmd/go/internal/work/exec.go +@@ -1684,6 +1684,14 @@ func (b *Builder) getPkgConfigFlags(a *Action) (cflags, ldflags []string, err er + return nil, nil, fmt.Errorf("invalid pkg-config package name: %s", pkg) + } + } ++ ++ // Running 'pkg-config' can cause execution of ++ // arbitrary code using flags that are not in ++ // the safelist. ++ if err := checkCompilerFlags("CFLAGS", "pkg-config --cflags", pcflags); err != nil { ++ return nil, nil, err ++ } ++ + var out []byte + out, err = sh.runOut(p.Dir, nil, b.PkgconfigCmd(), "--cflags", pcflags, "--", pkgs) + if err != nil { +diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go +index 568eecd325..79724ed04a 100644 +--- a/src/cmd/go/internal/work/security.go ++++ b/src/cmd/go/internal/work/security.go +@@ -122,6 +122,7 @@ var validCompilerFlags = []*lazyregexp.Regexp{ + re(`-pedantic(-errors)?`), + re(`-pipe`), + re(`-pthread`), ++ re(`--static`), + re(`-?-std=([^@\-].*)`), + re(`-?-stdlib=([^@\-].*)`), + re(`--sysroot=([^@\-].*)`), +-- +2.35.6 From patchwork Thu Feb 12 05:01:50 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 80949 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 27CABEDF036 for ; Thu, 12 Feb 2026 05:02:22 +0000 (UTC) Received: from alln-iport-4.cisco.com (alln-iport-4.cisco.com [173.37.142.91]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.38761.1770872537110231960 for ; Wed, 11 Feb 2026 21:02:17 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=hyQ2RhH7; spf=pass (domain: cisco.com, ip: 173.37.142.91, mailfrom: deeratho@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=40240; q=dns/txt; s=iport01; t=1770872537; x=1772082137; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=Wfd66TumCqk6KYo7asWCXxyfEaP73rgeKE1ev5M1uVo=; b=hyQ2RhH7cyz1PlLOFKw1rqhUsDEOFBOiXTSOgrmRoTpF3wqPYoScW4Gs 8nMJPiyr2IYUXD+BpoKlLFA5/s37V9QoXRJUJpuzwmc6YoZBgv30TXq7S Y+40amXt39CVJrCsYLSGY4lDM76jTSUNBWpSlHX/XOsTP0ZpDSZyxqaF2 4fZWOyfwHYuKm1jP21xrB68NEQFWdtpFRYpIseGUIbKTUtTCwbHjSpu2q 7yoTSVbM98yQ38Q7cNJTAKI/wk9M/73aDjw+tHL8Cq+IDRLMeCC471+C6 VsRqN1Dpr35hzYY41UAXOxbMMT0e20gI28scKsKzYT3HPSLNAdLzdiQNO g==; X-CSE-ConnectionGUID: D7pFSAudQqSHIgN+5mSp9Q== X-CSE-MsgGUID: //zJJKD2R5SvefaaU2xXLA== X-IPAS-Result: A0CrBgCUXY1p/4z/Ja1QCoJZgkgPcV9CKx4DlCeCIYEWilGFZoxQFIEIA2APAQEBDz0UBAEBhQcCjR0CJjQJDgECBAEBAQEDAgMBAQEBAQEBAQEBAQsBAQUBAQECAQcFgQ4Thk8NhloBIAEXAXIDAQJPCyMhgwIBNoIEAzYCAQgJp34aN4IsgQGCZnwBBQJDT9hHDYJSAQsUAYE4hTuCeYUfWxgBhHgnGxuBcoEVgnJ2gQWBGkIBAYEzE4ZeBIIigQ6BElInD5FUSIEeA1ksAVUTDQoLBwWBZgM1EioVbjIdgSM+F4ELGwcFiBUPiQ94cIEgcgMLGA1IESw3FBsEPm4HjktBgS8RJkwBLQQMHAEhBA8BByMBFwkCXhEHAyhBDwEYHAItkloSCDgDj1mCIaAdcQoog3SMHo8+hXwaM4QEgVelEAuYe4JYizGECYNUZYxyNAsNAU+EaIFoPDmBDgsHcBU7gmcJFjMZD44qAgELC4NegX+BcIEkvE8iNQIENgIHCwEBAwmTB2ABAQ IronPort-Data: A9a23:exTyr6M/pBxg/g7vrR30lsFynXyQoLVcMsEvi/4bfWQNrUp33z1Vm mseD2HUMvbcMDOhLtt+Odzi9E8Cv8PdztIwSHM5pCpnJ55oRWUpJjg4wmPYZX76whjrFRo/h ykmQoCeaphyFTmE+kvF3oHJ9RFUzbuPSqf3FNnKMyVwQR4MYCo6gHqPocZh6mJTqYb/WVrlV e/a+ZWFZgf/gmQsawr41orawP9RlKWq0N8nlgRWicBj5Df2i3QTBZQDEqC9R1OQapVUBOOzW 9HYx7i/+G7Dlz91Yj9yuu+mGqGiaue60Tmm0hK6aYD76vRxjnBaPpIACRYpQRw/ZwNlMDxG4 I4lWZSYEW/FN0BX8QgXe0Ew/ypWZcWq9FJbSJSymZT78qHIT5fj69kxFG8NFJAUw/9MIUBB0 79FLQsVPynW0opawJrjIgVtrt4oIM+uOMYUvWttiGmCS/0nWpvEBa7N4Le03h9p2ZsIRqmYP ZdEL2MzNHwsYDUXUrsTIJ4zkf2hmnn4WzZZs1mS46Ew5gA/ySQvjuSzb4SPIIfiqcN92QGKh EDl0z7DXyoEOdKWwAff4kKIr7qa9c/8cMdIfFGizdZtmFCVy2kZBREaWFf+qv6jh2a6WslDM AoT4icooK04+UCnQ9W7WAe3yENopTYGUNZWVul/4waXx++MuECSB3MPSXhKb9lOWNIKeAHGH 2Shx7vBbQGDepXMIZ5B3t94dQ+PBBU= IronPort-HdrOrdr: A9a23:e+4tuK4d3olNG1O7RwPXwN3XdLJyesId70hD6qkXc202TiX2ra 6TdZgguCMc6wxhO03I++rgBEDoexq1nvRICOIqUotKMjOLhILRFuFfBU+I+UyFJ8U4ndQtsJ tdTw== X-Talos-CUID: 9a23:rA5JLG1BJ27Kr/qxFBtmdrxfNp89XEb00XvpOnSYKGlPC+CQckfBwfYx X-Talos-MUID: 9a23:um+iCw2LQ+KQpuEgEfN8RnihxTUjpOO8KmIuvc885vKaOCJ5MgrHnASTa9py X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.21,286,1763424000"; d="scan'208";a="664676223" Received: from rcdn-l-core-03.cisco.com ([173.37.255.140]) by alln-iport-4.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 12 Feb 2026 05:02:15 +0000 Received: from sjc-ads-3552.cisco.com (sjc-ads-3552.cisco.com [171.68.249.250]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-03.cisco.com (Postfix) with ESMTPS id 6AF171800060B for ; Thu, 12 Feb 2026 05:02:15 +0000 (GMT) Received: by sjc-ads-3552.cisco.com (Postfix, from userid 1795984) id 190DACC12B5; Wed, 11 Feb 2026 21:02:15 -0800 (PST) From: "Deepak Rathore -X (deeratho - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Subject: [openembedded-core] [scarthgap] [PATCH 5/5] go 1.22.12: Fix CVE-2025-68119 Date: Wed, 11 Feb 2026 21:01:50 -0800 Message-ID: <20260212050211.4088499-1-deeratho@cisco.com> X-Mailer: git-send-email 2.44.4 MIME-Version: 1.0 X-Outbound-SMTP-Client: 171.68.249.250, sjc-ads-3552.cisco.com X-Outbound-Node: rcdn-l-core-03.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Thu, 12 Feb 2026 05:02:22 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/231009 From: Deepak Rathore Upstream Repository: https://github.com/golang/go.git Bug details: https://nvd.nist.gov/vuln/detail/CVE-2025-68119 Type: Security Fix CVE: CVE-2025-68119 Score: 7.0 Patch: [1] https://github.com/golang/go/commit/62452bed4801 [2] https://github.com/golang/go/commit/73fe85f0ea1b Note: - First commit [1] is a dependent patch which is required additionally in original fix [2] to define ENV variable changes in src/cmd/go/internal/vcs/vcs.go file. Signed-off-by: Deepak Rathore diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 82019f25dd..ca0f05f7c8 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -35,6 +35,8 @@ SRC_URI += "\ file://CVE-2025-61726.patch \ file://CVE-2025-61728.patch \ file://CVE-2025-61731.patch \ + file://CVE-2025-68119-dependent.patch \ + file://CVE-2025-68119.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch b/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch new file mode 100644 index 0000000000..5875d129cc --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-68119-dependent.patch @@ -0,0 +1,175 @@ +From 121b6cb231b5d904c03739495fcda69152d83f88 Mon Sep 17 00:00:00 2001 +From: Matt Harbison +Date: Sat, 3 Aug 2024 00:06:30 +0000 +Subject: [PATCH] cmd/go: fix the accuracy of Mercurial vcs.* stamped data + +There were a few Mercurial command line uses that could cause the wrong +data to be used: + +* The log command needs '-r.' to specify the currently checked out commit +* HGPLAIN is needed to disable optional output on commands +* '-S' is needed to for the 'status' command to recurse into any subrepos + +The most likely issue to be seen here was the use of '-l1' instead of +'-r.', which prints the most recent commit instead of the current checkout. +Since tagging in Mercurial creates a new commit, this basically means the +data was wrong for every tagged build. + +This also adds an hgrc config file to the test, with config options to +keep the time and author values fixed. It's what's used in the Mercurial +test harness to keep the commit hashes stable, and allows the tests here to +also match the time and the revision ID, to prevent regressing. + +Fixes #63532 + +CVE: CVE-2025-68119 +Upstream-Status: Backport [https://github.com/golang/go/commit/62452bed4801] + +Change-Id: I5b9971ce87c83431ec77e4a002bdc33fcf393856 +GitHub-Last-Rev: 62c9db0a28fee5881d0fe49f7bbb6e1653c7ff60 +GitHub-Pull-Request: golang/go#63557 +Reviewed-on: https://go-review.googlesource.com/c/go/+/535377 +Reviewed-by: Bryan Mills +LUCI-TryBot-Result: Go LUCI +Reviewed-by: Sam Thanawalla +Auto-Submit: Sam Thanawalla +Reviewed-by: Michael Matloob +(cherry picked from commit 62452bed480108623910feace4a5cea5448e6822) +Signed-off-by: Deepak Rathore +--- + src/cmd/go/internal/vcs/vcs.go | 13 +++++-- + .../testdata/script/version_buildvcs_hg.txt | 39 ++++++++++++++++--- + 2 files changed, 43 insertions(+), 9 deletions(-) + +diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go +index 89d9f0e94e..60f76d77cf 100644 +--- a/src/cmd/go/internal/vcs/vcs.go ++++ b/src/cmd/go/internal/vcs/vcs.go +@@ -37,6 +37,7 @@ import ( + type Cmd struct { + Name string + Cmd string // name of binary to invoke command ++ Env []string // any environment values to set/override + RootNames []rootName // filename and mode indicating the root of a checkout directory + + CreateCmd []string // commands to download a fresh copy of a repository +@@ -154,6 +155,10 @@ func vcsByCmd(cmd string) *Cmd { + var vcsHg = &Cmd{ + Name: "Mercurial", + Cmd: "hg", ++ ++ // HGPLAIN=1 turns off additional output that a user may have enabled via ++ // config options or certain extensions. ++ Env: []string{"HGPLAIN=1"}, + RootNames: []rootName{ + {filename: ".hg", isDir: true}, + }, +@@ -189,12 +194,11 @@ func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) { + + func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { + // Output changeset ID and seconds since epoch. +- out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -l1 -T {node}:{date|hgdate}`) ++ out, err := vcsHg.runOutputVerboseOnly(rootDir, `log -r. -T {node}:{date|hgdate}`) + if err != nil { + return Status{}, err + } + +- // Successful execution without output indicates an empty repo (no commits). + var rev string + var commitTime time.Time + if len(out) > 0 { +@@ -209,7 +213,7 @@ func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { + } + + // Also look for untracked files. +- out, err = vcsHg.runOutputVerboseOnly(rootDir, "status") ++ out, err = vcsHg.runOutputVerboseOnly(rootDir, "status -S") + if err != nil { + return Status{}, err + } +@@ -689,6 +693,9 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ + + cmd := exec.Command(v.Cmd, args...) + cmd.Dir = dir ++ if v.Env != nil { ++ cmd.Env = append(cmd.Environ(), v.Env...) ++ } + if cfg.BuildX { + fmt.Fprintf(os.Stderr, "cd %s\n", dir) + fmt.Fprintf(os.Stderr, "%s %s\n", v.Cmd, strings.Join(args, " ")) +diff --git a/src/cmd/go/testdata/script/version_buildvcs_hg.txt b/src/cmd/go/testdata/script/version_buildvcs_hg.txt +index fbbd886102..13904fae12 100644 +--- a/src/cmd/go/testdata/script/version_buildvcs_hg.txt ++++ b/src/cmd/go/testdata/script/version_buildvcs_hg.txt +@@ -6,6 +6,8 @@ + [short] skip + env GOBIN=$WORK/gopath/bin + env oldpath=$PATH ++env TZ=GMT ++env HGRCPATH=$WORK/hgrc + cd repo/a + + # If there's no local repository, there's no VCS info. +@@ -29,24 +31,43 @@ cd .. + env PATH=$oldpath + rm .hg + +-# If there is an empty repository in a parent directory, only "uncommitted" is tagged. ++# An empty repository or one explicitly updated to null uses the null cset ID, ++# and the time is hard set to 1/1/70, regardless of the current time. + exec hg init + cd a + go install + go version -m $GOBIN/a$GOEXE +-! stdout vcs.revision +-! stdout vcs.time ++stdout '^\tbuild\tvcs.revision=0000000000000000000000000000000000000000$' ++stdout '^\tbuild\tvcs.time=1970-01-01T00:00:00Z$' + stdout '^\tbuild\tvcs.modified=true$' + cd .. + + # Revision and commit time are tagged for repositories with commits. + exec hg add a README +-exec hg commit -m 'initial commit' ++exec hg commit -m 'initial commit' --user test-user --date '2024-07-31T01:21:27+00:00' + cd a + go install + go version -m $GOBIN/a$GOEXE +-stdout '^\tbuild\tvcs.revision=' +-stdout '^\tbuild\tvcs.time=' ++stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' ++stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' ++stdout '^\tbuild\tvcs.modified=false$' ++rm $GOBIN/a$GOEXE ++ ++# Add an extra commit and then back off of it to show that the hash is ++# from the checked out revision, not the tip revision. ++cp ../../outside/empty.txt . ++exec hg ci -Am 'another commit' --user test-user --date '2024-08-01T19:24:38+00:00' ++exec hg update --clean -r '.^' ++ ++# Modified state is not thrown off by extra status output ++exec hg bisect -v -g . ++exec hg bisect -v -b '.^^' ++exec hg status ++stdout '^.+' ++go install ++go version -m $GOBIN/a$GOEXE ++stdout '^\tbuild\tvcs.revision=71eaed52daeaafea83cb604f75b0a0336ef2c345$' ++stdout '^\tbuild\tvcs.time=2024-07-31T01:21:27Z$' + stdout '^\tbuild\tvcs.modified=false$' + rm $GOBIN/a$GOEXE + +@@ -88,4 +109,10 @@ go 1.18 + package main + + func main() {} ++-- $WORK/hgrc -- ++[ui] ++# tweakdefaults is an opt-in that may print extra output in commands like ++# status. That can be disabled by setting HGPLAIN=1. ++tweakdefaults = 1 ++ + -- outside/empty.txt -- +-- +2.35.6 diff --git a/meta/recipes-devtools/go/go/CVE-2025-68119.patch b/meta/recipes-devtools/go/go/CVE-2025-68119.patch new file mode 100644 index 0000000000..d3f1724453 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-68119.patch @@ -0,0 +1,828 @@ +From 204e2fdacfbdb72a0b85fb526c8599128e430e94 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker +Date: Wed, 10 Dec 2025 08:13:07 -0500 +Subject: [PATCH] [release-branch.go1.24] cmd/go: update VCS commands to use + safer flag/argument syntax + +In various situations, the toolchain invokes VCS commands. Some of these +commands take arbitrary input, either provided by users or fetched from +external sources. To prevent potential command injection vulnerabilities +or misinterpretation of arguments as flags, this change updates the VCS +commands to use various techniques to separate flags from positional +arguments, and to directly associate flags with their values. + +Additionally, we update the environment variable for Mercurial to use +`HGPLAIN=+strictflags`, which is the more explicit way to disable user +configurations (intended or otherwise) that might interfere with command +execution. + +We also now disallow version strings from being prefixed with '-' or +'/', as doing so opens us up to making the same mistake again in the +future. As far as we know there are currently ~0 public modules affected +by this. + +While I was working on cmd/go/internal/vcs, I also noticed that a +significant portion of the commands being implemented were dead code. +In order to reduce the maintenance burden and surface area for potential +issues, I removed the dead code for unused commands. + +We should probably follow up with a more structured change to make it +harder to accidentally re-introduce these issues in the future, but for +now this addresses the issue at hand. + +Thanks to splitline (@splitline) from DEVCORE Research Team for +reporting this issue. + +Fixes CVE-2025-68119 +Updates #77099 +Fixes #77103 + +CVE: CVE-2025-68119 +Upstream-Status: Backport [https://github.com/golang/go/commit/73fe85f0ea1b] + +Backport Changes: +- In file src/cmd/go/internal/modfetch/codehost/git.go, Replaced the + function call runGIT with RUN. This changes is not present in current + version v1.22.12 and this changes were introduced in version v1.24 by + this commit https://github.com/golang/go/commit/8aa2eed8fb90 + +Change-Id: I9d9f4ee05b95be49fe14edf71a1b8e6c0784378e +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3260 +Reviewed-by: Damien Neil +Reviewed-by: Nicholas Husin +Reviewed-on: https://go-review.googlesource.com/c/go/+/736710 +Auto-Submit: Michael Pratt +Reviewed-by: Junyang Shao +LUCI-TryBot-Result: Go LUCI +(cherry picked from commit 94a1296a457387d1fd6eca1a9bcd44e89bdd9d55) +Reviewed-on: https://go-review.googlesource.com/c/go/+/739421 +Auto-Submit: Dmitri Shuralyov +(cherry picked from commit 73fe85f0ea1bf2cec8e9a89bf5645de06ecaa0a6) +Signed-off-by: Deepak Rathore +--- + src/cmd/go/internal/modcmd/edit.go | 10 +- + src/cmd/go/internal/modfetch/codehost/git.go | 20 +- + src/cmd/go/internal/modfetch/codehost/vcs.go | 20 +- + src/cmd/go/internal/modget/query.go | 5 +- + src/cmd/go/internal/modload/build.go | 12 +- + src/cmd/go/internal/modload/list.go | 30 +- + src/cmd/go/internal/toolchain/select.go | 7 +- + src/cmd/go/internal/vcs/vcs.go | 331 +------------------ + src/cmd/go/internal/workcmd/edit.go | 5 +- + 9 files changed, 96 insertions(+), 344 deletions(-) + +diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go +index db131b0881..330603fe32 100644 +--- a/src/cmd/go/internal/modcmd/edit.go ++++ b/src/cmd/go/internal/modcmd/edit.go +@@ -284,7 +284,10 @@ func runEdit(ctx context.Context, cmd *base.Command, args []string) { + + // parsePathVersion parses -flag=arg expecting arg to be path@version. + func parsePathVersion(flag, arg string) (path, version string) { +- before, after, found := strings.Cut(arg, "@") ++ before, after, found, err := modload.ParsePathVersion(arg) ++ if err != nil { ++ base.Fatalf("go: -%s=%s: %v", flag, arg, err) ++ } + if !found { + base.Fatalf("go: -%s=%s: need path@version", flag, arg) + } +@@ -318,7 +321,10 @@ func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version + if allowDirPath && modfile.IsDirectoryPath(arg) { + return arg, "", nil + } +- before, after, found := strings.Cut(arg, "@") ++ before, after, found, err := modload.ParsePathVersion(arg) ++ if err != nil { ++ return "", "", err ++ } + if !found { + path = arg + } else { +diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go +index 9996be7af7..45727ae3fb 100644 +--- a/src/cmd/go/internal/modfetch/codehost/git.go ++++ b/src/cmd/go/internal/modfetch/codehost/git.go +@@ -246,7 +246,7 @@ func (r *gitRepo) loadRefs(ctx context.Context) (map[string]string, error) { + r.refsErr = err + return + } +- out, gitErr := Run(ctx, r.dir, "git", "ls-remote", "-q", r.remote) ++ out, gitErr := Run(ctx, r.dir, "git", "ls-remote", "-q","--end-of-options", r.remote) + release() + + if gitErr != nil { +@@ -509,7 +509,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro + if fromTag && !slices.Contains(info.Tags, tag) { + // The local repo includes the commit hash we want, but it is missing + // the corresponding tag. Add that tag and try again. +- _, err := Run(ctx, r.dir, "git", "tag", tag, hash) ++ _, err := Run(ctx, r.dir, "git", "tag","--end-of-options", tag, hash) + if err != nil { + return nil, err + } +@@ -554,7 +554,7 @@ func (r *gitRepo) stat(ctx context.Context, rev string) (info *RevInfo, err erro + // an apparent Git bug introduced in Git 2.21 (commit 61c771), + // which causes the handler for protocol version 1 to sometimes miss + // tags that point to the requested commit (see https://go.dev/issue/56881). +- _, err = Run(ctx, r.dir, "git", "-c", "protocol.version=2", "fetch", "-f", "--depth=1", r.remote, refspec) ++ _, err = Run(ctx, r.dir, "git", "-c", "protocol.version=2", "fetch", "-f", "--depth=1","--end-of-options", r.remote, refspec) + release() + + if err == nil { +@@ -597,12 +597,12 @@ func (r *gitRepo) fetchRefsLocked(ctx context.Context) error { + } + defer release() + +- if _, err := Run(ctx, r.dir, "git", "fetch", "-f", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { ++ if _, err := Run(ctx, r.dir, "git", "fetch", "-f","--end-of-options", r.remote, "refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { + return err + } + + if _, err := os.Stat(filepath.Join(r.dir, "shallow")); err == nil { +- if _, err := Run(ctx, r.dir, "git", "fetch", "--unshallow", "-f", r.remote); err != nil { ++ if _, err := Run(ctx, r.dir, "git", "fetch", "--unshallow", "-f", "--end-of-options",r.remote); err != nil { + return err + } + } +@@ -615,7 +615,7 @@ func (r *gitRepo) fetchRefsLocked(ctx context.Context) error { + // statLocal returns a new RevInfo describing rev in the local git repository. + // It uses version as info.Version. + func (r *gitRepo) statLocal(ctx context.Context, version, rev string) (*RevInfo, error) { +- out, err := Run(ctx, r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D", rev, "--") ++ out, err := Run(ctx, r.dir, "git", "-c", "log.showsignature=false", "log", "--no-decorate", "-n1", "--format=format:%H %ct %D","--end-of-options", rev, "--") + if err != nil { + // Return info with Origin.RepoSum if possible to allow caching of negative lookup. + var info *RevInfo +@@ -705,7 +705,7 @@ func (r *gitRepo) ReadFile(ctx context.Context, rev, file string, maxSize int64) + if err != nil { + return nil, err + } +- out, err := Run(ctx, r.dir, "git", "cat-file", "blob", info.Name+":"+file) ++ out, err := Run(ctx, r.dir, "git", "cat-file","--end-of-options", "blob", info.Name+":"+file) + if err != nil { + return nil, fs.ErrNotExist + } +@@ -723,7 +723,7 @@ func (r *gitRepo) RecentTag(ctx context.Context, rev, prefix string, allowed fun + // result is definitive. + describe := func() (definitive bool) { + var out []byte +- out, err = Run(ctx, r.dir, "git", "for-each-ref", "--format", "%(refname)", "refs/tags", "--merged", rev) ++ out, err = Run(ctx, r.dir, "git", "for-each-ref", "--format=%(refname)", "--merged="+rev) + if err != nil { + return true + } +@@ -865,7 +865,7 @@ func (r *gitRepo) ReadZip(ctx context.Context, rev, subdir string, maxSize int64 + // TODO: Use maxSize or drop it. + args := []string{} + if subdir != "" { +- args = append(args, "--", subdir) ++ args = append(args, subdir) + } + info, err := r.Stat(ctx, rev) // download rev into local git repo + if err != nil { +@@ -887,7 +887,7 @@ func (r *gitRepo) ReadZip(ctx context.Context, rev, subdir string, maxSize int64 + // text file line endings. Setting -c core.autocrlf=input means only + // translate files on the way into the repo, not on the way out (archive). + // The -c core.eol=lf should be unnecessary but set it anyway. +- archive, err := Run(ctx, r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args) ++ archive, err := Run(ctx, r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", "--end-of-options", info.Name, args) + if err != nil { + if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) { + return nil, fs.ErrNotExist +diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go +index 5bd100556b..425f61269f 100644 +--- a/src/cmd/go/internal/modfetch/codehost/vcs.go ++++ b/src/cmd/go/internal/modfetch/codehost/vcs.go +@@ -162,20 +162,20 @@ var vcsCmds = map[string]*vcsCmd{ + branchRE: re(`(?m)^[^\n]+$`), + badLocalRevRE: re(`(?m)^(tip)$`), + statLocal: func(rev, remote string) []string { +- return []string{"hg", "log", "-l1", "-r", rev, "--template", "{node} {date|hgdate} {tags}"} ++ return []string{"hg", "log", "-l1", fmt.Sprintf("--rev=%s", rev), "--template", "{node} {date|hgdate} {tags}"} + }, + parseStat: hgParseStat, + fetch: []string{"hg", "pull", "-f"}, + latest: "tip", + readFile: func(rev, file, remote string) []string { +- return []string{"hg", "cat", "-r", rev, file} ++ return []string{"hg", "cat", fmt.Sprintf("--rev=%s", rev), "--", file} + }, + readZip: func(rev, subdir, remote, target string) []string { + pattern := []string{} + if subdir != "" { +- pattern = []string{"-I", subdir + "/**"} ++ pattern = []string{fmt.Sprintf("--include=%s", subdir+"/**")} + } +- return str.StringList("hg", "archive", "-t", "zip", "--no-decode", "-r", rev, "--prefix=prefix/", pattern, "--", target) ++ return str.StringList("hg", "archive", "-t", "zip", "--no-decode", fmt.Sprintf("--rev=%s", rev), "--prefix=prefix/", pattern, "--", target) + }, + }, + +@@ -215,19 +215,19 @@ var vcsCmds = map[string]*vcsCmd{ + tagRE: re(`(?m)^\S+`), + badLocalRevRE: re(`^revno:-`), + statLocal: func(rev, remote string) []string { +- return []string{"bzr", "log", "-l1", "--long", "--show-ids", "-r", rev} ++ return []string{"bzr", "log", "-l1", "--long", "--show-ids", fmt.Sprintf("--revision=%s", rev)} + }, + parseStat: bzrParseStat, + latest: "revno:-1", + readFile: func(rev, file, remote string) []string { +- return []string{"bzr", "cat", "-r", rev, file} ++ return []string{"bzr", "cat", fmt.Sprintf("--revision=%s", rev), "--", file} + }, + readZip: func(rev, subdir, remote, target string) []string { + extra := []string{} + if subdir != "" { + extra = []string{"./" + subdir} + } +- return str.StringList("bzr", "export", "--format=zip", "-r", rev, "--root=prefix/", "--", target, extra) ++ return str.StringList("bzr", "export", "--format=zip", fmt.Sprintf("--revision=%s", rev), "--root=prefix/", "--", target, extra) + }, + }, + +@@ -242,17 +242,17 @@ var vcsCmds = map[string]*vcsCmd{ + }, + tagRE: re(`XXXTODO`), + statLocal: func(rev, remote string) []string { +- return []string{"fossil", "info", "-R", ".fossil", rev} ++ return []string{"fossil", "info", "-R", ".fossil", "--", rev} + }, + parseStat: fossilParseStat, + latest: "trunk", + readFile: func(rev, file, remote string) []string { +- return []string{"fossil", "cat", "-R", ".fossil", "-r", rev, file} ++ return []string{"fossil", "cat", "-R", ".fossil", fmt.Sprintf("-r=%s", rev), "--", file} + }, + readZip: func(rev, subdir, remote, target string) []string { + extra := []string{} + if subdir != "" && !strings.ContainsAny(subdir, "*?[],") { +- extra = []string{"--include", subdir} ++ extra = []string{fmt.Sprintf("--include=%s", subdir)} + } + // Note that vcsRepo.ReadZip below rewrites this command + // to run in a different directory, to work around a fossil bug. +diff --git a/src/cmd/go/internal/modget/query.go b/src/cmd/go/internal/modget/query.go +index 498ba6c2ff..0d33a52677 100644 +--- a/src/cmd/go/internal/modget/query.go ++++ b/src/cmd/go/internal/modget/query.go +@@ -139,7 +139,10 @@ func errSet(err error) pathSet { return pathSet{err: err} } + // newQuery returns a new query parsed from the raw argument, + // which must be either path or path@version. + func newQuery(raw string) (*query, error) { +- pattern, rawVers, found := strings.Cut(raw, "@") ++ pattern, rawVers, found, err := modload.ParsePathVersion(raw) ++ if err != nil { ++ return nil, err ++ } + if found && (strings.Contains(rawVers, "@") || rawVers == "") { + return nil, fmt.Errorf("invalid module version syntax %q", raw) + } +diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go +index 5cf1487c3e..08acf3aa2b 100644 +--- a/src/cmd/go/internal/modload/build.go ++++ b/src/cmd/go/internal/modload/build.go +@@ -12,7 +12,6 @@ import ( + "io/fs" + "os" + "path/filepath" +- "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" +@@ -88,7 +87,16 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic { + return nil + } + +- if path, vers, found := strings.Cut(path, "@"); found { ++ path, vers, found, err := ParsePathVersion(path) ++ if err != nil { ++ return &modinfo.ModulePublic{ ++ Path: path, ++ Error: &modinfo.ModuleError{ ++ Err: err.Error(), ++ }, ++ } ++ } ++ if found { + m := module.Version{Path: path, Version: vers} + return moduleInfo(ctx, nil, m, 0, nil) + } +diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go +index ef93c25121..e9efb1918e 100644 +--- a/src/cmd/go/internal/modload/list.go ++++ b/src/cmd/go/internal/modload/list.go +@@ -149,7 +149,11 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List + } + continue + } +- if path, vers, found := strings.Cut(arg, "@"); found { ++ path, vers, found, err := ParsePathVersion(arg) ++ if err != nil { ++ base.Fatalf("go: %v", err) ++ } ++ if found { + if vers == "upgrade" || vers == "patch" { + if _, ok := rs.rootSelected(path); !ok || rs.pruning == unpruned { + needFullGraph = true +@@ -175,7 +179,11 @@ func listModules(ctx context.Context, rs *Requirements, args []string, mode List + + matchedModule := map[module.Version]bool{} + for _, arg := range args { +- if path, vers, found := strings.Cut(arg, "@"); found { ++ path, vers, found, err := ParsePathVersion(arg) ++ if err != nil { ++ base.Fatalf("go: %v", err) ++ } ++ if found { + var current string + if mg == nil { + current, _ = rs.rootSelected(path) +@@ -308,3 +316,21 @@ func modinfoError(path, vers string, err error) *modinfo.ModuleError { + + return &modinfo.ModuleError{Err: err.Error()} + } ++ ++// ParsePathVersion parses arg expecting arg to be path@version. If there is no ++// '@' in arg, found is false, vers is "", and path is arg. This mirrors the ++// typical usage of strings.Cut. ParsePathVersion is meant to be a general ++// replacement for strings.Cut in module version parsing. If the version is ++// invalid, an error is returned. The version is considered invalid if it is ++// prefixed with '-' or '/', which can cause security problems when constructing ++// commands to execute that use the version. ++func ParsePathVersion(arg string) (path, vers string, found bool, err error) { ++ path, vers, found = strings.Cut(arg, "@") ++ if !found { ++ return arg, "", false, nil ++ } ++ if len(vers) > 0 && (vers[0] == '-' || vers[0] == '/') { ++ return "", "", false, fmt.Errorf("invalid module version %q", vers) ++ } ++ return path, vers, true, nil ++} +diff --git a/src/cmd/go/internal/toolchain/select.go b/src/cmd/go/internal/toolchain/select.go +index 14a8d3c21d..838ebae6a7 100644 +--- a/src/cmd/go/internal/toolchain/select.go ++++ b/src/cmd/go/internal/toolchain/select.go +@@ -614,7 +614,10 @@ func goInstallVersion() bool { + if !strings.Contains(pkgArg, "@") || build.IsLocalImport(pkgArg) || filepath.IsAbs(pkgArg) { + return false + } +- path, version, _ := strings.Cut(pkgArg, "@") ++ path, version, _, err := modload.ParsePathVersion(pkgArg) ++ if err != nil { ++ base.Fatalf("go: %v", err) ++ } + if path == "" || version == "" || gover.IsToolchain(path) { + return false + } +@@ -650,7 +653,7 @@ func goInstallVersion() bool { + allowed = nil + } + noneSelected := func(path string) (version string) { return "none" } +- _, err := modload.QueryPackages(ctx, path, version, noneSelected, allowed) ++ _, err = modload.QueryPackages(ctx, path, version, noneSelected, allowed) + if errors.Is(err, gover.ErrTooNew) { + // Run early switch, same one go install or go run would eventually do, + // if it understood all the command-line flags. +diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go +index 60f76d77cf..55bf25ff62 100644 +--- a/src/cmd/go/internal/vcs/vcs.go ++++ b/src/cmd/go/internal/vcs/vcs.go +@@ -17,7 +17,6 @@ import ( + "os" + "os/exec" + "path/filepath" +- "regexp" + "strconv" + "strings" + "sync" +@@ -40,20 +39,10 @@ type Cmd struct { + Env []string // any environment values to set/override + RootNames []rootName // filename and mode indicating the root of a checkout directory + +- CreateCmd []string // commands to download a fresh copy of a repository +- DownloadCmd []string // commands to download updates into an existing repository +- +- TagCmd []tagCmd // commands to list tags +- TagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd +- TagSyncCmd []string // commands to sync to specific tag +- TagSyncDefault []string // commands to sync to default tag +- + Scheme []string + PingCmd string + +- RemoteRepo func(v *Cmd, rootDir string) (remoteRepo string, err error) +- ResolveRepo func(v *Cmd, rootDir, remoteRepo string) (realRepo string, err error) +- Status func(v *Cmd, rootDir string) (Status, error) ++ Status func(v *Cmd, rootDir string) (Status, error) + } + + // Status is the current state of a local repository. +@@ -156,40 +145,16 @@ var vcsHg = &Cmd{ + Name: "Mercurial", + Cmd: "hg", + +- // HGPLAIN=1 turns off additional output that a user may have enabled via +- // config options or certain extensions. +- Env: []string{"HGPLAIN=1"}, ++ // HGPLAIN=+strictflags turns off additional output that a user may have ++ // enabled via config options or certain extensions. ++ Env: []string{"HGPLAIN=+strictflags"}, + RootNames: []rootName{ + {filename: ".hg", isDir: true}, + }, + +- CreateCmd: []string{"clone -U -- {repo} {dir}"}, +- DownloadCmd: []string{"pull"}, +- +- // We allow both tag and branch names as 'tags' +- // for selecting a version. This lets people have +- // a go.release.r60 branch and a go1 branch +- // and make changes in both, without constantly +- // editing .hgtags. +- TagCmd: []tagCmd{ +- {"tags", `^(\S+)`}, +- {"branches", `^(\S+)`}, +- }, +- TagSyncCmd: []string{"update -r {tag}"}, +- TagSyncDefault: []string{"update default"}, +- +- Scheme: []string{"https", "http", "ssh"}, +- PingCmd: "identify -- {scheme}://{repo}", +- RemoteRepo: hgRemoteRepo, +- Status: hgStatus, +-} +- +-func hgRemoteRepo(vcsHg *Cmd, rootDir string) (remoteRepo string, err error) { +- out, err := vcsHg.runOutput(rootDir, "paths default") +- if err != nil { +- return "", err +- } +- return strings.TrimSpace(string(out)), nil ++ Scheme: []string{"https", "http", "ssh"}, ++ PingCmd: "identify -- {scheme}://{repo}", ++ Status: hgStatus, + } + + func hgStatus(vcsHg *Cmd, rootDir string) (Status, error) { +@@ -252,25 +217,6 @@ var vcsGit = &Cmd{ + {filename: ".git", isDir: true}, + }, + +- CreateCmd: []string{"clone -- {repo} {dir}", "-go-internal-cd {dir} submodule update --init --recursive"}, +- DownloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"}, +- +- TagCmd: []tagCmd{ +- // tags/xxx matches a git tag named xxx +- // origin/xxx matches a git branch named xxx on the default remote repository +- {"show-ref", `(?:tags|origin)/(\S+)$`}, +- }, +- TagLookupCmd: []tagCmd{ +- {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, +- }, +- TagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"}, +- // both createCmd and downloadCmd update the working dir. +- // No need to do more here. We used to 'checkout master' +- // but that doesn't work if the default branch is not named master. +- // DO NOT add 'checkout master' here. +- // See golang.org/issue/9032. +- TagSyncDefault: []string{"submodule update --init --recursive"}, +- + Scheme: []string{"git", "https", "http", "git+ssh", "ssh"}, + + // Leave out the '--' separator in the ls-remote command: git 2.7.4 does not +@@ -279,54 +225,7 @@ var vcsGit = &Cmd{ + // See golang.org/issue/33836. + PingCmd: "ls-remote {scheme}://{repo}", + +- RemoteRepo: gitRemoteRepo, +- Status: gitStatus, +-} +- +-// scpSyntaxRe matches the SCP-like addresses used by Git to access +-// repositories by SSH. +-var scpSyntaxRe = lazyregexp.New(`^(\w+)@([\w.-]+):(.*)$`) +- +-func gitRemoteRepo(vcsGit *Cmd, rootDir string) (remoteRepo string, err error) { +- const cmd = "config remote.origin.url" +- outb, err := vcsGit.run1(rootDir, cmd, nil, false) +- if err != nil { +- // if it doesn't output any message, it means the config argument is correct, +- // but the config value itself doesn't exist +- if outb != nil && len(outb) == 0 { +- return "", errors.New("remote origin not found") +- } +- return "", err +- } +- out := strings.TrimSpace(string(outb)) +- +- var repoURL *urlpkg.URL +- if m := scpSyntaxRe.FindStringSubmatch(out); m != nil { +- // Match SCP-like syntax and convert it to a URL. +- // Eg, "git@github.com:user/repo" becomes +- // "ssh://git@github.com/user/repo". +- repoURL = &urlpkg.URL{ +- Scheme: "ssh", +- User: urlpkg.User(m[1]), +- Host: m[2], +- Path: m[3], +- } +- } else { +- repoURL, err = urlpkg.Parse(out) +- if err != nil { +- return "", err +- } +- } +- +- // Iterate over insecure schemes too, because this function simply +- // reports the state of the repo. If we can't see insecure schemes then +- // we can't report the actual repo URL. +- for _, s := range vcsGit.Scheme { +- if repoURL.Scheme == s { +- return repoURL.String(), nil +- } +- } +- return "", errors.New("unable to parse output of git " + cmd) ++ Status: gitStatus, + } + + func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) { +@@ -366,62 +265,9 @@ var vcsBzr = &Cmd{ + {filename: ".bzr", isDir: true}, + }, + +- CreateCmd: []string{"branch -- {repo} {dir}"}, +- +- // Without --overwrite bzr will not pull tags that changed. +- // Replace by --overwrite-tags after http://pad.lv/681792 goes in. +- DownloadCmd: []string{"pull --overwrite"}, +- +- TagCmd: []tagCmd{{"tags", `^(\S+)`}}, +- TagSyncCmd: []string{"update -r {tag}"}, +- TagSyncDefault: []string{"update -r revno:-1"}, +- +- Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, +- PingCmd: "info -- {scheme}://{repo}", +- RemoteRepo: bzrRemoteRepo, +- ResolveRepo: bzrResolveRepo, +- Status: bzrStatus, +-} +- +-func bzrRemoteRepo(vcsBzr *Cmd, rootDir string) (remoteRepo string, err error) { +- outb, err := vcsBzr.runOutput(rootDir, "config parent_location") +- if err != nil { +- return "", err +- } +- return strings.TrimSpace(string(outb)), nil +-} +- +-func bzrResolveRepo(vcsBzr *Cmd, rootDir, remoteRepo string) (realRepo string, err error) { +- outb, err := vcsBzr.runOutput(rootDir, "info "+remoteRepo) +- if err != nil { +- return "", err +- } +- out := string(outb) +- +- // Expect: +- // ... +- // (branch root|repository branch): +- // ... +- +- found := false +- for _, prefix := range []string{"\n branch root: ", "\n repository branch: "} { +- i := strings.Index(out, prefix) +- if i >= 0 { +- out = out[i+len(prefix):] +- found = true +- break +- } +- } +- if !found { +- return "", fmt.Errorf("unable to parse output of bzr info") +- } +- +- i := strings.Index(out, "\n") +- if i < 0 { +- return "", fmt.Errorf("unable to parse output of bzr info") +- } +- out = out[:i] +- return strings.TrimSpace(out), nil ++ Scheme: []string{"https", "http", "bzr", "bzr+ssh"}, ++ PingCmd: "info -- {scheme}://{repo}", ++ Status: bzrStatus, + } + + func bzrStatus(vcsBzr *Cmd, rootDir string) (Status, error) { +@@ -489,45 +335,11 @@ var vcsSvn = &Cmd{ + {filename: ".svn", isDir: true}, + }, + +- CreateCmd: []string{"checkout -- {repo} {dir}"}, +- DownloadCmd: []string{"update"}, +- + // There is no tag command in subversion. + // The branch information is all in the path names. + +- Scheme: []string{"https", "http", "svn", "svn+ssh"}, +- PingCmd: "info -- {scheme}://{repo}", +- RemoteRepo: svnRemoteRepo, +-} +- +-func svnRemoteRepo(vcsSvn *Cmd, rootDir string) (remoteRepo string, err error) { +- outb, err := vcsSvn.runOutput(rootDir, "info") +- if err != nil { +- return "", err +- } +- out := string(outb) +- +- // Expect: +- // +- // ... +- // URL: +- // ... +- // +- // Note that we're not using the Repository Root line, +- // because svn allows checking out subtrees. +- // The URL will be the URL of the subtree (what we used with 'svn co') +- // while the Repository Root may be a much higher parent. +- i := strings.Index(out, "\nURL: ") +- if i < 0 { +- return "", fmt.Errorf("unable to parse output of svn info") +- } +- out = out[i+len("\nURL: "):] +- i = strings.Index(out, "\n") +- if i < 0 { +- return "", fmt.Errorf("unable to parse output of svn info") +- } +- out = out[:i] +- return strings.TrimSpace(out), nil ++ Scheme: []string{"https", "http", "svn", "svn+ssh"}, ++ PingCmd: "info -- {scheme}://{repo}", + } + + // fossilRepoName is the name go get associates with a fossil repository. In the +@@ -543,24 +355,8 @@ var vcsFossil = &Cmd{ + {filename: "_FOSSIL_", isDir: false}, + }, + +- CreateCmd: []string{"-go-internal-mkdir {dir} clone -- {repo} " + filepath.Join("{dir}", fossilRepoName), "-go-internal-cd {dir} open .fossil"}, +- DownloadCmd: []string{"up"}, +- +- TagCmd: []tagCmd{{"tag ls", `(.*)`}}, +- TagSyncCmd: []string{"up tag:{tag}"}, +- TagSyncDefault: []string{"up trunk"}, +- +- Scheme: []string{"https", "http"}, +- RemoteRepo: fossilRemoteRepo, +- Status: fossilStatus, +-} +- +-func fossilRemoteRepo(vcsFossil *Cmd, rootDir string) (remoteRepo string, err error) { +- out, err := vcsFossil.runOutput(rootDir, "remote-url") +- if err != nil { +- return "", err +- } +- return strings.TrimSpace(string(out)), nil ++ Scheme: []string{"https", "http"}, ++ Status: fossilStatus, + } + + var errFossilInfo = errors.New("unable to parse output of fossil info") +@@ -661,7 +457,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ + args[i] = expand(m, arg) + } + +- if len(args) >= 2 && args[0] == "-go-internal-mkdir" { ++ if len(args) >= 2 && args[0] == "--go-internal-mkdir" { + var err error + if filepath.IsAbs(args[1]) { + err = os.Mkdir(args[1], fs.ModePerm) +@@ -674,7 +470,7 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ + args = args[2:] + } + +- if len(args) >= 2 && args[0] == "-go-internal-cd" { ++ if len(args) >= 2 && args[0] == "--go-internal-cd" { + if filepath.IsAbs(args[1]) { + dir = args[1] + } else { +@@ -735,99 +531,6 @@ func (v *Cmd) Ping(scheme, repo string) error { + return v.runVerboseOnly(dir, v.PingCmd, "scheme", scheme, "repo", repo) + } + +-// Create creates a new copy of repo in dir. +-// The parent of dir must exist; dir must not. +-func (v *Cmd) Create(dir, repo string) error { +- release, err := base.AcquireNet() +- if err != nil { +- return err +- } +- defer release() +- +- for _, cmd := range v.CreateCmd { +- if err := v.run(filepath.Dir(dir), cmd, "dir", dir, "repo", repo); err != nil { +- return err +- } +- } +- return nil +-} +- +-// Download downloads any new changes for the repo in dir. +-func (v *Cmd) Download(dir string) error { +- release, err := base.AcquireNet() +- if err != nil { +- return err +- } +- defer release() +- +- for _, cmd := range v.DownloadCmd { +- if err := v.run(dir, cmd); err != nil { +- return err +- } +- } +- return nil +-} +- +-// Tags returns the list of available tags for the repo in dir. +-func (v *Cmd) Tags(dir string) ([]string, error) { +- var tags []string +- for _, tc := range v.TagCmd { +- out, err := v.runOutput(dir, tc.cmd) +- if err != nil { +- return nil, err +- } +- re := regexp.MustCompile(`(?m-s)` + tc.pattern) +- for _, m := range re.FindAllStringSubmatch(string(out), -1) { +- tags = append(tags, m[1]) +- } +- } +- return tags, nil +-} +- +-// TagSync syncs the repo in dir to the named tag, +-// which either is a tag returned by tags or is v.tagDefault. +-func (v *Cmd) TagSync(dir, tag string) error { +- if v.TagSyncCmd == nil { +- return nil +- } +- if tag != "" { +- for _, tc := range v.TagLookupCmd { +- out, err := v.runOutput(dir, tc.cmd, "tag", tag) +- if err != nil { +- return err +- } +- re := regexp.MustCompile(`(?m-s)` + tc.pattern) +- m := re.FindStringSubmatch(string(out)) +- if len(m) > 1 { +- tag = m[1] +- break +- } +- } +- } +- +- release, err := base.AcquireNet() +- if err != nil { +- return err +- } +- defer release() +- +- if tag == "" && v.TagSyncDefault != nil { +- for _, cmd := range v.TagSyncDefault { +- if err := v.run(dir, cmd); err != nil { +- return err +- } +- } +- return nil +- } +- +- for _, cmd := range v.TagSyncCmd { +- if err := v.run(dir, cmd, "tag", tag); err != nil { +- return err +- } +- } +- return nil +-} +- + // A vcsPath describes how to convert an import path into a + // version control system and repository name. + type vcsPath struct { +diff --git a/src/cmd/go/internal/workcmd/edit.go b/src/cmd/go/internal/workcmd/edit.go +index 8d975b0b3d..c1252cc95e 100644 +--- a/src/cmd/go/internal/workcmd/edit.go ++++ b/src/cmd/go/internal/workcmd/edit.go +@@ -242,7 +242,10 @@ func allowedVersionArg(arg string) bool { + // parsePathVersionOptional parses path[@version], using adj to + // describe any errors. + func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version string, err error) { +- before, after, found := strings.Cut(arg, "@") ++ before, after, found, err := modload.ParsePathVersion(arg) ++ if err != nil { ++ return "", "", err ++ } + if !found { + path = arg + } else { +-- +2.35.6