Unguarded rdmsr() in print_svm_info()/print_vmx_info(): CPUID-advertised VMX/SVM without MSR backing β ring-0 #GP β boot-time kernel panic
Summary
print_svm does do_cpuid(0x8000000A) with no exthigh check + raw rdmsr(MSR_AMD_VM_CR); vmx printers raw-rdmsr FEATURE_CONTROL/VMX_BASIC/control MSRs - all gated solely on hypervisor-controllable CPUID bits, neither bootverbose-gated. Same class the file already guards with rdmsr_safe for ARCH_CAP (:683-696, comment documents the VirtualBox-class bugs). TCG +svm run proves the path executes; #GP itself not observable on stock QEMU 7.2 (TCG returns 0). rdmsr_safe + exthigh-guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5345 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.9 KB | β raw | |
| VERDICT.md | β | 2.6 KB | β raw | |
| boot-tcg-svm.log | β | 11.9 KB | view raw | |
| boot-kvm-svm-bitstripped.log | β | 11.9 KB | view raw | |
| run.sh | β | 187 B | view raw | |
| env.txt | β | 768 B | view raw | |
| fix.diff | β | 1.4 KB | view raw | |
| verdict.json | β | 3.9 KB | view raw |
DF-5345 β Unguarded rdmsr() in print_svm_info()/print_vmx_info(): CPUID-advertised VMX/SVM without MSR backing β #GP β boot panic
Where
sys/platform/pc64/x86_64/identcpu.c
1272: static void
1273: print_svm_info(void)
1274: {
1275: u_int features, regs[4];
1276: uint64_t msr;
1277:
1278: kprintf("\n SVM: ");
1279: do_cpuid(0x8000000A, regs); /* no cpu_exthigh >= 0x8000000a check */
1280: features = regs[3];
1281:
1282: msr = rdmsr(MSR_AMD_VM_CR); /* UNGUARDED raw rdmsr */
...
1339: print_vmx_info(void)
...
1345: msr = rdmsr(MSR_IA32_FEATURE_CONTROL); /* UNGUARDED */
...
1350: basic = rdmsr(MSR_VMX_BASIC); /* UNGUARDED */
1351: pin_ctls = vmx_settable(basic, MSR_VMX_PINBASED_CTLS, /* rdmsr again */
Both printers are gated only on CPUID feature bits
(:498 cpu_feature2 & CPUID2_VMX, :501 amd_feature2 & AMDID2_SVM) β bits
that in a VM are written by the hypervisor and on metal by firmware. A
hypervisor that advertises the bit without implementing the MSRs makes the
kernel execute rdmsr on a non-existent MSR in ring 0 β #GP β
boot-time kernel panic. Neither printer is bootverbose-gated
(only print_AMD_info/print_INTEL_info are, :564-569).
The file itself documents this exact failure class and guards one instance of it properly:
689: if (cpu_stdext_feature3 & CPUID_STDEXT3_ARCH_CAP) {
690: if (rdmsr_safe(MSR_IA32_ARCH_CAPABILITIES, &cpu_ia32_arch_caps))
...
683: * Some hypervisors fail to implement
684: * MSR_IA32_ARCH_CAPABILITIES, catch any problems.
print_svm_info/print_vmx_info/vmx_settable were never given the same treatment.
Reproduction attempts (QEMU 7.2.22)
- KVM,
-cpu qemu64,+svm,check=off(Intel host): QEMU clears host-unsupported feature bits during KVM CPU realize, so the SVM bit never reaches the guest (boot-kvm-svm-bitstripped.log:37AMD Features2=0x1<LAHF>) β the path is not reached this way. - TCG,
-cpu qemu64,+svm,check=off(boot-tcg-svm.log): the bit does reach the guest (AMD Features2=0x7<LAHF,CMP,SVM>, line 37) andprint_svm_info()runs and executes the rawrdmsr(MSR_AMD_VM_CR)(SVM: Features=0x0at line 39 β printed after the rdmsr at :1282). QEMU TCG returns 0 for unimplemented MSRs instead of injecting #GP, so the guest survives; the panic is therefore not observable on stock QEMU β it requires a hypervisor that faults unsupported MSR reads (KVM does; VirtualBox-class bugs are the documented motivation for the rdmsr_safe guard at :690).
Honest classification: not_reproduced on this harness (boot completed, no panic) with the dangerous path proven reached and the rdmsr proven executed under a lying CPUID configuration.
Files
boot-tcg-svm.logβ TCG boot: SVM bit exposed, print_svm_info executedboot-kvm-svm-bitstripped.logβ KVM control: bit stripped, path not reachedrun.shβ exact QEMU commandsenv.txt,fix.diff
DF-5345 β VERDICT
Status: not_reproduced (the panic itself is not observable on stock QEMU 7.2 β TCG returns 0 for unimplemented MSRs; QEMU-under-KVM strips host-unsupported CPUID bits before the guest sees them). The code defect is certain and the dangerous path was proven reached and executed on a lying-CPUID configuration.
What was proven
- TCG boot with
-cpu qemu64,+svm,check=offexposesAMD Features2=0x7<LAHF,CMP,SVM>to the guest (boot-tcg-svm.log:37). printcpuinfo()(machdep.c:342) β identcpu.c:501if (amd_feature2 & AMDID2_SVM) print_svm_info();βdo_cpuid(0x8000000A)(:1279, nocpu_exthighguard) βrdmsr(MSR_AMD_VM_CR)(:1282) executed in ring 0 on a CPU that does not implement it β evidenced bySVM: Features=0x0(:39 of the log, printed after the MSR read) and the boot completing tologin:withOrigin="TCGTCGTCGTCG"(VMM detected).- QEMU TCG emulates unknown-MSR reads as 0 rather than #GP, so no fault
occurred. On hypervisors that inject #GP for unsupported MSRs (KVM
semantics) the same CPUID lie panics the kernel during early boot
(
Fatal trap 13: general protection faultinprint_svm_info).
Why this is a real defect
- The file already contains the mitigated precedent: :683-696 comments
"Some hypervisors fail to implement MSR_IA32_ARCH_CAPABILITIES, catch any
problems" and uses
rdmsr_safe. print_svm_info (:1282) and print_vmx_info (:1345, :1350, and everyvmx_settable()call at :1329-1332) use rawrdmsrfor the same class of CPUID-gated MSR. - print_svm_info additionally reads CPUID leaf 0x8000000A without checking
cpu_exthigh >= 0x8000000A. - print_vmx_info is not bootverbose-gated β every boot on a VMX-advertising CPU executes three+ raw VMX MSR reads.
Threat model: malicious/buggy hypervisor or firmware (the "malicious firmware analog for VMs"). Impact ceiling: boot-time kernel panic (DoS of the machine at startup β unauthenticated, no userland needed once CPUID lies).
Fix validation
not_testable β the faulting hypervisor needed to demonstrate the panic
before/after the fix cannot be built from stock QEMU 7.2 (TCG never
injects #GP on unknown MSR reads; KVM strips the feature bit). The fix is
the same pattern already proven in-file at :690 (rdmsr_safe).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablenot_testable: demonstrating the panic before/after the fix requires a hypervisor that advertises VMX/SVM CPUID bits yet faults the MSR reads; stock QEMU 7.2 cannot (TCG returns 0 for unknown MSRs; KVM strips host-unsupported bits). The proposed fix is the identical, in-file-proven pattern (rdmsr_safe) used for MSR_IA32_ARCH_CAPABILITIES at identcpu.c:690.
n/a (no faulting hypervisor available); see boot-tcg-svm.log for path-reachability proof
Confirmed kernel references
Detail
Evidence (decisive lines)
boot-tcg-svm.log:37 (AMD Features2=0x7<LAHF,CMP,SVM> - CPUID lie delivered), :39 (SVM: Features=0x0 - print_svm_info ran past the rdmsr), :41 (login reached - TCG does not #GP unknown MSRs); boot-kvm-svm-bitstripped.log:37 (KVM control: bit stripped); VERDICT.md (full analysis); contrast identcpu.c:690 rdmsr_safe(MSR_IA32_ARCH_CAPABILITIES)
PoC changes
No seed; authored QEMU-based trigger. KVM variant failed to deliver the SVM bit (QEMU host-feature filtering); switched to TCG where the bit survives - that boot proves path-reachability but TCG's return-0 semantics for unknown MSRs preclude the #GP.
Verified recommended fix
Use rdmsr_safe() in print_svm_info/print_vmx_info/vmx_settable and skip/print nothing on failure; guard leaf 0x8000000A with cpu_exthigh >= 0x8000000A (see fix.diff)
Verdict
Code defect certain, panic not observable on stock QEMU 7.2. print_svm_info() executes a raw rdmsr(MSR_AMD_VM_CR) at identcpu.c:1282 (and print_vmx_info()/vmx_settable() read MSR_IA32_FEATURE_CONTROL / MSR_VMX_BASIC / VMX control MSRs raw at :1345,:1350,:1329-1332) gated only on CPUID feature bits the hypervisor controls (:498,:501), with no cpu_exthigh check for leaf 0x8000000A (:1279). Proven on-guest that the path is reached and the unguarded rdmsr executes under a lying CPUID config: TCG boot with -cpu qemu64,+svm,check=off delivered 'AMD Features2=0x7
No comments yet.