VYPR
High severityNVD Advisory· Published Nov 18, 2025· Updated Feb 26, 2026

KubeVirt Vulnerable to Arbitrary Host File Read and Write

CVE-2025-64324

Description

KubeVirt is a virtual machine management add-on for Kubernetes. The hostDisk feature in KubeVirt allows mounting a host file or directory owned by the user with UID 107 into a VM. However, prior to version 1.6.1 and 1.7.0, the implementation of this feature and more specifically the DiskOrCreate option (which creates a file if it doesn't exist) has a logic bug that allows an attacker to read and write arbitrary files owned by more privileged users on the host system. Versions 1.6.1 and 1.7.0 fix the issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
kubevirt.io/kubevirtGo
< 1.6.11.6.1
kubevirt.io/kubevirtGo
>= 1.7.0-alpha.0, < 1.7.0-rc.01.7.0-rc.0

Affected products

1

Patches

2
00d03e43e3bf

Merge pull request #15076 from kubevirt-bot/cherry-pick-15037-to-release-1.6

https://github.com/kubevirt/kubevirtkubevirt-botSep 18, 2025via ghsa
4 files changed · +50 19
  • pkg/ephemeral-disk-utils/utils.go+17 2 modified
    @@ -44,14 +44,29 @@ func MockDefaultOwnershipManager() {
     type nonOpManager struct {
     }
     
    -func (no *nonOpManager) UnsafeSetFileOwnership(file string) error {
    +func (no *nonOpManager) UnsafeSetFileOwnership(_ string) error {
     	return nil
     }
     
    -func (no *nonOpManager) SetFileOwnership(file *safepath.Path) error {
    +func (no *nonOpManager) SetFileOwnership(_ *safepath.Path) error {
     	return nil
     }
     
    +func MockDefaultOwnershipManagerWithFailure() {
    +	DefaultOwnershipManager = &failureManager{}
    +}
    +
    +type failureManager struct {
    +}
    +
    +func (no *failureManager) UnsafeSetFileOwnership(_ string) error {
    +	panic("unexpected call to UnsafeSetFileOwnership")
    +}
    +
    +func (no *failureManager) SetFileOwnership(_ *safepath.Path) error {
    +	panic("unexpected call to SetFileOwnership")
    +}
    +
     type OwnershipManager struct {
     	user string
     }
    
  • pkg/host-disk/host-disk.go+7 7 modified
    @@ -235,7 +235,7 @@ func (hdc *DiskImgCreator) setlessPVCSpaceToleration(toleration int) {
     	hdc.lessPVCSpaceToleration = toleration
     }
     
    -func (hdc DiskImgCreator) Create(vmi *v1.VirtualMachineInstance) error {
    +func (hdc *DiskImgCreator) Create(vmi *v1.VirtualMachineInstance) error {
     	for _, volume := range vmi.Spec.Volumes {
     		if hostDisk := volume.VolumeSource.HostDisk; shouldMountHostDisk(hostDisk) {
     			if err := hdc.mountHostDiskAndSetOwnership(vmi, volume.Name, hostDisk); err != nil {
    @@ -263,19 +263,19 @@ func (hdc *DiskImgCreator) mountHostDiskAndSetOwnership(vmi *v1.VirtualMachineIn
     	}
     
     	if fileNotExists {
    -		if err := hdc.handleRequestedSizeAndCreateSparseRaw(vmi, diskDir, filepath.Base(hostDisk.Path), hostDisk); err != nil {
    +		if err = hdc.handleRequestedSizeAndCreateSparseRaw(vmi, diskDir, filepath.Base(hostDisk.Path), hostDisk); err != nil {
     			return err
     		}
     
     		diskPath, err = safepath.JoinNoFollow(diskDir, filepath.Base(hostDisk.Path))
     		if err != nil {
     			return err
     		}
    -	}
    -	// Change file ownership to the qemu user.
    -	if err := ephemeraldiskutils.DefaultOwnershipManager.SetFileOwnership(diskPath); err != nil {
    -		log.Log.Reason(err).Errorf("Couldn't set Ownership on %s: %v", diskPath, err)
    -		return err
    +		// Change file ownership to the qemu user.
    +		if err = ephemeraldiskutils.DefaultOwnershipManager.SetFileOwnership(diskPath); err != nil {
    +			log.Log.Reason(err).Errorf("Couldn't set Ownership on %s: %v", diskPath, err)
    +			return err
    +		}
     	}
     	return nil
     }
    
  • pkg/host-disk/host-disk_test.go+11 6 modified
    @@ -34,15 +34,13 @@ import (
     	"k8s.io/apimachinery/pkg/api/resource"
     	"k8s.io/client-go/kubernetes/fake"
     	"k8s.io/client-go/tools/record"
    -
    -	"kubevirt.io/kubevirt/pkg/libvmi"
    -	"kubevirt.io/kubevirt/pkg/safepath"
    -
     	v1 "kubevirt.io/api/core/v1"
     	"kubevirt.io/client-go/kubecli"
     
    +	ephemeraldiskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
    +	"kubevirt.io/kubevirt/pkg/libvmi"
     	libvmistatus "kubevirt.io/kubevirt/pkg/libvmi/status"
    -
    +	"kubevirt.io/kubevirt/pkg/safepath"
     	"kubevirt.io/kubevirt/pkg/testutils"
     )
     
    @@ -300,7 +298,14 @@ var _ = Describe("HostDisk", func() {
     			})
     		})
     		Context("With existing disk.img", func() {
    -			It("Should not re-create disk.img", func() {
    +			AfterEach(func() {
    +				By("Switching back to the regular mock ownership manager")
    +				ephemeraldiskutils.MockDefaultOwnershipManager()
    +			})
    +
    +			It("Should not re-create or chown disk.img", func() {
    +				By("Switching to an ownership manager that panics when called")
    +				ephemeraldiskutils.MockDefaultOwnershipManagerWithFailure()
     				By("Creating a disk.img before adding a HostDisk volume")
     				tmpDiskImg := createTempDiskImg("volume1")
     				By("Creating a new VMI with a HostDisk volumes")
    
  • tests/storage/storage.go+15 4 modified
    @@ -253,14 +253,25 @@ var _ = Describe(SIG("Storage", func() {
     					// Start the VirtualMachineInstance with the PVC attached
     					vmi = newVMI(pvcName)
     
    -					vmi = libvmops.RunVMIAndExpectLaunch(vmi, 180)
    +					if imageOwnedByQEMU {
    +						vmi = libvmops.RunVMIAndExpectLaunch(vmi, 180)
     
    -					By(checkingVMInstanceConsoleOut)
    -					Expect(console.LoginToAlpine(vmi)).To(Succeed())
    +						By(checkingVMInstanceConsoleOut)
    +						Expect(console.LoginToAlpine(vmi)).To(Succeed())
    +					} else {
    +						By("Starting a VirtualMachineInstance")
    +						createdVMI := libvmops.RunVMIAndExpectScheduling(vmi, 60)
    +
    +						By(fmt.Sprintf("Checking that VirtualMachineInstance start failed: starting at %v", time.Now()))
    +						ctx, cancel := context.WithCancel(context.Background())
    +						defer cancel()
    +						event := watcher.New(createdVMI).Timeout(60*time.Second).SinceWatchedObjectResourceVersion().WaitFor(ctx, watcher.WarningEvent, "SyncFailed")
    +						Expect(event.Message).To(ContainSubstring("Could not open '/var/run/kubevirt-private/vmi-disks/disk0/disk.img': Permission denied"), "VMI should not be started")
    +					}
     				},
     					Entry("[test_id:3130]with Disk PVC", newRandomVMIWithPVC, true),
     					Entry("[test_id:3131]with CDRom PVC", newRandomVMIWithCDRom, true),
    -					Entry("hostpath disk image file not owned by qemu", newRandomVMIWithPVC, false),
    +					Entry("unless hostpath disk image file not owned by qemu", newRandomVMIWithPVC, false),
     				)
     			})
     
    
ff3b69b08b6b

Merge pull request #15037 from jean-edouard/hostpathchown

https://github.com/kubevirt/kubevirtkubevirt-botJul 3, 2025via ghsa
4 files changed · +50 19
  • pkg/ephemeral-disk-utils/utils.go+17 2 modified
    @@ -44,14 +44,29 @@ func MockDefaultOwnershipManager() {
     type nonOpManager struct {
     }
     
    -func (no *nonOpManager) UnsafeSetFileOwnership(file string) error {
    +func (no *nonOpManager) UnsafeSetFileOwnership(_ string) error {
     	return nil
     }
     
    -func (no *nonOpManager) SetFileOwnership(file *safepath.Path) error {
    +func (no *nonOpManager) SetFileOwnership(_ *safepath.Path) error {
     	return nil
     }
     
    +func MockDefaultOwnershipManagerWithFailure() {
    +	DefaultOwnershipManager = &failureManager{}
    +}
    +
    +type failureManager struct {
    +}
    +
    +func (no *failureManager) UnsafeSetFileOwnership(_ string) error {
    +	panic("unexpected call to UnsafeSetFileOwnership")
    +}
    +
    +func (no *failureManager) SetFileOwnership(_ *safepath.Path) error {
    +	panic("unexpected call to SetFileOwnership")
    +}
    +
     type OwnershipManager struct {
     	user string
     }
    
  • pkg/host-disk/host-disk.go+7 7 modified
    @@ -226,7 +226,7 @@ func (hdc *DiskImgCreator) setlessPVCSpaceToleration(toleration int) {
     	hdc.lessPVCSpaceToleration = toleration
     }
     
    -func (hdc DiskImgCreator) Create(vmi *v1.VirtualMachineInstance) error {
    +func (hdc *DiskImgCreator) Create(vmi *v1.VirtualMachineInstance) error {
     	for _, volume := range vmi.Spec.Volumes {
     		if hostDisk := volume.VolumeSource.HostDisk; shouldMountHostDisk(hostDisk) {
     			if err := hdc.mountHostDiskAndSetOwnership(vmi, volume.Name, hostDisk); err != nil {
    @@ -249,14 +249,14 @@ func (hdc *DiskImgCreator) mountHostDiskAndSetOwnership(vmi *v1.VirtualMachineIn
     		return err
     	}
     	if !fileExists {
    -		if err := hdc.handleRequestedSizeAndCreateSparseRaw(vmi, diskDir, diskPath, hostDisk); err != nil {
    +		if err = hdc.handleRequestedSizeAndCreateSparseRaw(vmi, diskDir, diskPath, hostDisk); err != nil {
    +			return err
    +		}
    +		// Change file ownership to the qemu user.
    +		if err = ephemeraldiskutils.DefaultOwnershipManager.UnsafeSetFileOwnership(diskPath); err != nil {
    +			log.Log.Reason(err).Errorf("Couldn't set Ownership on %s: %v", diskPath, err)
     			return err
     		}
    -	}
    -	// Change file ownership to the qemu user.
    -	if err := ephemeraldiskutils.DefaultOwnershipManager.UnsafeSetFileOwnership(diskPath); err != nil {
    -		log.Log.Reason(err).Errorf("Couldn't set Ownership on %s: %v", diskPath, err)
    -		return err
     	}
     	return nil
     }
    
  • pkg/host-disk/host-disk_test.go+11 6 modified
    @@ -33,15 +33,13 @@ import (
     	"k8s.io/apimachinery/pkg/api/resource"
     	"k8s.io/client-go/kubernetes/fake"
     	"k8s.io/client-go/tools/record"
    -
    -	"kubevirt.io/kubevirt/pkg/libvmi"
    -	"kubevirt.io/kubevirt/pkg/safepath"
    -
     	v1 "kubevirt.io/api/core/v1"
     	"kubevirt.io/client-go/kubecli"
     
    +	ephemeraldiskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
    +	"kubevirt.io/kubevirt/pkg/libvmi"
     	libvmistatus "kubevirt.io/kubevirt/pkg/libvmi/status"
    -
    +	"kubevirt.io/kubevirt/pkg/safepath"
     	"kubevirt.io/kubevirt/pkg/testutils"
     )
     
    @@ -289,7 +287,14 @@ var _ = Describe("HostDisk", func() {
     			})
     		})
     		Context("With existing disk.img", func() {
    -			It("Should not re-create disk.img", func() {
    +			AfterEach(func() {
    +				By("Switching back to the regular mock ownership manager")
    +				ephemeraldiskutils.MockDefaultOwnershipManager()
    +			})
    +
    +			It("Should not re-create or chown disk.img", func() {
    +				By("Switching to an ownership manager that panics when called")
    +				ephemeraldiskutils.MockDefaultOwnershipManagerWithFailure()
     				By("Creating a disk.img before adding a HostDisk volume")
     				tmpDiskImg := createTempDiskImg("volume1")
     				By("Creating a new VMI with a HostDisk volumes")
    
  • tests/storage/storage.go+15 4 modified
    @@ -253,14 +253,25 @@ var _ = Describe(SIG("Storage", func() {
     					// Start the VirtualMachineInstance with the PVC attached
     					vmi = newVMI(pvcName)
     
    -					vmi = libvmops.RunVMIAndExpectLaunch(vmi, 180)
    +					if imageOwnedByQEMU {
    +						vmi = libvmops.RunVMIAndExpectLaunch(vmi, 180)
     
    -					By(checkingVMInstanceConsoleOut)
    -					Expect(console.LoginToAlpine(vmi)).To(Succeed())
    +						By(checkingVMInstanceConsoleOut)
    +						Expect(console.LoginToAlpine(vmi)).To(Succeed())
    +					} else {
    +						By("Starting a VirtualMachineInstance")
    +						createdVMI := libvmops.RunVMIAndExpectScheduling(vmi, 60)
    +
    +						By(fmt.Sprintf("Checking that VirtualMachineInstance start failed: starting at %v", time.Now()))
    +						ctx, cancel := context.WithCancel(context.Background())
    +						defer cancel()
    +						event := watcher.New(createdVMI).Timeout(60*time.Second).SinceWatchedObjectResourceVersion().WaitFor(ctx, watcher.WarningEvent, "SyncFailed")
    +						Expect(event.Message).To(ContainSubstring("Could not open '/var/run/kubevirt-private/vmi-disks/disk0/disk.img': Permission denied"), "VMI should not be started")
    +					}
     				},
     					Entry("[test_id:3130]with Disk PVC", newRandomVMIWithPVC, true),
     					Entry("[test_id:3131]with CDRom PVC", newRandomVMIWithCDRom, true),
    -					Entry("hostpath disk image file not owned by qemu", newRandomVMIWithPVC, false),
    +					Entry("unless hostpath disk image file not owned by qemu", newRandomVMIWithPVC, false),
     				)
     			})
     
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.