CVE-2024-47744
Publication date:
21/10/2024
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
KVM: Use dedicated mutex to protect kvm_usage_count to avoid deadlock<br />
<br />
Use a dedicated mutex to guard kvm_usage_count to fix a potential deadlock<br />
on x86 due to a chain of locks and SRCU synchronizations. Translating the<br />
below lockdep splat, CPU1 #6 will wait on CPU0 #1, CPU0 #8 will wait on<br />
CPU2 #3, and CPU2 #7 will wait on CPU1 #4 (if there&#39;s a writer, due to the<br />
fairness of r/w semaphores).<br />
<br />
CPU0 CPU1 CPU2<br />
1 lock(&kvm->slots_lock);<br />
2 lock(&vcpu->mutex);<br />
3 lock(&kvm->srcu);<br />
4 lock(cpu_hotplug_lock);<br />
5 lock(kvm_lock);<br />
6 lock(&kvm->slots_lock);<br />
7 lock(cpu_hotplug_lock);<br />
8 sync(&kvm->srcu);<br />
<br />
Note, there are likely more potential deadlocks in KVM x86, e.g. the same<br />
pattern of taking cpu_hotplug_lock outside of kvm_lock likely exists with<br />
__kvmclock_cpufreq_notifier():<br />
<br />
cpuhp_cpufreq_online()<br />
|<br />
-> cpufreq_online()<br />
|<br />
-> cpufreq_gov_performance_limits()<br />
|<br />
-> __cpufreq_driver_target()<br />
|<br />
-> __target_index()<br />
|<br />
-> cpufreq_freq_transition_begin()<br />
|<br />
-> cpufreq_notify_transition()<br />
|<br />
-> ... __kvmclock_cpufreq_notifier()<br />
<br />
But, actually triggering such deadlocks is beyond rare due to the<br />
combination of dependencies and timings involved. E.g. the cpufreq<br />
notifier is only used on older CPUs without a constant TSC, mucking with<br />
the NX hugepage mitigation while VMs are running is very uncommon, and<br />
doing so while also onlining/offlining a CPU (necessary to generate<br />
contention on cpu_hotplug_lock) would be even more unusual.<br />
<br />
The most robust solution to the general cpu_hotplug_lock issue is likely<br />
to switch vm_list to be an RCU-protected list, e.g. so that x86&#39;s cpufreq<br />
notifier doesn&#39;t to take kvm_lock. For now, settle for fixing the most<br />
blatant deadlock, as switching to an RCU-protected list is a much more<br />
involved change, but add a comment in locking.rst to call out that care<br />
needs to be taken when walking holding kvm_lock and walking vm_list.<br />
<br />
======================================================<br />
WARNING: possible circular locking dependency detected<br />
6.10.0-smp--c257535a0c9d-pip #330 Tainted: G S O<br />
------------------------------------------------------<br />
tee/35048 is trying to acquire lock:<br />
ff6a80eced71e0a8 (&kvm->slots_lock){+.+.}-{3:3}, at: set_nx_huge_pages+0x179/0x1e0 [kvm]<br />
<br />
but task is already holding lock:<br />
ffffffffc07abb08 (kvm_lock){+.+.}-{3:3}, at: set_nx_huge_pages+0x14a/0x1e0 [kvm]<br />
<br />
which lock already depends on the new lock.<br />
<br />
the existing dependency chain (in reverse order) is:<br />
<br />
-> #3 (kvm_lock){+.+.}-{3:3}:<br />
__mutex_lock+0x6a/0xb40<br />
mutex_lock_nested+0x1f/0x30<br />
kvm_dev_ioctl+0x4fb/0xe50 [kvm]<br />
__se_sys_ioctl+0x7b/0xd0<br />
__x64_sys_ioctl+0x21/0x30<br />
x64_sys_call+0x15d0/0x2e60<br />
do_syscall_64+0x83/0x160<br />
entry_SYSCALL_64_after_hwframe+0x76/0x7e<br />
<br />
-> #2 (cpu_hotplug_lock){++++}-{0:0}:<br />
cpus_read_lock+0x2e/0xb0<br />
static_key_slow_inc+0x16/0x30<br />
kvm_lapic_set_base+0x6a/0x1c0 [kvm]<br />
kvm_set_apic_base+0x8f/0xe0 [kvm]<br />
kvm_set_msr_common+0x9ae/0xf80 [kvm]<br />
vmx_set_msr+0xa54/0xbe0 [kvm_intel]<br />
__kvm_set_msr+0xb6/0x1a0 [kvm]<br />
kvm_arch_vcpu_ioctl+0xeca/0x10c0 [kvm]<br />
kvm_vcpu_ioctl+0x485/0x5b0 [kvm]<br />
__se_sys_ioctl+0x7b/0xd0<br />
__x64_sys_ioctl+0x21/0x30<br />
x64_sys_call+0x15d0/0x2e60<br />
do_syscall_64+0x83/0x160<br />
entry_SYSCALL_64_after_hwframe+0x76/0x7e<br />
<br />
-> #1 (&kvm->srcu){.+.+}-{0:0}:<br />
__synchronize_srcu+0x44/0x1a0<br />
<br />
---truncated---
Severity CVSS v4.0: Pending analysis
Last modification:
22/10/2024