From f55cedce1b9c11ca2384f5164759250b4caa63a4 Mon Sep 17 00:00:00 2001 From: jianli-97 Date: Thu, 22 Aug 2024 10:30:00 +0800 Subject: [PATCH] fix CVE-2023-48795 --- 0001-fix-CVE-2023-48795.patch | 481 ++++++++++++++++++++++++++++++++++ podman.spec | 7 +- 2 files changed, 487 insertions(+), 1 deletion(-) create mode 100644 0001-fix-CVE-2023-48795.patch diff --git a/0001-fix-CVE-2023-48795.patch b/0001-fix-CVE-2023-48795.patch new file mode 100644 index 0000000..9f369e7 --- /dev/null +++ b/0001-fix-CVE-2023-48795.patch @@ -0,0 +1,481 @@ +From 31452ba546c48601c33e6b94c50b54125625272b Mon Sep 17 00:00:00 2001 +From: jianli-97 +Date: Thu, 22 Aug 2024 10:23:15 +0800 +Subject: [PATCH] fix CVE-2023-48795 + +--- + .../golang.org/x/crypto/ssh/handshake.go | 85 ++++++++++++++++++- + .../golang.org/x/crypto/ssh/transport.go | 32 +++++-- + vendor/golang.org/x/crypto/ssh/handshake.go | 85 ++++++++++++++++++- + vendor/golang.org/x/crypto/ssh/transport.go | 32 +++++-- + 4 files changed, 216 insertions(+), 18 deletions(-) + +diff --git a/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/handshake.go b/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/handshake.go +index 2b10b05..de7ac9a 100644 +--- a/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/handshake.go ++++ b/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/handshake.go +@@ -34,6 +34,16 @@ type keyingTransport interface { + // direction will be effected if a msgNewKeys message is sent + // or received. + prepareKeyChange(*algorithms, *kexResult) error ++ ++ // setStrictMode sets the strict KEX mode, notably triggering ++ // sequence number resets on sending or receiving msgNewKeys. ++ // If the sequence number is already > 1 when setStrictMode ++ // is called, an error is returned. ++ setStrictMode() error ++ ++ // setInitialKEXDone indicates to the transport that the initial key exchange ++ // was completed ++ setInitialKEXDone() + } + + // handshakeTransport implements rekeying on top of a keyingTransport +@@ -94,6 +104,10 @@ type handshakeTransport struct { + + // The session ID or nil if first kex did not complete yet. + sessionID []byte ++ ++ // strictMode indicates if the other side of the handshake indicated ++ // that we should be following the strict KEX protocol restrictions. ++ strictMode bool + } + + type pendingKex struct { +@@ -201,7 +215,10 @@ func (t *handshakeTransport) readLoop() { + close(t.incoming) + break + } +- if p[0] == msgIgnore || p[0] == msgDebug { ++ // If this is the first kex, and strict KEX mode is enabled, ++ // we don't ignore any messages, as they may be used to manipulate ++ // the packet sequence numbers. ++ if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) { + continue + } + t.incoming <- p +@@ -432,6 +449,11 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { + return successPacket, nil + } + ++const ( ++ kexStrictClient = "kex-strict-c-v00@openssh.com" ++ kexStrictServer = "kex-strict-s-v00@openssh.com" ++) ++ + // sendKexInit sends a key change message. + func (t *handshakeTransport) sendKexInit() error { + t.mu.Lock() +@@ -455,14 +477,56 @@ func (t *handshakeTransport) sendKexInit() error { + } + io.ReadFull(rand.Reader, msg.Cookie[:]) + +- if len(t.hostKeys) > 0 { ++ // We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm, ++ // and possibly to add the ext-info extension algorithm. Since the slice may be the ++ // user owned KeyExchanges, we create our own slice in order to avoid using user ++ // owned memory by mistake. ++ msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info ++ msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) ++ ++ isServer := len(t.hostKeys) > 0 ++ if isServer { + for _, k := range t.hostKeys { +- msg.ServerHostKeyAlgos = append( +- msg.ServerHostKeyAlgos, k.PublicKey().Type()) ++ // If k is a MultiAlgorithmSigner, we restrict the signature ++ // algorithms. If k is a AlgorithmSigner, presume it supports all ++ // signature algorithms associated with the key format. If k is not ++ // an AlgorithmSigner, we can only assume it only supports the ++ // algorithms that matches the key format. (This means that Sign ++ // can't pick a different default). ++ keyFormat := k.PublicKey().Type() ++ switch s := k.(type) { ++ case MultiAlgorithmSigner: ++ for _, algo := range algorithmsForKeyFormat(keyFormat) { ++ if contains(s.Algorithms(), underlyingAlgo(algo)) { ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) ++ } ++ } ++ case AlgorithmSigner: ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...) ++ default: ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) ++ } ++ } ++ ++ if t.sessionID == nil { ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictServer) + } + } else { + msg.ServerHostKeyAlgos = t.hostKeyAlgorithms ++ ++ // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what ++ // algorithms the server supports for public key authentication. See RFC ++ // 8308, Section 2.1. ++ // ++ // We also send the strict KEX mode extension algorithm, in order to opt ++ // into the strict KEX mode. ++ if firstKeyExchange := t.sessionID == nil; firstKeyExchange { ++ msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictClient) ++ } ++ + } ++ + packet := Marshal(msg) + + // writePacket destroys the contents, so save a copy. +@@ -557,6 +621,13 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + return err + } + ++ if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) { ++ t.strictMode = true ++ if err := t.conn.setStrictMode(); err != nil { ++ return err ++ } ++ } ++ + // We don't send FirstKexFollows, but we handle receiving it. + // + // RFC 4253 section 7 defines the kex and the agreement method for +@@ -608,6 +679,12 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + return unexpectedMessageError(msgNewKeys, packet[0]) + } + ++ if firstKeyExchange { ++ // Indicates to the transport that the first key exchange is completed ++ // after receiving SSH_MSG_NEWKEYS. ++ t.conn.setInitialKEXDone() ++ } ++ + return nil + } + +diff --git a/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/transport.go b/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/transport.go +index 49ddc2e..379e4a8 100644 +--- a/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/transport.go ++++ b/gvisor-tap-vsock-4ee84d66bd86668f011733d8873989b5862bcd07/vendor/golang.org/x/crypto/ssh/transport.go +@@ -48,6 +48,9 @@ type transport struct { + rand io.Reader + isClient bool + io.Closer ++ ++ strictMode bool ++ initialKEXDone bool + } + + // packetCipher represents a combination of SSH encryption/MAC +@@ -73,6 +76,18 @@ type connectionState struct { + pendingKeyChange chan packetCipher + } + ++func (t *transport) setStrictMode() error { ++ if t.reader.seqNum != 1 { ++ return errors.New("ssh: sequence number != 1 when strict KEX mode requested") ++ } ++ t.strictMode = true ++ return nil ++} ++ ++func (t *transport) setInitialKEXDone() { ++ t.initialKEXDone = true ++} ++ + // prepareKeyChange sets up key material for a keychange. The key changes in + // both directions are triggered by reading and writing a msgNewKey packet + // respectively. +@@ -111,11 +126,12 @@ func (t *transport) printPacket(p []byte, write bool) { + // Read and decrypt next packet. + func (t *transport) readPacket() (p []byte, err error) { + for { +- p, err = t.reader.readPacket(t.bufReader) ++ p, err = t.reader.readPacket(t.bufReader, t.strictMode) + if err != nil { + break + } +- if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { ++ // in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX ++ if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) { + break + } + } +@@ -126,7 +142,7 @@ func (t *transport) readPacket() (p []byte, err error) { + return p, err + } + +-func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { ++func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) { + packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) + s.seqNum++ + if err == nil && len(packet) == 0 { +@@ -139,6 +155,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher ++ if strictMode { ++ s.seqNum = 0 ++ } + default: + return nil, errors.New("ssh: got bogus newkeys message") + } +@@ -169,10 +188,10 @@ func (t *transport) writePacket(packet []byte) error { + if debugTransport { + t.printPacket(packet, true) + } +- return t.writer.writePacket(t.bufWriter, t.rand, packet) ++ return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode) + } + +-func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { ++func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error { + changeKeys := len(packet) > 0 && packet[0] == msgNewKeys + + err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) +@@ -187,6 +206,9 @@ func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet [] + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher ++ if strictMode { ++ s.seqNum = 0 ++ } + default: + panic("ssh: no key material for msgNewKeys") + } +diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go +index 2b10b05..de7ac9a 100644 +--- a/vendor/golang.org/x/crypto/ssh/handshake.go ++++ b/vendor/golang.org/x/crypto/ssh/handshake.go +@@ -34,6 +34,16 @@ type keyingTransport interface { + // direction will be effected if a msgNewKeys message is sent + // or received. + prepareKeyChange(*algorithms, *kexResult) error ++ ++ // setStrictMode sets the strict KEX mode, notably triggering ++ // sequence number resets on sending or receiving msgNewKeys. ++ // If the sequence number is already > 1 when setStrictMode ++ // is called, an error is returned. ++ setStrictMode() error ++ ++ // setInitialKEXDone indicates to the transport that the initial key exchange ++ // was completed ++ setInitialKEXDone() + } + + // handshakeTransport implements rekeying on top of a keyingTransport +@@ -94,6 +104,10 @@ type handshakeTransport struct { + + // The session ID or nil if first kex did not complete yet. + sessionID []byte ++ ++ // strictMode indicates if the other side of the handshake indicated ++ // that we should be following the strict KEX protocol restrictions. ++ strictMode bool + } + + type pendingKex struct { +@@ -201,7 +215,10 @@ func (t *handshakeTransport) readLoop() { + close(t.incoming) + break + } +- if p[0] == msgIgnore || p[0] == msgDebug { ++ // If this is the first kex, and strict KEX mode is enabled, ++ // we don't ignore any messages, as they may be used to manipulate ++ // the packet sequence numbers. ++ if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) { + continue + } + t.incoming <- p +@@ -432,6 +449,11 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { + return successPacket, nil + } + ++const ( ++ kexStrictClient = "kex-strict-c-v00@openssh.com" ++ kexStrictServer = "kex-strict-s-v00@openssh.com" ++) ++ + // sendKexInit sends a key change message. + func (t *handshakeTransport) sendKexInit() error { + t.mu.Lock() +@@ -455,14 +477,56 @@ func (t *handshakeTransport) sendKexInit() error { + } + io.ReadFull(rand.Reader, msg.Cookie[:]) + +- if len(t.hostKeys) > 0 { ++ // We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm, ++ // and possibly to add the ext-info extension algorithm. Since the slice may be the ++ // user owned KeyExchanges, we create our own slice in order to avoid using user ++ // owned memory by mistake. ++ msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info ++ msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) ++ ++ isServer := len(t.hostKeys) > 0 ++ if isServer { + for _, k := range t.hostKeys { +- msg.ServerHostKeyAlgos = append( +- msg.ServerHostKeyAlgos, k.PublicKey().Type()) ++ // If k is a MultiAlgorithmSigner, we restrict the signature ++ // algorithms. If k is a AlgorithmSigner, presume it supports all ++ // signature algorithms associated with the key format. If k is not ++ // an AlgorithmSigner, we can only assume it only supports the ++ // algorithms that matches the key format. (This means that Sign ++ // can't pick a different default). ++ keyFormat := k.PublicKey().Type() ++ switch s := k.(type) { ++ case MultiAlgorithmSigner: ++ for _, algo := range algorithmsForKeyFormat(keyFormat) { ++ if contains(s.Algorithms(), underlyingAlgo(algo)) { ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algo) ++ } ++ } ++ case AlgorithmSigner: ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, algorithmsForKeyFormat(keyFormat)...) ++ default: ++ msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) ++ } ++ } ++ ++ if t.sessionID == nil { ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictServer) + } + } else { + msg.ServerHostKeyAlgos = t.hostKeyAlgorithms ++ ++ // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what ++ // algorithms the server supports for public key authentication. See RFC ++ // 8308, Section 2.1. ++ // ++ // We also send the strict KEX mode extension algorithm, in order to opt ++ // into the strict KEX mode. ++ if firstKeyExchange := t.sessionID == nil; firstKeyExchange { ++ msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictClient) ++ } ++ + } ++ + packet := Marshal(msg) + + // writePacket destroys the contents, so save a copy. +@@ -557,6 +621,13 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + return err + } + ++ if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) { ++ t.strictMode = true ++ if err := t.conn.setStrictMode(); err != nil { ++ return err ++ } ++ } ++ + // We don't send FirstKexFollows, but we handle receiving it. + // + // RFC 4253 section 7 defines the kex and the agreement method for +@@ -608,6 +679,12 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { + return unexpectedMessageError(msgNewKeys, packet[0]) + } + ++ if firstKeyExchange { ++ // Indicates to the transport that the first key exchange is completed ++ // after receiving SSH_MSG_NEWKEYS. ++ t.conn.setInitialKEXDone() ++ } ++ + return nil + } + +diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go +index 49ddc2e..379e4a8 100644 +--- a/vendor/golang.org/x/crypto/ssh/transport.go ++++ b/vendor/golang.org/x/crypto/ssh/transport.go +@@ -48,6 +48,9 @@ type transport struct { + rand io.Reader + isClient bool + io.Closer ++ ++ strictMode bool ++ initialKEXDone bool + } + + // packetCipher represents a combination of SSH encryption/MAC +@@ -73,6 +76,18 @@ type connectionState struct { + pendingKeyChange chan packetCipher + } + ++func (t *transport) setStrictMode() error { ++ if t.reader.seqNum != 1 { ++ return errors.New("ssh: sequence number != 1 when strict KEX mode requested") ++ } ++ t.strictMode = true ++ return nil ++} ++ ++func (t *transport) setInitialKEXDone() { ++ t.initialKEXDone = true ++} ++ + // prepareKeyChange sets up key material for a keychange. The key changes in + // both directions are triggered by reading and writing a msgNewKey packet + // respectively. +@@ -111,11 +126,12 @@ func (t *transport) printPacket(p []byte, write bool) { + // Read and decrypt next packet. + func (t *transport) readPacket() (p []byte, err error) { + for { +- p, err = t.reader.readPacket(t.bufReader) ++ p, err = t.reader.readPacket(t.bufReader, t.strictMode) + if err != nil { + break + } +- if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { ++ // in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX ++ if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) { + break + } + } +@@ -126,7 +142,7 @@ func (t *transport) readPacket() (p []byte, err error) { + return p, err + } + +-func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { ++func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) { + packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) + s.seqNum++ + if err == nil && len(packet) == 0 { +@@ -139,6 +155,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher ++ if strictMode { ++ s.seqNum = 0 ++ } + default: + return nil, errors.New("ssh: got bogus newkeys message") + } +@@ -169,10 +188,10 @@ func (t *transport) writePacket(packet []byte) error { + if debugTransport { + t.printPacket(packet, true) + } +- return t.writer.writePacket(t.bufWriter, t.rand, packet) ++ return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode) + } + +-func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { ++func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error { + changeKeys := len(packet) > 0 && packet[0] == msgNewKeys + + err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) +@@ -187,6 +206,9 @@ func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet [] + select { + case cipher := <-s.pendingKeyChange: + s.packetCipher = cipher ++ if strictMode { ++ s.seqNum = 0 ++ } + default: + panic("ssh: no key material for msgNewKeys") + } +-- +2.33.0 + diff --git a/podman.spec b/podman.spec index 69b7873..d131f20 100644 --- a/podman.spec +++ b/podman.spec @@ -2,7 +2,7 @@ Name: podman Version: 3.4.4 -Release: 2 +Release: 3 Summary: A daemonless container engine for managing Containers Epoch: 1 License: ASL 2.0 @@ -66,6 +66,7 @@ Provides: bundled(golang(k8s.io/apimachinery)) = v0.19.0 Patch1: 0001-Fix-the-invalid-memory-address-reference.patch Patch2: 0002-add-openEuler-hardened-ld.patch Patch3: 0001-CVE-2022-32149.patch +Patch4: 0001-fix-CVE-2023-48795.patch %description Podman manages the entire container ecosystem which includes pods, @@ -153,6 +154,7 @@ tar -xf %SOURCE4 %patch1 -p1 %patch2 -p1 %patch3 -p1 +%patch4 -p1 %build GO_MD2MAN_PATH="$(pwd)%{_bindir}" @@ -323,6 +325,9 @@ done %{_libexecdir}/%{name}/gvproxy %changelog +* Thu Aug 22 2024 lijian - 1:3.4.4-3 +- Fix CVE-2023-48795 + * Thu Apr 25 2024 lijian - 1:3.4.4-2 - Fix CVE-2022-32149 -- Gitee