FAILED: patch "[PATCH] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM" failed to apply to 6.1-stable tree
Subsystems (3)
Sasha Levin
maintainerThe patch below does not apply to the 6.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.1.y
git checkout FETCH_HEAD
git cherry-pick -x cf533b4d3630b229d78ad55567c5db2f365052a2
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '[email protected]' --subject-prefix 'PATCH 6.1.y' 'HEAD^..'
Thanks,
Sasha
------------------ original commit in Linus's tree ------------------
From cf533b4d3630b229d78ad55567c5db2f365052a2 Mon Sep 17 00:00:00 2001
From: Fuad Tabba <[email protected]>
Date: Thu, 1 Oct 2026 14:56:55 +0100
Subject: [PATCH] KVM: arm64: Validate the host vCPU's VM before reading it
under pKVM
On an MTE-capable host under pKVM, enter_exception64() reads the VM's MTE flag through vcpu->kvm, which for a host vCPU is a host-writable pointer nothing validates. The host can point it at any address in the hyp linear map and read back bit 1 of that word through PSR_TCO in the vCPU's CPSR, or panic the hypervisor with an unmapped one.
Get the VM through a get/put pair around the read: a loaded vCPU's is the hyp VM, an unloaded host vCPU's is read once and pinned, and a pointer the host never shared leaves TCO clear.
--- arch/arm64/kvm/hyp/exception.c | 5 ++- arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 28 ++++++++++++++++ arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 2 ++ arch/arm64/kvm/hyp/nvhe/pkvm.c | 37 ++++++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-)
arch/arm64/kvm/hyp/exception.c +4 -1
@@ -70,6 +70,7 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, enum exception_type type) {unsigned long sctlr, vbar, old, new, mode; +struct kvm *kvm;u64 exc_offset; mode = *vcpu_cpsr (vcpu) & (PSR_MODE_MASK |PSR_MODE32_BIT );
@@ -109,8 +110,10 @@ static void enter_exception64(struct kvm_vcpu *vcpu, unsigned long target_mode, new |= (old &PSR_C_BIT ); new |= (old &PSR_V_BIT ); -if (kvm_has_mte (kern_hyp_va (vcpu->kvm))) + kvm =vcpu_get_kvm (vcpu); +if (kvm &&kvm_has_mte (kvm)) new |=PSR_TCO_BIT ; +vcpu_put_kvm (vcpu, kvm); new |= (old &PSR_DIT_BIT );
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h +28 -0
@@ -13,6 +13,34 @@#include <asm/kvm_emulate.h> #include <asm/kvm_host.h> +#ifdef __KVM_NVHE_HYPERVISOR__ +#include <nvhe/pkvm.h> + +/* Under pKVM a host vCPU's ->kvm is host-writable. */ +static inline struct kvm *vcpu_get_kvm (struct kvm_vcpu *vcpu) +{ +if (is_protected_kvm_enabled ()) +return pkvm_vcpu_get_kvm (vcpu); + +return kern_hyp_va (vcpu->kvm); +} + +static inline void vcpu_put_kvm (struct kvm_vcpu *vcpu,struct kvm *kvm) +{ +if (is_protected_kvm_enabled ()) +pkvm_vcpu_put_kvm (vcpu, kvm); +} +#else +static inline struct kvm *vcpu_get_kvm (struct kvm_vcpu *vcpu) +{ +return vcpu->kvm; +} + +static inline void vcpu_put_kvm (struct kvm_vcpu *vcpu,struct kvm *kvm) +{ +} +#endif +static inline void kvm_skip_instr (struct kvm_vcpu *vcpu) {if (vcpu_mode_is_32bit (vcpu)) {
arch/arm64/kvm/hyp/include/nvhe/pkvm.h +2 -0
@@ -83,6 +83,8 @@ struct pkvm_hyp_vcpu *pkvm_load_hyp_vcpu(pkvm_handle_t handle, unsigned int vcpu_idx);void pkvm_put_hyp_vcpu (struct pkvm_hyp_vcpu *hyp_vcpu);struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu (void ); +struct kvm *pkvm_vcpu_get_kvm (struct kvm_vcpu *vcpu); +void pkvm_vcpu_put_kvm (struct kvm_vcpu *vcpu,struct kvm *kvm);struct pkvm_hyp_vm *get_pkvm_hyp_vm (pkvm_handle_t handle);struct pkvm_hyp_vm *get_np_pkvm_hyp_vm (pkvm_handle_t handle);
arch/arm64/kvm/hyp/nvhe/pkvm.c +37 -0
@@ -304,6 +304,43 @@ struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void) } +static struct pkvm_hyp_vm *pkvm_get_loaded_hyp_vm (struct kvm_vcpu *vcpu) +{ +struct pkvm_hyp_vcpu *hyp_vcpu =pkvm_get_loaded_hyp_vcpu (); + +if (hyp_vcpu && + (vcpu == &hyp_vcpu->vcpu || vcpu == hyp_vcpu->host_vcpu)) +return pkvm_hyp_vcpu_to_hyp_vm (hyp_vcpu); + +return NULL ; +} + +/* +* A loaded vCPU's VM is the hyp VM. An unloaded host vCPU's is mapped at +* EL2 only while pinned, so it's read once and pinned; the pin fails for +* memory the host isn't sharing. +*/ +struct kvm *pkvm_vcpu_get_kvm (struct kvm_vcpu *vcpu) +{ +struct pkvm_hyp_vm *hyp_vm =pkvm_get_loaded_hyp_vm (vcpu); +struct kvm *kvm; + +if (hyp_vm) +return &hyp_vm->kvm; + + kvm =kern_hyp_va (READ_ONCE (vcpu->kvm)); +if (hyp_pin_shared_mem (kvm, kvm +1 )) +return NULL ; + +return kvm; +} + +void pkvm_vcpu_put_kvm (struct kvm_vcpu *vcpu,struct kvm *kvm) +{ +if (kvm && !pkvm_get_loaded_hyp_vm (vcpu)) +hyp_unpin_shared_mem (kvm, kvm +1 ); +} +struct pkvm_hyp_vm *get_pkvm_hyp_vm (pkvm_handle_t handle) {struct pkvm_hyp_vm *hyp_vm;
Signature · 1 line
2.53.0