CVE-2025-21977
Publication date:
01/04/2025
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
fbdev: hyperv_fb: Fix hang in kdump kernel when on Hyper-V Gen 2 VMs<br />
<br />
Gen 2 Hyper-V VMs boot via EFI and have a standard EFI framebuffer<br />
device. When the kdump kernel runs in such a VM, loading the efifb<br />
driver may hang because of accessing the framebuffer at the wrong<br />
memory address.<br />
<br />
The scenario occurs when the hyperv_fb driver in the original kernel<br />
moves the framebuffer to a different MMIO address because of conflicts<br />
with an already-running efifb or simplefb driver. The hyperv_fb driver<br />
then informs Hyper-V of the change, which is allowed by the Hyper-V FB<br />
VMBus device protocol. However, when the kexec command loads the kdump<br />
kernel into crash memory via the kexec_file_load() system call, the<br />
system call doesn&#39;t know the framebuffer has moved, and it sets up the<br />
kdump screen_info using the original framebuffer address. The transition<br />
to the kdump kernel does not go through the Hyper-V host, so Hyper-V<br />
does not reset the framebuffer address like it would do on a reboot.<br />
When efifb tries to run, it accesses a non-existent framebuffer<br />
address, which traps to the Hyper-V host. After many such accesses,<br />
the Hyper-V host thinks the guest is being malicious, and throttles<br />
the guest to the point that it runs very slowly or appears to have hung.<br />
<br />
When the kdump kernel is loaded into crash memory via the kexec_load()<br />
system call, the problem does not occur. In this case, the kexec command<br />
builds the screen_info table itself in user space from data returned<br />
by the FBIOGET_FSCREENINFO ioctl against /dev/fb0, which gives it the<br />
new framebuffer location.<br />
<br />
This problem was originally reported in 2020 [1], resulting in commit<br />
3cb73bc3fa2a ("hyperv_fb: Update screen_info after removing old<br />
framebuffer"). This commit solved the problem by setting orig_video_isVGA<br />
to 0, so the kdump kernel was unaware of the EFI framebuffer. The efifb<br />
driver did not try to load, and no hang occurred. But in 2024, commit<br />
c25a19afb81c ("fbdev/hyperv_fb: Do not clear global screen_info")<br />
effectively reverted 3cb73bc3fa2a. Commit c25a19afb81c has no reference<br />
to 3cb73bc3fa2a, so perhaps it was done without knowing the implications<br />
that were reported with 3cb73bc3fa2a. In any case, as of commit<br />
c25a19afb81c, the original problem came back again.<br />
<br />
Interestingly, the hyperv_drm driver does not have this problem because<br />
it never moves the framebuffer. The difference is that the hyperv_drm<br />
driver removes any conflicting framebuffers *before* allocating an MMIO<br />
address, while the hyperv_fb drivers removes conflicting framebuffers<br />
*after* allocating an MMIO address. With the "after" ordering, hyperv_fb<br />
may encounter a conflict and move the framebuffer to a different MMIO<br />
address. But the conflict is essentially bogus because it is removed<br />
a few lines of code later.<br />
<br />
Rather than fix the problem with the approach from 2020 in commit<br />
3cb73bc3fa2a, instead slightly reorder the steps in hyperv_fb so<br />
conflicting framebuffers are removed before allocating an MMIO address.<br />
Then the default framebuffer MMIO address should always be available, and<br />
there&#39;s never any confusion about which framebuffer address the kdump<br />
kernel should use -- it&#39;s always the original address provided by<br />
the Hyper-V host. This approach is already used by the hyperv_drm<br />
driver, and is consistent with the usage guidelines at the head of<br />
the module with the function aperture_remove_conflicting_devices().<br />
<br />
This approach also solves a related minor problem when kexec_load()<br />
is used to load the kdump kernel. With current code, unbinding and<br />
rebinding the hyperv_fb driver could result in the framebuffer moving<br />
back to the default framebuffer address, because on the rebind there<br />
are no conflicts. If such a move is done after the kdump kernel is<br />
loaded with the new framebuffer address, at kdump time it could again<br />
have the wrong address.<br />
<br />
This problem and fix are described in terms of the kdump kernel, but<br />
it can also occur<br />
---truncated---
Severity CVSS v4.0: Pending analysis
Last modification:
01/04/2025