Restrict PV features to only enabled guests
Subsystems (4)
cover Restrict PV features to only enabled guests
To date, KVM has allowed guests to use paravirtual interfaces regardless of the configured CPUID. While almost any guest will consult the KVM_CPUID_FEATURES leaf _before_ using PV features, it is still undesirable to have such interfaces silently present.
This series aims to address the issue by adding explicit checks against the guest's CPUID when servicing any paravirtual feature. Since this effectively changes the guest/hypervisor ABI, a KVM_CAP is warranted to guard the new behavior.
Patches 1-2 refactor some of the PV code in anticipation of the change. Patch 3 introduces the checks + KVM_CAP. Finally, patch 4 fixes some doc typos that were noticed when working on this series.
Parent commit: f3633c268354 ("Merge tag 'kvm-s390-next-5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into kvm-next-5.6")
Oliver Upton (4):
kvm: x86: encapsulate wrmsr(MSR_KVM_SYSTEM_TIME) emulation in helper
fn
kvm: x86: set wall_clock in kvm_write_wall_clock()
kvm: x86: only provide PV features if enabled in guest's CPUID
Documentation: kvm: fix some typos in cpuid.rst
Documentation/virt/kvm/api.rst | 11 +++ Documentation/virt/kvm/cpuid.rst | 88 +++++++++++----------- arch/x86/include/asm/kvm_host.h | 6 ++ arch/x86/kvm/cpuid.h | 16 ++++ arch/x86/kvm/x86.c | 122 +++++++++++++++++++++++-------- include/uapi/linux/kvm.h | 1 + 6 files changed, 171 insertions(+), 73 deletions(-)
Signature · 1 line
2.28.0.236.gb10cc79966-goog
PATCH 1/4 kvm: x86: encapsulate wrmsr(MSR_KVM_SYSTEM_TIME) emulation in helper fn
No functional change intended.
--- arch/x86/kvm/x86.c | 58 +++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 26 deletions(-)
arch/x86/kvm/x86.c +32 -26
@@ -1822,6 +1822,34 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)kvm_write_guest (kvm, wall_clock, &version,sizeof (version)); } +void kvm_write_system_time (struct kvm_vcpu *vcpu,gpa_t system_time, +bool old_msr,bool host_initiated) +{ +struct kvm_arch *ka = &vcpu->kvm->arch; + +if (vcpu->vcpu_id ==0 && !host_initiated) { +if (ka->boot_vcpu_runs_old_kvmclock && old_msr) +kvm_make_request (KVM_REQ_MASTERCLOCK_UPDATE , vcpu); + + ka->boot_vcpu_runs_old_kvmclock = old_msr; + } + + vcpu->arch.time = system_time; +kvm_make_request (KVM_REQ_GLOBAL_CLOCK_UPDATE , vcpu); + +/* we verify if the enable bit is set... */ + vcpu->arch.pv_time_enabled = false; +if (!(system_time &1 )) +return ; + +if (!kvm_gfn_to_hva_cache_init (vcpu->kvm, + &vcpu->arch.pv_time, system_time & ~1ULL , +sizeof (struct pvclock_vcpu_time_info ))) + vcpu->arch.pv_time_enabled = true; + +return ; +} +static uint32_t div_frac (uint32_t dividend,uint32_t divisor) {do_shl32_div32 (dividend, divisor);
@@ -2973,33 +3001,11 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)kvm_write_wall_clock (vcpu->kvm, data);break ;case MSR_KVM_SYSTEM_TIME_NEW : -case MSR_KVM_SYSTEM_TIME : { -struct kvm_arch *ka = &vcpu->kvm->arch; - -if (vcpu->vcpu_id ==0 && !msr_info->host_initiated) { -bool tmp = (msr ==MSR_KVM_SYSTEM_TIME ); - -if (ka->boot_vcpu_runs_old_kvmclock != tmp) -kvm_make_request (KVM_REQ_MASTERCLOCK_UPDATE , vcpu); - - ka->boot_vcpu_runs_old_kvmclock = tmp; - } - - vcpu->arch.time = data; -kvm_make_request (KVM_REQ_GLOBAL_CLOCK_UPDATE , vcpu); - -/* we verify if the enable bit is set... */ - vcpu->arch.pv_time_enabled = false; -if (!(data &1 )) -break ; - -if (!kvm_gfn_to_hva_cache_init (vcpu->kvm, - &vcpu->arch.pv_time, data & ~1ULL , -sizeof (struct pvclock_vcpu_time_info ))) - vcpu->arch.pv_time_enabled = true; - +kvm_write_system_time (vcpu, data, false, msr_info->host_initiated); +break ; +case MSR_KVM_SYSTEM_TIME : +kvm_write_system_time (vcpu, data, true, msr_info->host_initiated);break ; - }case MSR_KVM_ASYNC_PF_EN :if (kvm_pv_enable_async_pf (vcpu, data))return 1 ;
Signature · 1 line
2.28.0.236.gb10cc79966-goog
PATCH 2/4 kvm: x86: set wall_clock in kvm_write_wall_clock()
In reply to Oliver UptonSmall change to avoid meaningless duplication in the subsequent patch. No functional change intended.
--- arch/x86/kvm/x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/kvm/x86.c +2 -1
@@ -1790,6 +1790,8 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)struct pvclock_wall_clock wc;u64 wall_nsec; + kvm->arch.wall_clock = wall_clock; +if (!wall_clock)return ;
@@ -2997,7 +2999,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)break ;case MSR_KVM_WALL_CLOCK_NEW :case MSR_KVM_WALL_CLOCK : - vcpu->kvm->arch.wall_clock = data;kvm_write_wall_clock (vcpu->kvm, data);break ;case MSR_KVM_SYSTEM_TIME_NEW :
Signature · 1 line
2.28.0.236.gb10cc79966-goog
PATCH 3/4 kvm: x86: only provide PV features if enabled in guest's CPUID
In reply to Oliver UptonKVM unconditionally provides PV features to the guest, regardless of the configured CPUID. An unwitting guest that doesn't check KVM_CPUID_FEATURES before use could access paravirt features that userspace did not intend to provide. Fix this by checking the guest's CPUID before performing any paravirtual operations.
Introduce a capability, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, to gate the aforementioned enforcement. Migrating a VM from a host w/o this patch to a host with this patch could silently change the ABI exposed to the guest, warranting that we default to the old behavior and opt-in for the new one.
--- Documentation/virt/kvm/api.rst | 11 ++++++ arch/x86/include/asm/kvm_host.h | 6 +++ arch/x86/kvm/cpuid.h | 16 ++++++++ arch/x86/kvm/x86.c | 67 ++++++++++++++++++++++++++++++--- include/uapi/linux/kvm.h | 1 + 5 files changed, 96 insertions(+), 5 deletions(-)
Documentation/virt/kvm/api.rst +11 -0
@@ -6155,3 +6155,14 @@ KVM can therefore start protected VMs. This capability governs the KVM_S390_PV_COMMAND ioctl and the KVM_MP_STATE_LOAD MP_STATE. KVM_SET_MP_STATE can fail for protected guests when the state change is invalid. + + +8.24 KVM_CAP_ENFORCE_PV_CPUID +----------------------------- + +Architectures: x86 + +When enabled, KVM will disable paravirtual features provided to the +guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf +(0x40000001). Otherwise, a guest may use the paravirtual features +regardless of what has actually been exposed through the CPUID leaf.
arch/x86/include/asm/kvm_host.h +6 -0
@@ -788,6 +788,12 @@ struct kvm_vcpu_arch {/* AMD MSRC001_0015 Hardware Configuration */ u64 msr_hwcr; + +/* +* Indicates whether PV emulation should be disabled if not present in +* the guest's cpuid. +*/ +bool enforce_pv_feature_cpuid; };struct kvm_lpage_info {
arch/x86/kvm/cpuid.h +16 -0
@@ -5,6 +5,7 @@#include "x86.h" #include <asm/cpu.h> #include <asm/processor.h> +#include <uapi/asm/kvm_para.h> extern u32 kvm_cpu_caps[NCAPINTS ]__read_mostly ;void kvm_set_cpu_caps (void );
@@ -308,4 +309,19 @@ static inline bool page_address_valid(struct kvm_vcpu *vcpu, gpa_t gpa)return PAGE_ALIGNED (gpa) && !(gpa >>cpuid_maxphyaddr (vcpu)); } +static __always_inline bool guest_pv_has(struct kvm_vcpu *vcpu, +unsigned int kvm_feature) +{ +struct kvm_cpuid_entry2 *cpuid; + +if (!vcpu->arch.enforce_pv_feature_cpuid) +return true; + + cpuid =kvm_find_cpuid_entry (vcpu,KVM_CPUID_FEATURES ,0 ); +if (!cpuid) +return false; + +return cpuid->eax & (1u << kvm_feature); +} +#endif
arch/x86/kvm/x86.c +62 -5
151 lines not on this page · raw message
include/uapi/linux/kvm.h +1 -0
@@ -1035,6 +1035,7 @@ struct kvm_ppc_resize_hpt {#define KVM_CAP_LAST_CPU 184#define KVM_CAP_SMALLER_MAXPHYADDR 185#define KVM_CAP_S390_DIAG318 186 +#define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 187#ifdef KVM_CAP_IRQ_ROUTING
Signature · 1 line
2.28.0.236.gb10cc79966-goog
PATCH 4/4 Documentation: kvm: fix some typos in cpuid.rst
In reply to Oliver Upton--- Documentation/virt/kvm/cpuid.rst | 88 ++++++++++++++++---------------- 1 file changed, 44 insertions(+), 44 deletions(-)
Documentation/virt/kvm/cpuid.rst +44 -44
@@ -38,64 +38,64 @@ returns:: where ``flag`` is defined as below: -================================= =========== ================================ -flag value meaning -================================= =========== ================================ -KVM_FEATURE_CLOCKSOURCE 0 kvmclock available at msrs - 0x11 and 0x12 +================================== =========== ================================ +flag value meaning +================================== =========== ================================ +KVM_FEATURE_CLOCKSOURCE 0 kvmclock available at msrs + 0x11 and 0x12 -KVM_FEATURE_NOP_IO_DELAY 1 not necessary to perform delays - on PIO operations +KVM_FEATURE_NOP_IO_DELAY 1 not necessary to perform delays + on PIO operations -KVM_FEATURE_MMU_OP 2 deprecated +KVM_FEATURE_MMU_OP 2 deprecated -KVM_FEATURE_CLOCKSOURCE2 3 kvmclock available at msrs - 0x4b564d00 and 0x4b564d01 +KVM_FEATURE_CLOCKSOURCE2 3 kvmclock available at msrs + 0x4b564d00 and 0x4b564d01 -KVM_FEATURE_ASYNC_PF 4 async pf can be enabled by - writing to msr 0x4b564d02 +KVM_FEATURE_ASYNC_PF 4 async pf can be enabled by + writing to msr 0x4b564d02 -KVM_FEATURE_STEAL_TIME 5 steal time can be enabled by - writing to msr 0x4b564d03 +KVM_FEATURE_STEAL_TIME 5 steal time can be enabled by + writing to msr 0x4b564d03 -KVM_FEATURE_PV_EOI 6 paravirtualized end of interrupt - handler can be enabled by - writing to msr 0x4b564d04 +KVM_FEATURE_PV_EOI 6 paravirtualized end of interrupt + handler can be enabled by + writing to msr 0x4b564d04 -KVM_FEATURE_PV_UNHAULT 7 guest checks this feature bit - before enabling paravirtualized - spinlock support +KVM_FEATURE_PV_UNHALT 7 guest checks this feature bit + before enabling paravirtualized + spinlock support -KVM_FEATURE_PV_TLB_FLUSH 9 guest checks this feature bit - before enabling paravirtualized - tlb flush +KVM_FEATURE_PV_TLB_FLUSH 9 guest checks this feature bit + before enabling paravirtualized + tlb flush -KVM_FEATURE_ASYNC_PF_VMEXIT 10 paravirtualized async PF VM EXIT - can be enabled by setting bit 2 - when writing to msr 0x4b564d02 +KVM_FEATURE_ASYNC_PF_VMEXIT 10 paravirtualized async PF VM EXIT + can be enabled by setting bit 2 + when writing to msr 0x4b564d02 -KVM_FEATURE_PV_SEND_IPI 11 guest checks this feature bit - before enabling paravirtualized - sebd IPIs +KVM_FEATURE_PV_SEND_IPI 11 guest checks this feature bit + before enabling paravirtualized + send IPIs -KVM_FEATURE_PV_POLL_CONTROL 12 host-side polling on HLT can - be disabled by writing - to msr 0x4b564d05. +KVM_FEATURE_PV_POLL_CONTROL 12 host-side polling on HLT can + be disabled by writing + to msr 0x4b564d05. -KVM_FEATURE_PV_SCHED_YIELD 13 guest checks this feature bit - before using paravirtualized - sched yield. +KVM_FEATURE_PV_SCHED_YIELD 13 guest checks this feature bit + before using paravirtualized + sched yield. -KVM_FEATURE_ASYNC_PF_INT 14 guest checks this feature bit - before using the second async - pf control msr 0x4b564d06 and - async pf acknowledgment msr - 0x4b564d07. +KVM_FEATURE_ASYNC_PF_INT 14 guest checks this feature bit + before using the second async + pf control msr 0x4b564d06 and + async pf acknowledgment msr + 0x4b564d07. -KVM_FEATURE_CLOCSOURCE_STABLE_BIT 24 host will warn if no guest-side - per-cpu warps are expeced in - kvmclock -================================= =========== ================================ +KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 24 host will warn if no guest-side + per-cpu warps are expected in + kvmclock +================================== =========== ================================ ::
Signature · 1 line
2.28.0.236.gb10cc79966-goog