[PATCH v1 1/2] KVM: x86: Reject reserved CR8 bits in KVM_SET_SREGS

From: Tharit Tangkijwanichakul

Date: Tue Sep 08 2026 - 13:11:59 EST


kvm_is_valid_sregs() validates the incoming CR0, CR4, and efer values but
never checks CR8.

When userspace passes a CR8 value with any of the
reserved bits [63:4] set, __set_sregs_common() forwards it to
kvm_set_cr8(), which rejects the reserved bits and returns early. That
return value is not checked, so the ioctl reports success while the
requested value is silently dropped. A subsequent KVM_GET_SREGS then
returns a CR8 different from the one userspace believed it had written.

Factor the reserved-bit check out into kvm_is_valid_cr8() and use it both
in kvm_set_cr8() and in kvm_is_valid_sregs().

Fixes: 2f5bb3fe5835 ("KVM: x86: Move the bulk of register specific code from x86.c to regs.c")
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@xxxxxxxxx>
---
arch/x86/kvm/regs.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/regs.c b/arch/x86/kvm/regs.c
index 8f66438989e4..fad31b59c622 100644
--- a/arch/x86/kvm/regs.c
+++ b/arch/x86/kvm/regs.c
@@ -440,9 +440,14 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_set_cr4);

+static bool kvm_is_valid_cr8(unsigned long cr8)
+{
+ return !(cr8 & CR8_RESERVED_BITS);
+}
+
int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8)
{
- if (cr8 & CR8_RESERVED_BITS)
+ if (!kvm_is_valid_cr8(cr8))
return 1;
if (lapic_in_kernel(vcpu))
kvm_lapic_set_tpr(vcpu, cr8);
@@ -565,6 +570,7 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)

return kvm_is_valid_cr4(vcpu, sregs->cr4) &&
kvm_is_valid_cr0(vcpu, sregs->cr0) &&
+ kvm_is_valid_cr8(sregs->cr8) &&
kvm_valid_efer(vcpu, sregs->efer);
}

--
2.53.0