linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes
@ 2026-09-15 12:38 Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

Hi folks,

This series consolidates three postings, which it supersedes:
  - The stage-2 MMU pointer hypercall rejection [1]: patch 2, reworked
    to move the hypercalls out of the always-available band instead of
    guarding each handler, and covering __kvm_flush_vm_context() too
    (Marc). __kvm_flush_cpu_context() stays in the set, which the
    sketch on the thread left out.
  - The GICv5 CPU interface series [2]: its hypercall patch reworked
    the same way, as patch 1, and its other three as patches 3, 6 and
    7, with 3's comment and 7's message trimmed and 6 unchanged.
    Sascha's Reviewed-by on the reworked patch isn't carried, the code
    having changed.
  - The __kvm_adjust_pc() host pointer fixes [3]: patches 4 and 5,
    with Vincent's and Joey's nits taken and their Reviewed-by
    collected. (thanks!)

Under pKVM, EL2 still trusts the host at the hypercall boundary in a
few places: hypercalls the host has no use for in protected mode stay
callable, the __kvm_adjust_pc() hypercall it does use takes a host
vCPU nothing pins or validates, and the vgic model EL2 copies out of
the host's struct kvm goes unchecked.

Patches 1 and 2 move the GICv5 CPU interface save/restore and the
stage-2 flushes into the band the dispatcher rejects once pKVM has
finalised. Patch 3 validates the vgic model EL2 copies from the host.
Patches 4 and 5 fix two host pointers dereferenced unvalidated on the
__kvm_adjust_pc() path, the vCPU's VM and the vCPU itself: either
panics the hypervisor if unmapped, and the VM read leaks a bit of hyp
memory through PSR_TCO on MTE hardware. Both carry Cc: stable. The
pKVM core series [4] carries the same two fixes as its patches 2 and
3, in the form posted before Vincent's nits, so that it applies as
is. Patches 6 and 7 are the rest of [2]: the EL1 side of the GICv5
access on nVHE, and a comment fix.

Patch 2 carries no Fixes: tag, no in-tree host path reaching those
hypercalls under pKVM; patch 1 keeps the one it was posted with.

The GICv5 residency and VDPEND hypercalls queued for 7.4 carry the
per-handler check the superseded GICv5 patch used, and can move the
same way.

Superseded postings:
  - 20260914174521.832575-1-fuad.tabba@linux.dev
  - 20260817103228.1203140-1-fuad.tabba@linux.dev (and its v1,
    20260806100256.371164-1-fuad.tabba@linux.dev)
  - 20260915070418.3209779-1-fuad.tabba@linux.dev (and its v1,
    20260914065136.3418404-1-fuad.tabba@linux.dev)

Based on v7.3-rc3 (fd73f4a665989). On kvmarm/next, patches 1 and 2
conflict with the new GICv5 hypercall IDs and patch 5 with the typed
hypercall handlers.

Cheers,
/fuad

[1] https://lore.kernel.org/all/20260914174521.832575-1-fuad.tabba@linux.dev/
[2] https://lore.kernel.org/all/20260817103228.1203140-1-fuad.tabba@linux.dev/
[3] https://lore.kernel.org/all/20260915070418.3209779-1-fuad.tabba@linux.dev/
[4] https://lore.kernel.org/all/20260914113338.159227-1-fuad.tabba@linux.dev/

Fuad Tabba (7):
  KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
  KVM: arm64: Validate the host-provided vgic model in pKVM
  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
  KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch

 arch/arm64/include/asm/kvm_asm.h           | 16 ++++----
 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/hyp-main.c         | 36 +++++++++++++----
 arch/arm64/kvm/hyp/nvhe/pkvm.c             | 47 +++++++++++++++++++++-
 arch/arm64/kvm/hyp/nvhe/switch.c           |  4 +-
 arch/arm64/kvm/vgic/vgic.c                 | 12 ++++--
 8 files changed, 125 insertions(+), 25 deletions(-)


base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
-- 
2.39.5



^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 14:02   ` Marc Zyngier
  2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

__vgic_v5_save_apr() and __vgic_v5_restore_vmcr_apr() remain callable
once pKVM has finalised. pKVM never registers a GICv5 vgic, so neither
has a valid caller in protected mode, and on a GICv3 machine both reach
a register that is UNDEFINED at EL2 and panic the hypervisor.

Move both into the band the dispatcher rejects once pKVM has finalised.

Fixes: af325e87af5da ("KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_asm.h   | 4 ++--
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index e5b92ac09e69e..ea319c496bb26 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -62,6 +62,8 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___kvm_enable_ssbs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_init_lrs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
+	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
 
@@ -87,8 +89,6 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___tracing_write_event,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs,
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs,
-	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
-	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_PKVM_ONLY),
 
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 9a3b92e626adb..7c939baf9c1ba 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__kvm_enable_ssbs),
 	HANDLE_FUNC(__vgic_v3_init_lrs),
 	HANDLE_FUNC(__vgic_v3_get_gic_config),
+	HANDLE_FUNC(__vgic_v5_save_apr),
+	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
 	HANDLE_FUNC(__pkvm_prot_finalize),
 
 	HANDLE_FUNC(__kvm_adjust_pc),
@@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__tracing_write_event),
 	HANDLE_FUNC(__vgic_v3_save_aprs),
 	HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
-	HANDLE_FUNC(__vgic_v5_save_apr),
-	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
 
 	HANDLE_FUNC(__pkvm_host_share_hyp),
 	HANDLE_FUNC(__pkvm_host_unshare_hyp),
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/7] KVM: arm64: Reject the stage-2 flush hypercalls under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

The stage-2 TLB and context flush hypercalls remain callable once pKVM
has finalised, and five of the six dereference a host-supplied
struct kvm_s2_mmu pointer. Under pKVM none has a valid caller: the host
walks no guest stage-2, its TLB flushes go through the handle-based
__pkvm_tlb_flush_vmid, and kvm_arch_vcpu_load() skips both the VMID
update and the CPU context flush.

Move them into the band the dispatcher rejects once pKVM has finalised.

Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260914130152.F0D5F1F000FF@smtp.kernel.org/
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_asm.h   | 12 ++++++------
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 11 ++++++-----
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index ea319c496bb26..b182c908c1a98 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -64,6 +64,12 @@ enum __kvm_host_smccc_func {
 	__KVM_HOST_SMCCC_FUNC___vgic_v3_get_gic_config,
 	__KVM_HOST_SMCCC_FUNC___vgic_v5_save_apr,
 	__KVM_HOST_SMCCC_FUNC___vgic_v5_restore_vmcr_apr,
+	__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa_nsh,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid,
+	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
+	__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
 
 	MARKER(__KVM_HOST_SMCCC_FUNC_MIN_PKVM),
 
@@ -72,12 +78,6 @@ enum __kvm_host_smccc_func {
 	/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
 	__KVM_HOST_SMCCC_FUNC___kvm_adjust_pc,
 	__KVM_HOST_SMCCC_FUNC___kvm_vcpu_run,
-	__KVM_HOST_SMCCC_FUNC___kvm_flush_vm_context,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_ipa_nsh,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid,
-	__KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range,
-	__KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context,
 	__KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff,
 	__KVM_HOST_SMCCC_FUNC___tracing_load,
 	__KVM_HOST_SMCCC_FUNC___tracing_unload,
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index 7c939baf9c1ba..b2657a3c65b40 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -913,16 +913,16 @@ static const hcall_t host_hcall[] = {
 	HANDLE_FUNC(__vgic_v3_get_gic_config),
 	HANDLE_FUNC(__vgic_v5_save_apr),
 	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
-	HANDLE_FUNC(__pkvm_prot_finalize),
-
-	HANDLE_FUNC(__kvm_adjust_pc),
-	HANDLE_FUNC(__kvm_vcpu_run),
 	HANDLE_FUNC(__kvm_flush_vm_context),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_ipa_nsh),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid),
 	HANDLE_FUNC(__kvm_tlb_flush_vmid_range),
 	HANDLE_FUNC(__kvm_flush_cpu_context),
+	HANDLE_FUNC(__pkvm_prot_finalize),
+
+	HANDLE_FUNC(__kvm_adjust_pc),
+	HANDLE_FUNC(__kvm_vcpu_run),
 	HANDLE_FUNC(__kvm_timer_set_cntvoff),
 	HANDLE_FUNC(__tracing_load),
 	HANDLE_FUNC(__tracing_unload),
@@ -969,7 +969,8 @@ static void handle_host_hcall(struct kvm_cpu_context *host_ctxt)
 
 	/*
 	 * If pKVM has been initialised then reject any calls to the
-	 * early "privileged" hypercalls. Note that we cannot reject
+	 * early "privileged" hypercalls, and to the ones the host has no
+	 * use for in protected mode. Note that we cannot reject
 	 * calls to __pkvm_prot_finalize for two reasons: (1) The static
 	 * key used to determine initialisation must be toggled prior to
 	 * finalisation and (2) finalisation is performed on a per-CPU
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
  2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-16 11:00   ` Joey Gouly
  2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

EL2 copies vgic_model from the host's struct kvm unchecked, and the nVHE
world switch dispatches on it with no cpucap guard. A host writing
KVM_DEV_TYPE_ARM_VGIC_V5 makes EL2 access GICv5 CPU interface registers
that are UNDEFINED without FEAT_GCIE, and panics the hypervisor on any
GICv3 machine.

Accept only GICv3, the one model pKVM supports, forcing anything else
to 0.

Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 459bd9eb7e4bc..4c33c863e90e1 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -340,13 +340,19 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 {
 	struct kvm *kvm = &hyp_vm->kvm;
 	unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
+	u32 vgic_model = READ_ONCE(host_kvm->arch.vgic.vgic_model);
 	DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
 
 	/* CTR_EL0 is always under host control, even for protected VMs. */
 	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
 
-	/* Preserve the vgic model so that GICv3 emulation works */
-	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
+	/*
+	 * GICv3 is the only model pKVM runs, and the GICv5 world switch
+	 * touches registers UNDEFINED at EL2 without FEAT_GCIE.
+	 */
+	if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
+		vgic_model = 0;
+	hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;
 
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (2 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, 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/
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
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 | 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(-)

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..f55950ee2a7e4 100644
--- a/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
+++ b/arch/arm64/kvm/hyp/include/hyp/adjust_pc.h
@@ -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)) {
diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index c904647d2f760..5ddb407149667 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -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);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 4c33c863e90e1..737f3a5c4f640 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -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;
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC under pKVM
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (3 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
  2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
  6 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, 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 isn't sharing, and the request is then dropped like any other
bad host pointer.

Fixes: efa1368ba9f4b ("KVM: arm64: Commit exceptions from KVM_SET_VCPU_EVENTS immediately")
Reviewed-by: Vincent Donnefort <vdonnefort@google.com>
Reviewed-by: Joey Gouly <joey.gouly@arm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/hyp-main.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index b2657a3c65b40..a138b42e7cea3 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -542,8 +542,27 @@ 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 fails only
+	 * for memory the host isn't sharing, a bad pointer, so the request
+	 * is dropped.
+	 */
+	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] 12+ messages in thread

* [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (4 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch Fuad Tabba
  6 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

can_access_vgic_from_kernel() excludes only the GICv3 system register
interface, so on a native GICv5 system without FEAT_GCIE_LEGACY it
returns true under nVHE. The kernel then saves and restores the CPU
interface from EL1, where ICH_VMCR_EL2 and the ICH_PPI_* registers are
UNDEFINED, and the nVHE world switch already does that work at EL2.

Require VHE for GICv5 as for GICv3.

Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/vgic/vgic.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index b25303d9919fd..da72779d3b3ee 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1045,11 +1045,15 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 static inline bool can_access_vgic_from_kernel(void)
 {
 	/*
-	 * GICv2 can always be accessed from the kernel because it is
-	 * memory-mapped, and VHE systems can access GICv3 EL2 system
-	 * registers.
+	 * GICv3 and GICv5 drive the CPU interface through EL2 system
+	 * registers, so only VHE reaches them from the kernel. GICv2 is
+	 * memory-mapped and always reachable.
 	 */
-	return !static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) || has_vhe();
+	if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif) ||
+	    kvm_vgic_global_state.type == VGIC_V5)
+		return has_vhe();
+
+	return true;
 }
 
 static inline void vgic_save_state(struct kvm_vcpu *vcpu)
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch
  2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
                   ` (5 preceding siblings ...)
  2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
@ 2026-09-15 12:38 ` Fuad Tabba
  6 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 12:38 UTC (permalink / raw)
  To: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel
  Cc: catalin.marinas, will, joey.gouly, seiden, suzuki.poulose,
	yuzenghui, mark.rutland, vdonnefort, qperret, Sascha.Bischoff,
	steven.price, tabba

__hyp_vgic_save_state() and __hyp_vgic_restore_state() handle GICv5 as
well as GICv3, but their comments name VGICv3 only.

Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/switch.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
index 7318e3e6a5f36..6b9e20f6b31b3 100644
--- a/arch/arm64/kvm/hyp/nvhe/switch.c
+++ b/arch/arm64/kvm/hyp/nvhe/switch.c
@@ -110,7 +110,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
 	write_sysreg(__kvm_hyp_host_vector, vbar_el2);
 }
 
-/* Save VGICv3 state on non-VHE systems */
+/* Save vgic state on non-VHE systems */
 static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 {
 	if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
@@ -125,7 +125,7 @@ static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
 	}
 }
 
-/* Restore VGICv3 state on non-VHE systems */
+/* Restore vgic state on non-VHE systems */
 static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
 {
 	if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
-- 
2.39.5



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
@ 2026-09-15 14:02   ` Marc Zyngier
  2026-09-15 14:12     ` Fuad Tabba
  0 siblings, 1 reply; 12+ messages in thread
From: Marc Zyngier @ 2026-09-15 14:02 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: oupton, kvmarm, linux-arm-kernel, linux-kernel, catalin.marinas,
	will, joey.gouly, seiden, suzuki.poulose, yuzenghui, mark.rutland,
	vdonnefort, qperret, Sascha.Bischoff, steven.price, tabba

On Tue, 15 Sep 2026 13:38:40 +0100,
Fuad Tabba <fuad.tabba@linux.dev> wrote:
>

[...]

> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 9a3b92e626adb..7c939baf9c1ba 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
>  	HANDLE_FUNC(__kvm_enable_ssbs),
>  	HANDLE_FUNC(__vgic_v3_init_lrs),
>  	HANDLE_FUNC(__vgic_v3_get_gic_config),
> +	HANDLE_FUNC(__vgic_v5_save_apr),
> +	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
>  	HANDLE_FUNC(__pkvm_prot_finalize),
>  
>  	HANDLE_FUNC(__kvm_adjust_pc),
> @@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
>  	HANDLE_FUNC(__tracing_write_event),
>  	HANDLE_FUNC(__vgic_v3_save_aprs),
>  	HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
> -	HANDLE_FUNC(__vgic_v5_save_apr),
> -	HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
>  
>  	HANDLE_FUNC(__pkvm_host_share_hyp),
>  	HANDLE_FUNC(__pkvm_host_unshare_hyp),

Why moving things in the array? The whole point of HANDLE_FUNC() is to
abstract the position.

	M.

-- 
Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM
  2026-09-15 14:02   ` Marc Zyngier
@ 2026-09-15 14:12     ` Fuad Tabba
  0 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-15 14:12 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: oupton, kvmarm, linux-arm-kernel, linux-kernel, catalin.marinas,
	will, joey.gouly, seiden, suzuki.poulose, yuzenghui, mark.rutland,
	vdonnefort, qperret, Sascha.Bischoff, steven.price

On Tue, 15 Sept 2026 at 15:02, Marc Zyngier <maz@kernel.org> wrote:
>
> On Tue, 15 Sep 2026 13:38:40 +0100,
> Fuad Tabba <fuad.tabba@linux.dev> wrote:
> >
>
> [...]
>
> > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > index 9a3b92e626adb..7c939baf9c1ba 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > @@ -911,6 +911,8 @@ static const hcall_t host_hcall[] = {
> >       HANDLE_FUNC(__kvm_enable_ssbs),
> >       HANDLE_FUNC(__vgic_v3_init_lrs),
> >       HANDLE_FUNC(__vgic_v3_get_gic_config),
> > +     HANDLE_FUNC(__vgic_v5_save_apr),
> > +     HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
> >       HANDLE_FUNC(__pkvm_prot_finalize),
> >
> >       HANDLE_FUNC(__kvm_adjust_pc),
> > @@ -932,8 +934,6 @@ static const hcall_t host_hcall[] = {
> >       HANDLE_FUNC(__tracing_write_event),
> >       HANDLE_FUNC(__vgic_v3_save_aprs),
> >       HANDLE_FUNC(__vgic_v3_restore_vmcr_aprs),
> > -     HANDLE_FUNC(__vgic_v5_save_apr),
> > -     HANDLE_FUNC(__vgic_v5_restore_vmcr_apr),
> >
> >       HANDLE_FUNC(__pkvm_host_share_hyp),
> >       HANDLE_FUNC(__pkvm_host_unshare_hyp),
>
> Why moving things in the array? The whole point of HANDLE_FUNC() is to
> abstract the position.

It's only cosmetic. The array is in the same order as the enum today,
entry for entry.

Cheers,
/fuad

>
>         M.
>
> --
> Without deviation from the norm, progress is not possible.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
@ 2026-09-16 11:00   ` Joey Gouly
  2026-09-16 11:30     ` Fuad Tabba
  0 siblings, 1 reply; 12+ messages in thread
From: Joey Gouly @ 2026-09-16 11:00 UTC (permalink / raw)
  To: Fuad Tabba
  Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
	catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
	mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price,
	tabba

Question(s)
   |
   |
   v

On Tue, Sep 15, 2026 at 01:38:42PM +0100, Fuad Tabba wrote:
> EL2 copies vgic_model from the host's struct kvm unchecked, and the nVHE
> world switch dispatches on it with no cpucap guard. A host writing
> KVM_DEV_TYPE_ARM_VGIC_V5 makes EL2 access GICv5 CPU interface registers
> that are UNDEFINED without FEAT_GCIE, and panics the hypervisor on any
> GICv3 machine.
> 
> Accept only GICv3, the one model pKVM supports, forcing anything else
> to 0.
> 
> Fixes: 9b8e3d4ca0e73 ("KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore")
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
>  arch/arm64/kvm/hyp/nvhe/pkvm.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> index 459bd9eb7e4bc..4c33c863e90e1 100644
> --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
> +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
> @@ -340,13 +340,19 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
>  {
>  	struct kvm *kvm = &hyp_vm->kvm;
>  	unsigned long host_arch_flags = READ_ONCE(host_kvm->arch.flags);
> +	u32 vgic_model = READ_ONCE(host_kvm->arch.vgic.vgic_model);
>  	DECLARE_BITMAP(allowed_features, KVM_VCPU_MAX_FEATURES);
>  
>  	/* CTR_EL0 is always under host control, even for protected VMs. */
>  	hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0;
>  
> -	/* Preserve the vgic model so that GICv3 emulation works */
> -	hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model;
> +	/*
> +	 * GICv3 is the only model pKVM runs, and the GICv5 world switch
> +	 * touches registers UNDEFINED at EL2 without FEAT_GCIE.
> +	 */
> +	if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> +		vgic_model = 0;
> +	hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;

A bit confused by what is expected by writing 0 here? I would have maybe
expected to refuse running this VM? What happens if the host writes some
garbage here, so vgic_model=0, but then tries to access gic-v3
registers?

Thanks,
Joey

>  
>  	/* No restrictions for non-protected VMs. */
>  	if (!kvm_vm_is_protected(kvm)) {
> -- 
> 2.39.5
> 


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM
  2026-09-16 11:00   ` Joey Gouly
@ 2026-09-16 11:30     ` Fuad Tabba
  0 siblings, 0 replies; 12+ messages in thread
From: Fuad Tabba @ 2026-09-16 11:30 UTC (permalink / raw)
  To: Joey Gouly
  Cc: maz, oupton, kvmarm, linux-arm-kernel, linux-kernel,
	catalin.marinas, will, seiden, suzuki.poulose, yuzenghui,
	mark.rutland, vdonnefort, qperret, Sascha.Bischoff, steven.price

Hi Joey,

On Wed, 16 Sept 2026 at 12:00, Joey Gouly <joey.gouly@arm.com> wrote:
[...]
> > +       if (vgic_model != KVM_DEV_TYPE_ARM_VGIC_V3)
> > +               vgic_model = 0;
> > +       hyp_vm->kvm.arch.vgic.vgic_model = vgic_model;
>
> A bit confused by what is expected by writing 0 here? I would have maybe
> expected to refuse running this VM? What happens if the host writes some
> garbage here, so vgic_model=0, but then tries to access gic-v3
> registers?

0 is vgic_model for a VM with no in-kernel irqchip, which pKVM runs.
An unsupported model is treated the same, as a protected VM's features
are masked rather than rejected.

At EL2 the model only selects the GICv5 world-switch path (GICv3 is
saved and restored under the gicv3_cpuif static key) and gates
__vgic_v3_perform_cpuif_access(), which returns 0 for anything but V3
and leaves a trapped ICC_* access to the host. A host that writes a
model it doesn't have gets a guest without a working GIC, which it can
do anyway, but can't make EL2 run the GICv5 path on a GICv3 machine.

I'll say so in the comment if I respin.

Cheers,
/fuad


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-09-16 11:31 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 12:38 [PATCH 0/7] KVM: arm64: pKVM host hypercall and GICv5 CPU interface fixes Fuad Tabba
2026-09-15 12:38 ` [PATCH 1/7] KVM: arm64: Reject the GICv5 CPU interface hypercalls under pKVM Fuad Tabba
2026-09-15 14:02   ` Marc Zyngier
2026-09-15 14:12     ` Fuad Tabba
2026-09-15 12:38 ` [PATCH 2/7] KVM: arm64: Reject the stage-2 flush " Fuad Tabba
2026-09-15 12:38 ` [PATCH 3/7] KVM: arm64: Validate the host-provided vgic model in pKVM Fuad Tabba
2026-09-16 11:00   ` Joey Gouly
2026-09-16 11:30     ` Fuad Tabba
2026-09-15 12:38 ` [PATCH 4/7] KVM: arm64: Validate the host vCPU's VM before reading it under pKVM Fuad Tabba
2026-09-15 12:38 ` [PATCH 5/7] KVM: arm64: Pin the host vCPU before adjusting its PC " Fuad Tabba
2026-09-15 12:38 ` [PATCH 6/7] KVM: arm64: vgic: Do not access the GICv5 CPU interface from EL1 Fuad Tabba
2026-09-15 12:38 ` [PATCH 7/7] KVM: arm64: Fix stale VGICv3 comments in the nVHE world switch 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).