GHSA-9m94-w2vq-hcf9: KubeVirt VMI Denial-of-Service (DoS) Using Pod Impersonation
Summary_Short summary of the problem. Make the impact and severity as clear as possible.A logic flaw in the `virt-controller` allows an attacker to disrupt the control over a running VMI by creating a pod with the same labels as the legitimate `virt-launcher` pod associated with the VMI. This can mislead the `virt-controller` into associating the fake pod with the VMI, resulting in incorrect status updates and potentially causing a DoS (Denial-of-Service).Details_Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer._A vulnerability has been identified in the logic responsible for reconciling the state of VMI. Specifically, it is possible to associate a malicious attacker-controlled pod with an existing VMI running within the same namespace as the pod, thereby replacing the legitimate `virt-launcher` pod associated with the VMI.The `virt-launcher` pod is critical for enforcing the isolation mechanisms applied to the QEMU process that runs the virtual machine. It also serves, along with `virt-handler`, as a management interface that allows cluster users, operators, or administrators to control the lifecycle of the VMI (e.g., starting, stopping, or migrating it).When `virt-controller` receives a notification about a change in a VMI's state, it attempts to identify the corresponding `virt-launcher` pod. This is necessary in several scenarios, including:When hardware devices are requested to be hotplugged into the VMI—they must also be hotplugged into the associated `virt-launcher` pod.When additional RAM is requested—this may require updating the `virt-launcher` pod's cgroups.When additional CPU resources are added—this may also necessitate modifying the `virt-launcher` pod's cgroups.When the VMI is scheduled to migrate to another node.The core issue lies in the implementation of the `GetControllerOf` function, which is responsible for determining the controller (i.e., owning resource) of a given pod. In its current form, this logic can be manipulated, allowing an attacker to substitute a rogue pod in place of the legitimate `virt-launcher`, thereby compromising the VMI's integrity and control mechanisms.The current logic assumes that a `virt-launcher` pod associated with a VMI may not always have a `controllerRef`. In such cases, the controller falls back to inspecting the pod's labels. Specifically it evaluates the `kubevirt.io/created-by` label, which is expected to match the UID of the VMI triggering the reconciliation loop. If multiple pods are found that could be associated with the same VMI, the `virt-controller` selects the most recently created one.This logic appears to be designed with migration scenarios in mind, where it is expected that two `virt-launcher` pods might temporarily coexist for the same VMI: one for the migration source and one for the migration target node. However, a scenario was not identified in which a legitimate `virt-launcher` pod lacks a `controllerRef` and relies solely on labels (such as `kubevirt.io/created-by`) to indicate its association with a VMI.This fallback behaviour introduces a security risk. If an attacker is able to obtain the UID of a running VMI and create a pod within the same namespace, they can assign it labels that mimic those of a legitimate `virt-launcher` pod. As a result, the `CurrentVMIPod` function could mistakenly return the attacker-controlled pod instead of the authentic one.This vulnerability has at least two serious consequences:The attacker could disrupt or seize control over the VMI's lifecycle operations.The attacker could potentially influence the VMI's migration target node, bypassing node-level security constraints such as `nodeSelector` or `nodeAffinity`, which are typically used to enforce workload placement policies.PoC_Complete instructions, including specific configuration details, to reproduce the vulnerability._Consider the following VMI definition:The UID of the VMI can also be found as an argument to the container in the `virt-launcher` pod:Consider the following attacker-controlled pod which is associated to the VMI using the UID defined in the `kubevirt.io/created-by` label:To effectively attach the fake pod to the VMI, the attacker should wait for a state update to trigger the reconciliation loop:To illustrate the impact of this vulnerability, a race condition will be triggered in the `sync` function of the VMI controller:The above code adds additional annotations to the `virt-launcher` pod related to node eviction. This happens via an API call to Kubernetes which upon success returns a new updated pod object. This object replaces the current one in the execution flow.
There is a tiny window where an attacker could trigger a race condition which will mark the VMI as failed:To trigger it, the attacker should update the `fake-launcher` pod's annotations before the check `vmiPodExists := controller.PodExists(pod) && !isTempPod(pod)` in `sync`, and between the check `if !isTempPod(pod) && controller.IsPodReady(pod)` in `sync` but before the patch API call in `syncPodAnnotations` as follows:The above annotation will mark the attacker pod as ephemeral (i.e., used to provision the VMI) and will fail the VMI as the latter is already running (provisioning happens before the VMI starts running).The update should also happen during the reconciliation loop when the `fake-launcher` pod is initially going to be associated with the VMI and its labels, related to eviction, updated.Upon successful exploitation the VMI is marked as failed and could not be controlled via the Kubernetes API. However, the QEMU process is still running and the VMI is still present in the cluster:ImpactAs a result, an attacker could provoke a DoS condition for the affected VMI, compromising the availability of the services it provides.
CVSS v3.1: 5.3