* [PATCH v2 0/2] KVM: arm64: Validate host pointers in __kvm_adjust_pc() under pKVM
@ 2026-09-15 7:04 Fuad Tabba
2026-09-15 7:04 ` [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it " Fuad Tabba
2026-09-15 7:04 ` [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
0 siblings, 2 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 7:04 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, vdonnefort, qperret, tabba
Hi folks,
Changes since v1 [1]:
- New patch 1: enter_exception64() reads the VM's MTE flag through a
host-writable vcpu->kvm that nothing validates. It goes first,
since pinning the vCPU alone leaves that read on an unmapped VM.
(sashiko)
- Dropped the VM pin the fix carried in v1, patch 1 validating that
read at its site.
Two host pointers reach EL2 unvalidated on the __kvm_adjust_pc() path
under pKVM, and this series fixes both. The host vCPU isn't mapped at
EL2 until its first KVM_RUN pins it, and KVM_SET_VCPU_EVENTS with
ext_dabt_pending reaches the hypercall before that. The vcpu->kvm the
exception entry reads the MTE flag from is host-writable, and nothing
checks it. Either one panics the hypervisor, and on MTE-capable
hardware the flag read leaks one bit of hyp memory the host chose,
through PSR_TCO.
These are patches 2 and 3 of the pKVM core series [2], which carries
them so that it applies as is. They're respun here so they can be
applied on their own.
Based on v7.3-rc3 (fd73f4a665989).
Cheers,
/fuad
[1] https://lore.kernel.org/all/20260914065136.3418404-1-fuad.tabba@linux.dev/
[2] https://lore.kernel.org/all/20260914113338.159227-1-fuad.tabba@linux.dev/
Fuad Tabba (2):
KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
arch/arm64/kvm/hyp/exception.c | 5 ++-
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 18 ++++++++++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 19 ++++++++++-
arch/arm64/kvm/hyp/nvhe/pkvm.c | 39 ++++++++++++++++++++++
4 files changed, 79 insertions(+), 2 deletions(-)
base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
2026-09-15 7:04 [PATCH v2 0/2] KVM: arm64: Validate host pointers in __kvm_adjust_pc() under pKVM Fuad Tabba
@ 2026-09-15 7:04 ` Fuad Tabba
2026-09-15 7:34 ` Vincent Donnefort
2026-09-15 10:17 ` Joey Gouly
2026-09-15 7:04 ` [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
1 sibling, 2 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 7:04 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, vdonnefort, qperret, tabba
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.
Fixes: ea7fc1bb1cd1b ("KVM: arm64: Introduce MTE VM feature")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260914070536.877D91F000FF@smtp.kernel.org/
Cc: stable@vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/exception.c | 5 ++-
arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 18 ++++++++++
arch/arm64/kvm/hyp/nvhe/pkvm.c | 39 ++++++++++++++++++++++
3 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
index 754e2dc1df54a..6e60d890afa4a 100644
--- a/arch/arm64/kvm/hyp/exception.c
+++ b/arch/arm64/kvm/hyp/exception.c
@@ -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);
diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
index 4fdfeabefeb43..a4fb04faa7d09 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -13,6 +13,24 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_host.h>
+/*
+ * Under pKVM a host vCPU's ->kvm is host-writable: the nVHE pair
+ * validates it.
+ */
+#ifdef __KVM_NVHE_HYPERVISOR__
+struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu);
+void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *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)) {
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 459bd9eb7e4bc..9bdc7a9b84b8c 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -11,6 +11,8 @@
#include <asm/kvm_emulate.h>
+#include <hyp/adjust_pc.h>
+
#include <nvhe/mem_protect.h>
#include <nvhe/memory.h>
#include <nvhe/pkvm.h>
@@ -304,6 +306,43 @@ struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void)
}
+static struct pkvm_hyp_vm *loaded_hyp_vm_of(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;
+}
+
+/* An unloaded host vCPU's VM is mapped at EL2 only while pinned. */
+struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
+{
+ struct pkvm_hyp_vm *hyp_vm;
+ struct kvm *kvm;
+
+ if (!is_protected_kvm_enabled())
+ return kern_hyp_va(vcpu->kvm);
+
+ hyp_vm = loaded_hyp_vm_of(vcpu);
+ 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 vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+ if (kvm && is_protected_kvm_enabled() && !loaded_hyp_vm_of(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;
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
2026-09-15 7:04 [PATCH v2 0/2] KVM: arm64: Validate host pointers in __kvm_adjust_pc() under pKVM Fuad Tabba
2026-09-15 7:04 ` [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it " Fuad Tabba
@ 2026-09-15 7:04 ` Fuad Tabba
2026-09-15 7:41 ` Vincent Donnefort
2026-09-15 10:47 ` Joey Gouly
1 sibling, 2 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 7:04 UTC (permalink / raw)
To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, vdonnefort, qperret, tabba
Under pKVM, a page the host shares with EL2 is mapped at EL2 only while
it's pinned, and the host vCPU is pinned at its first KVM_RUN.
KVM_SET_VCPU_EVENTS with ext_dabt_pending reaches __kvm_adjust_pc() at
EL2 before that, and dereferencing the unmapped host vCPU panics the
hypervisor. Any process holding /dev/kvm on a pKVM host can trigger it.
Pin the host vCPU around the adjustment when no hyp vCPU is loaded for
it. A loaded hyp vCPU implies it's pinned. A pin fails only for memory
the host never shared, and the request is then dropped like any other
bad host pointer.
Fixes: efa1368ba9f4b ("KVM: arm64: Commit exceptions from KVM_SET_VCPU_EVENTS immediately")
Cc: stable@vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 9a3b92e626adb..4cb7347db2514 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -542,8 +542,25 @@ static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
{
DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
+ struct pkvm_hyp_vcpu *hyp_vcpu;
+ struct kvm_vcpu *host_vcpu;
- __kvm_adjust_pc(kern_hyp_va(vcpu));
+ host_vcpu = __get_host_hyp_vcpus(vcpu, &hyp_vcpu);
+ if (host_vcpu) {
+ __kvm_adjust_pc(host_vcpu);
+ return;
+ }
+
+ /*
+ * With no hyp vCPU loaded for it, the host vCPU may be unpinned,
+ * and so unmapped at EL2: its first run pins it.
+ */
+ host_vcpu = kern_hyp_va(vcpu);
+ if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
+ return;
+
+ __kvm_adjust_pc(host_vcpu);
+ hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
}
static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
--
2.39.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
2026-09-15 7:04 ` [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it " Fuad Tabba
@ 2026-09-15 7:34 ` Vincent Donnefort
2026-09-15 10:03 ` Fuad Tabba
2026-09-15 10:17 ` Joey Gouly
1 sibling, 1 reply; 10+ messages in thread
From: Vincent Donnefort @ 2026-09-15 7:34 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, qperret, tabba
On Tue, Sep 15, 2026 at 08:04:17AM +0100, Fuad Tabba wrote:
> 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.
>
> Fixes: ea7fc1bb1cd1b ("KVM: arm64: Introduce MTE VM feature")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260914070536.877D91F000FF@smtp.kernel.org/
> Cc: stable@vger.kernel.org
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> arch/arm64/kvm/hyp/exception.c | 5 ++-
> arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 18 ++++++++++
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 39 ++++++++++++++++++++++
> 3 files changed, 61 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
> index 754e2dc1df54a..6e60d890afa4a 100644
> --- a/arch/arm64/kvm/hyp/exception.c
> +++ b/arch/arm64/kvm/hyp/exception.c
> @@ -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);
>
> diff --git a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
> index 4fdfeabefeb43..a4fb04faa7d09 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
> @@ -13,6 +13,24 @@
> #include <asm/kvm_emulate.h>
> #include <asm/kvm_host.h>
>
> +/*
> + * Under pKVM a host vCPU's ->kvm is host-writable: the nVHE pair
> + * validates it.
> + */
> +#ifdef __KVM_NVHE_HYPERVISOR__
> +struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu);
> +void vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *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)) {
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index 459bd9eb7e4bc..9bdc7a9b84b8c 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -11,6 +11,8 @@
>
> #include <asm/kvm_emulate.h>
>
> +#include <hyp/adjust_pc.h>
> +
> #include <nvhe/mem_protect.h>
> #include <nvhe/memory.h>
> #include <nvhe/pkvm.h>
> @@ -304,6 +306,43 @@ struct pkvm_hyp_vcpu *pkvm_get_loaded_hyp_vcpu(void)
>
> }
>
> +static struct pkvm_hyp_vm *loaded_hyp_vm_of(struct kvm_vcpu *vcpu)
pkvm_get_loaded_hyp_vm()? to align with the other.
> +{
> + 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;
> +}
> +
> +/* An unloaded host vCPU's VM is mapped at EL2 only while pinned. */
Could we get the last paragraph of the commit here? As this describes quite well
what this is doing.
> +struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
> +{
> + struct pkvm_hyp_vm *hyp_vm;
> + struct kvm *kvm;
> +
> + if (!is_protected_kvm_enabled())
> + return kern_hyp_va(vcpu->kvm);
> +
> + hyp_vm = loaded_hyp_vm_of(vcpu);
> + 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 vcpu_put_kvm(struct kvm_vcpu *vcpu, struct kvm *kvm)
> +{
> + if (kvm && is_protected_kvm_enabled() && !loaded_hyp_vm_of(vcpu))
> + hyp_unpin_shared_mem(kvm, kvm + 1);
> +}
> +
It seems strange for pkvm.c to provides function that aren't prefixed with pkvm_
and declared into adjust_pc.h and not pkvm.h. I wonder if adjust_pc.h should't
just
struct kvm *vcpu_get_kvm(struct kvm_vcpu *vcpu)
{
if (is_protected_kvm_enabled())
return pkvm_vcpu_get_kvm()
else
kern_hyp_va(vcpu->kvm);
}
> struct pkvm_hyp_vm *get_pkvm_hyp_vm(pkvm_handle_t handle)
> {
> struct pkvm_hyp_vm *hyp_vm;
> --
> 2.39.5
>
Beside those nits:
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
--
Vincent
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
2026-09-15 7:04 ` [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
@ 2026-09-15 7:41 ` Vincent Donnefort
2026-09-15 10:47 ` Joey Gouly
1 sibling, 0 replies; 10+ messages in thread
From: Vincent Donnefort @ 2026-09-15 7:41 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, qperret, tabba
On Tue, Sep 15, 2026 at 08:04:18AM +0100, Fuad Tabba wrote:
> Under pKVM, a page the host shares with EL2 is mapped at EL2 only while
> it's pinned, and the host vCPU is pinned at its first KVM_RUN.
> KVM_SET_VCPU_EVENTS with ext_dabt_pending reaches __kvm_adjust_pc() at
> EL2 before that, and dereferencing the unmapped host vCPU panics the
> hypervisor. Any process holding /dev/kvm on a pKVM host can trigger it.
>
> Pin the host vCPU around the adjustment when no hyp vCPU is loaded for
> it. A loaded hyp vCPU implies it's pinned. A pin fails only for memory
> the host never shared, and the request is then dropped like any other
> bad host pointer.
>
> Fixes: efa1368ba9f4b ("KVM: arm64: Commit exceptions from KVM_SET_VCPU_EVENTS immediately")
> Cc: stable@vger.kernel.org
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9a3b92e626adb..4cb7347db2514 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -542,8 +542,25 @@ static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
> static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
> {
> DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
> + struct pkvm_hyp_vcpu *hyp_vcpu;
> + struct kvm_vcpu *host_vcpu;
>
> - __kvm_adjust_pc(kern_hyp_va(vcpu));
> + host_vcpu = __get_host_hyp_vcpus(vcpu, &hyp_vcpu);
> + if (host_vcpu) {
> + __kvm_adjust_pc(host_vcpu);
> + return;
> + }
> +
> + /*
> + * With no hyp vCPU loaded for it, the host vCPU may be unpinned,
> + * and so unmapped at EL2: its first run pins it.
> + */
> + host_vcpu = kern_hyp_va(vcpu);
> + if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
> + return;
> +
> + __kvm_adjust_pc(host_vcpu);
> + hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
> }
>
> static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
> --
> 2.39.5
>
Reviewed-by: Vincent Donnefort <vdonnefor@google.com>
--
Vincent
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
2026-09-15 7:34 ` Vincent Donnefort
@ 2026-09-15 10:03 ` Fuad Tabba
0 siblings, 0 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 10:03 UTC (permalink / raw)
To: Vincent Donnefort
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
yuzenghui, mark.rutland, steven.price, qperret
On Tue, 15 Sept 2026 at 08:34, Vincent Donnefort <vdonnefort@google.com> wrote:
[...]
> Beside those nits:
>
> Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Nits addressed, and I'll respin this as part of a consolidated series,
as requested by Marc.
Thanks for the review!
/fuad
> --
> Vincent
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
2026-09-15 7:04 ` [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it " Fuad Tabba
2026-09-15 7:34 ` Vincent Donnefort
@ 2026-09-15 10:17 ` Joey Gouly
2026-09-15 10:23 ` Fuad Tabba
1 sibling, 1 reply; 10+ messages in thread
From: Joey Gouly @ 2026-09-15 10:17 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
mark.rutland, steven.price, vdonnefort, qperret, tabba
Hi,
On Tue, Sep 15, 2026 at 08:04:17AM +0100, Fuad Tabba wrote:
> 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.
>
> Fixes: ea7fc1bb1cd1b ("KVM: arm64: Introduce MTE VM feature")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260914070536.877D91F000FF@smtp.kernel.org/
> Cc: stable@vger.kernel.org
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> arch/arm64/kvm/hyp/exception.c | 5 ++-
> arch/arm64/kvm/hyp/include/hyp/adjust_pc.h | 18 ++++++++++
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 39 ++++++++++++++++++++++
> 3 files changed, 61 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c
> index 754e2dc1df54a..6e60d890afa4a 100644
> --- a/arch/arm64/kvm/hyp/exception.c
> +++ b/arch/arm64/kvm/hyp/exception.c
> @@ -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))
It's fine to use the "host->kvm" here because even if sets this bit on
the host vCPU, the per-entry handlers in the other series won't copy
across the TCO bit.
Right?
> new |= PSR_TCO_BIT;
> + vcpu_put_kvm(vcpu, kvm);
>
> new |= (old & PSR_DIT_BIT);
>
[snip]
Agree with the nits that Vincent suggested!
Let's see if this sticks this time:
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Thanks,
Joey
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
2026-09-15 10:17 ` Joey Gouly
@ 2026-09-15 10:23 ` Fuad Tabba
0 siblings, 0 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 10:23 UTC (permalink / raw)
To: Joey Gouly
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
mark.rutland, steven.price, vdonnefort, qperret
Hi Joey,
On Tue, 15 Sept 2026 at 11:17, Joey Gouly <joey.gouly@arm.com> wrote:
[...]
> > - if (kvm_has_mte(kern_hyp_va(vcpu->kvm)))
> > + kvm = vcpu_get_kvm(vcpu);
> > + if (kvm && kvm_has_mte(kvm))
>
> It's fine to use the "host->kvm" here because even if sets this bit on
> the host vCPU, the per-entry handlers in the other series won't copy
> across the TCO bit.
> Right?
Yes.
> > new |= PSR_TCO_BIT;
> > + vcpu_put_kvm(vcpu, kvm);
> >
> > new |= (old & PSR_DIT_BIT);
> >
>
> [snip]
>
> Agree with the nits that Vincent suggested!
>
> Let's see if this sticks this time:
> Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Carrying it over for the respin, thanks again!
/fuad
> Thanks,
> Joey
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
2026-09-15 7:04 ` [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
2026-09-15 7:41 ` Vincent Donnefort
@ 2026-09-15 10:47 ` Joey Gouly
2026-09-15 11:00 ` Fuad Tabba
1 sibling, 1 reply; 10+ messages in thread
From: Joey Gouly @ 2026-09-15 10:47 UTC (permalink / raw)
To: Fuad Tabba
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
mark.rutland, steven.price, vdonnefort, qperret, tabba
Hi,
On Tue, Sep 15, 2026 at 08:04:18AM +0100, Fuad Tabba wrote:
> Under pKVM, a page the host shares with EL2 is mapped at EL2 only while
> it's pinned, and the host vCPU is pinned at its first KVM_RUN.
> KVM_SET_VCPU_EVENTS with ext_dabt_pending reaches __kvm_adjust_pc() at
> EL2 before that, and dereferencing the unmapped host vCPU panics the
> hypervisor. Any process holding /dev/kvm on a pKVM host can trigger it.
>
> Pin the host vCPU around the adjustment when no hyp vCPU is loaded for
> it. A loaded hyp vCPU implies it's pinned. A pin fails only for memory
> the host never shared, and the request is then dropped like any other
> bad host pointer.
>
> Fixes: efa1368ba9f4b ("KVM: arm64: Commit exceptions from KVM_SET_VCPU_EVENTS immediately")
> Cc: stable@vger.kernel.org
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9a3b92e626adb..4cb7347db2514 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -542,8 +542,25 @@ static void handle___pkvm_host_mkyoung_guest(struct kvm_cpu_context *host_ctxt)
> static void handle___kvm_adjust_pc(struct kvm_cpu_context *host_ctxt)
> {
> DECLARE_REG(struct kvm_vcpu *, vcpu, host_ctxt, 1);
> + struct pkvm_hyp_vcpu *hyp_vcpu;
> + struct kvm_vcpu *host_vcpu;
>
> - __kvm_adjust_pc(kern_hyp_va(vcpu));
> + host_vcpu = __get_host_hyp_vcpus(vcpu, &hyp_vcpu);
> + if (host_vcpu) {
> + __kvm_adjust_pc(host_vcpu);
> + return;
> + }
> +
> + /*
> + * With no hyp vCPU loaded for it, the host vCPU may be unpinned,
> + * and so unmapped at EL2: its first run pins it.
* A pin only fails if the memory was never shared, drop the request if
* it is a bad host pointer.
Or something like the commit message says.
> + */
> + host_vcpu = kern_hyp_va(vcpu);
> + if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
> + return;
> +
> + __kvm_adjust_pc(host_vcpu);
> + hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
> }
>
> static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Thanks,
Joey
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
2026-09-15 10:47 ` Joey Gouly
@ 2026-09-15 11:00 ` Fuad Tabba
0 siblings, 0 replies; 10+ messages in thread
From: Fuad Tabba @ 2026-09-15 11:00 UTC (permalink / raw)
To: Joey Gouly
Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
mark.rutland, steven.price, vdonnefort, qperret
Hi Joey,
On Tue, 15 Sept 2026 at 11:48, Joey Gouly <joey.gouly@arm.com> wrote:
[...]
> * A pin only fails if the memory was never shared, drop the request if
> * it is a bad host pointer.
>
> Or something like the commit message says.
Ack.
> > + */
> > + host_vcpu = kern_hyp_va(vcpu);
> > + if (hyp_pin_shared_mem(host_vcpu, host_vcpu + 1))
> > + return;
> > +
> > + __kvm_adjust_pc(host_vcpu);
> > + hyp_unpin_shared_mem(host_vcpu, host_vcpu + 1);
> > }
> >
> > static void handle___kvm_flush_vm_context(struct kvm_cpu_context *host_ctxt)
>
> Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Thanks!
/fuad
>
> Thanks,
> Joey
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-15 11:01 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 7:04 [PATCH v2 0/2] KVM: arm64: Validate host pointers in __kvm_adjust_pc() under pKVM Fuad Tabba
2026-09-15 7:04 ` [PATCH v2 1/2] KVM: arm64: Validate the host vCPU's VM before reading it " Fuad Tabba
2026-09-15 7:34 ` Vincent Donnefort
2026-09-15 10:03 ` Fuad Tabba
2026-09-15 10:17 ` Joey Gouly
2026-09-15 10:23 ` Fuad Tabba
2026-09-15 7:04 ` [PATCH v2 2/2] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
2026-09-15 7:41 ` Vincent Donnefort
2026-09-15 10:47 ` Joey Gouly
2026-09-15 11:00 ` Fuad Tabba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).