Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kubevirt1.8 for openSUSE:Factory 
checked in at 2026-10-22 15:50:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kubevirt1.8 (Old)
 and      /work/SRC/openSUSE:Factory/.kubevirt1.8.new.2252680 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kubevirt1.8"

Thu Oct 22 15:50:54 2026 rev:8 rq:1386988 version:1.8.4

Changes:
--------
--- /work/SRC/openSUSE:Factory/kubevirt1.8/kubevirt1.8.changes  2026-08-26 
19:52:44.097647059 +0200
+++ /work/SRC/openSUSE:Factory/.kubevirt1.8.new.2252680/kubevirt1.8.changes     
2026-10-22 15:54:47.230398203 +0200
@@ -11,0 +12,16 @@
+Mon Aug  3 23:14:03 UTC 2026 - Victor Carvalho <[email protected]>
+
+- Add 0003-use-safepath-when-dialing-the-migration-target-unix-sockets.patch:
+  CVE-2026-13622 (bsc#1272840) —
+  virt-handler dials the migration target unix sockets through
+  /proc/<pid>/root of the virt-launcher pod; resolve the socket path
+  with safepath and dial via ExecuteNoFollow so a symlink planted
+  inside the launcher filesystem cannot redirect the connection.
+  Unsupported target protocols are now rejected instead of dialed.
+- Add 0004-tests-dial-migration-target-sockets-through-proc-root-layout.patch:
+  the migration-proxy unit tests dialed target sockets straight out of a
+  temporary directory, which is not below a /proc/<pid>/root and is
+  therefore refused by the resolution above; place those sockets under a
+  "root" directory so they keep the shape they have in production.
+
+-------------------------------------------------------------------

New:
----
  0003-use-safepath-when-dialing-the-migration-target-unix-sockets.patch
  0004-tests-dial-migration-target-sockets-through-proc-root-layout.patch

----------(New B)----------
  New:
- Add 0003-use-safepath-when-dialing-the-migration-target-unix-sockets.patch:
  CVE-2026-13622 (bsc#1272840) —
  New:  Unsupported target protocols are now rejected instead of dialed.
- Add 0004-tests-dial-migration-target-sockets-through-proc-root-layout.patch:
  the migration-proxy unit tests dialed target sockets straight out of a
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kubevirt1.8.spec ++++++
--- /var/tmp/diff_new_pack.8bpnaz/_old  2026-10-22 15:54:48.135436139 +0200
+++ /var/tmp/diff_new_pack.8bpnaz/_new  2026-10-22 15:54:48.136436181 +0200
@@ -32,6 +32,8 @@
 Source3:        %{url}/releases/download/v%{version}/disks-images-provider.yaml
 Patch0001:      0001-safepath-make-sure-whole-path-has-no-symlink.patch
 Patch0002:      0002-console-use-JoinNoFollow-for-console-socket-path.patch
+Patch0003:      
0003-use-safepath-when-dialing-the-migration-target-unix-sockets.patch
+Patch0004:      
0004-tests-dial-migration-target-sockets-through-proc-root-layout.patch
 Source100:      %{name}-rpmlintrc
 BuildRequires:  glibc-devel-static
 BuildRequires:  golang-packaging

++++++ 0003-use-safepath-when-dialing-the-migration-target-unix-sockets.patch 
++++++
>From ee94588903e1a6aa21af28d4e7ef1e8085ab916c Mon Sep 17 00:00:00 2001
From: Igor Bezukh <[email protected]>
Date: Thu, 16 Jul 2026 13:10:51 +0300
Subject: [PATCH 1/2] use safepath when dialing the migration target unix
 sockets

since the target socket file resides on virt-launcher,
the handler constructs the path using /proc/<pid>/root.
using safe path will keep the dial process protected
from symlink attacks.

Signed-off-by: Igor Bezukh <[email protected]>
---
 .../migration-proxy/migration-proxy.go        | 76 ++++++++++++++++---
 1 file changed, 64 insertions(+), 12 deletions(-)

diff --git a/pkg/virt-handler/migration-proxy/migration-proxy.go 
b/pkg/virt-handler/migration-proxy/migration-proxy.go
index e7ab78a..6a4a42a 100644
--- a/pkg/virt-handler/migration-proxy/migration-proxy.go
+++ b/pkg/virt-handler/migration-proxy/migration-proxy.go
@@ -33,6 +33,7 @@ import (
        "kubevirt.io/client-go/log"
 
        diskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
+       "kubevirt.io/kubevirt/pkg/safepath"
        "kubevirt.io/kubevirt/pkg/util"
        "kubevirt.io/kubevirt/pkg/util/net/ip"
        virtconfig "kubevirt.io/kubevirt/pkg/virt-config"
@@ -443,22 +444,28 @@ func (m *migrationProxy) handleConnection(fd net.Conn) {
        inBoundErr := make(chan error, 1)
 
        var conn net.Conn
-       var err error
+       var dialErr error
        if m.targetProtocol == "tcp" && m.clientTLSConfig != nil {
-               conn, err = tls.Dial(m.targetProtocol, m.targetAddress, 
m.migrationTLSConfig)
+               conn, dialErr = tls.Dial(m.targetProtocol, m.targetAddress, 
m.migrationTLSConfig)
                // Check for specific error (CN missmatch), fallback to old 
client TLS
-               if err != nil {
-                       m.logger.Reason(err).Info("fallback to old tls config")
-                       conn, err = tls.Dial(m.targetProtocol, m.targetAddress, 
m.clientTLSConfig)
+               if dialErr != nil {
+                       m.logger.Reason(dialErr).Info("fallback to old tls 
config")
+                       conn, dialErr = tls.Dial(m.targetProtocol, 
m.targetAddress, m.clientTLSConfig)
                } else if tlsErr := conn.(*tls.Conn).Handshake(); tlsErr != nil 
{
-                       m.logger.Reason(err).Info("handshake failed, fallback 
to old tls config")
-                       conn, err = tls.Dial(m.targetProtocol, m.targetAddress, 
m.clientTLSConfig)
+                       m.logger.Reason(tlsErr).Info("handshake failed, 
fallback to old tls config")
+                       conn, dialErr = tls.Dial(m.targetProtocol, 
m.targetAddress, m.clientTLSConfig)
                }
+       } else if m.targetProtocol == "tcp" {
+               conn, dialErr = net.Dial(m.targetProtocol, m.targetAddress)
+       } else if m.targetProtocol == "unix" {
+               conn, dialErr = dialUnixNoFollow(m.targetAddress)
        } else {
-               conn, err = net.Dial(m.targetProtocol, m.targetAddress)
+               m.logger.Errorf("unsupported target protocol: %s", 
m.targetProtocol)
+               return
        }
-       if err != nil {
-               m.logger.Reason(err).Error("unable to create outbound leg of 
proxy to host")
+
+       if dialErr != nil {
+               m.logger.Reason(dialErr).Errorf("unable to create outbound leg 
of proxy to host")
                return
        }
 
@@ -476,11 +483,11 @@ func (m *migrationProxy) handleConnection(fd net.Conn) {
        }()
 
        select {
-       case err = <-outBoundErr:
+       case err := <-outBoundErr:
                if err != nil {
                        m.logger.Reason(err).Errorf("error encountered copying 
data to outbound connection")
                }
-       case err = <-inBoundErr:
+       case err := <-inBoundErr:
                if err != nil {
                        m.logger.Reason(err).Errorf("error encountered copying 
data into inbound connection")
                }
@@ -489,6 +496,51 @@ func (m *migrationProxy) handleConnection(fd net.Conn) {
        }
 }
 
+const procRootMarker = "/root/"
+
+type procRootPath struct {
+       rootBase string
+       elems    []string
+}
+
+func splitProcRootPath(path string) (*procRootPath, error) {
+       idx := strings.Index(path, procRootMarker)
+       if idx == -1 {
+               return nil, fmt.Errorf("path %q does not contain %q marker", 
path, procRootMarker)
+       }
+       rootBase := path[:idx+len("/root")]
+       relativePath := path[idx+len(procRootMarker):]
+       if relativePath == "" {
+               return nil, fmt.Errorf("path %q has empty relative path after 
%q marker", path, procRootMarker)
+       }
+       return &procRootPath{
+               rootBase: rootBase,
+               elems:    strings.Split(relativePath, "/"),
+       }, nil
+}
+
+func dialUnixNoFollow(path string) (net.Conn, error) {
+       procPath, err := splitProcRootPath(path)
+       if err != nil {
+               return nil, err
+       }
+       safePath, err := 
safepath.JoinAndResolveWithRelativeRoot(procPath.rootBase, procPath.elems...)
+       if err != nil {
+               return nil, err
+       }
+
+       var conn net.Conn
+       err = safePath.ExecuteNoFollow(func(safePath string) error {
+               var dialErr error
+               conn, dialErr = net.Dial("unix", safePath)
+               return dialErr
+       })
+       if err != nil {
+               return nil, err
+       }
+       return conn, nil
+}
+
 func (m *migrationProxy) Start() error {
 
        if m.unixSocketPath != "" {

++++++ 0004-tests-dial-migration-target-sockets-through-proc-root-layout.patch 
++++++
>From 6b82d6c38d82a74eea76161024b7af0cf33fdfa0 Mon Sep 17 00:00:00 2001
From: Victor Carvalho <[email protected]>
Date: Tue, 4 Aug 2026 07:33:06 +0200
Subject: [PATCH 2/2] tests: dial migration target sockets through a
 /proc/<pid>/root layout

The migration proxy resolves the target unix socket relative to the
/proc/<pid>/root of the virt-launcher it belongs to, and rejects a path
that is not below such a root. The unit tests dialed sockets straight
out of a temporary directory, so the target proxy refused to connect and
the tests blocked on a listener that never accepted.

Place the sockets that act as proxy targets under a "root" directory
inside the temporary directory. The paths then have the same shape as in
production and exercise the same resolution. The source socket keeps its
place: the source proxy listens on it and dials TCP, so it never reaches
that code path.
---
 .../migration-proxy/migration-proxy_test.go      | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/pkg/virt-handler/migration-proxy/migration-proxy_test.go 
b/pkg/virt-handler/migration-proxy/migration-proxy_test.go
index 50c5e70..56d929c 100644
--- a/pkg/virt-handler/migration-proxy/migration-proxy_test.go
+++ b/pkg/virt-handler/migration-proxy/migration-proxy_test.go
@@ -39,12 +39,18 @@ import (
 var _ = Describe("MigrationProxy", func() {
        var tlsConfig *tls.Config
        var tmpDir string
+       var launcherRoot string
 
        BeforeEach(func() {
                var err error
                tmpDir, err = os.MkdirTemp("", "migrationproxytest")
                Expect(err).ToNot(HaveOccurred())
                os.MkdirAll(tmpDir, 0755)
+               // virt-handler reaches the target sockets inside the 
virt-launcher
+               // filesystem through /proc/<pid>/root. Mirror that layout so 
the
+               // proxy resolves them exactly as it does in production.
+               launcherRoot = filepath.Join(tmpDir, "root")
+               Expect(os.MkdirAll(launcherRoot, 0755)).To(Succeed())
                store, err := certificates.GenerateSelfSignedCert(tmpDir, 
"test", "test")
 
                ephemeraldiskutils.MockDefaultOwnershipManager()
@@ -107,7 +113,7 @@ var _ = Describe("MigrationProxy", func() {
 
                        It("by creating both ends and sending a message", 
func() {
                                sourceSock := filepath.Join(tmpDir, 
"source-sock")
-                               virtqemudSock := filepath.Join(tmpDir, 
"virtqemud-sock")
+                               virtqemudSock := filepath.Join(launcherRoot, 
"virtqemud-sock")
                                virtqemudListener, err := net.Listen("unix", 
virtqemudSock)
 
                                Expect(err).ShouldNot(HaveOccurred())
@@ -151,10 +157,10 @@ var _ = Describe("MigrationProxy", func() {
 
                        DescribeTable("by creating both ends with a manager and 
sending a message", func(migrationConfig *v1.MigrationConfiguration) {
                                directMigrationPort := "49152"
-                               virtqemudSock := filepath.Join(tmpDir, 
"virtqemud-sock")
+                               virtqemudSock := filepath.Join(launcherRoot, 
"virtqemud-sock")
                                virtqemudListener, err := net.Listen("unix", 
virtqemudSock)
                                Expect(err).ShouldNot(HaveOccurred())
-                               directSock := filepath.Join(tmpDir, 
"mykey-"+directMigrationPort)
+                               directSock := filepath.Join(launcherRoot, 
"mykey-"+directMigrationPort)
                                directListener, err := net.Listen("unix", 
directSock)
 
                                Expect(err).ShouldNot(HaveOccurred())
@@ -218,12 +224,12 @@ var _ = Describe("MigrationProxy", func() {
                                key2 := "key2"
 
                                directMigrationPort := "49152"
-                               virtqemudSock := filepath.Join(tmpDir, 
"virtqemud-sock")
+                               virtqemudSock := filepath.Join(launcherRoot, 
"virtqemud-sock")
                                virtqemudListener, err := net.Listen("unix", 
virtqemudSock)
                                Expect(err).ShouldNot(HaveOccurred())
                                defer virtqemudListener.Close()
 
-                               directSock := filepath.Join(tmpDir, 
key1+"-"+directMigrationPort)
+                               directSock := filepath.Join(launcherRoot, 
key1+"-"+directMigrationPort)
                                directListener, err := net.Listen("unix", 
directSock)
                                Expect(err).ShouldNot(HaveOccurred())
                                defer directListener.Close()

Reply via email to