public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization
@ 2026-02-13 14:38 Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 1/4] KVM: arm64: Hide S1POE from guests when not supported by the host Fuad Tabba
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Fuad Tabba @ 2026-02-13 14:38 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel
  Cc: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
	catalin.marinas, will, tabba, stable

This series addresses state management and feature synchronization
vulnerabilities in both standard KVM and pKVM implementations on arm64.
The primary focus is ensuring that the hypervisor correctly handles
architectural extensions during context switches to prevent state
corruption.

Changes since v1 [1]:
- Moved optimising away S1POE handling when not supported by host to a
  separate patch.
- Fixed clearing, checking and setting KVM_ARCH_FLAG_ID_REGS_INITIALIZED

[1] https://lore.kernel.org/all/20260212090252.158689-1-tabba@google.com/

Based on Linux 6.19.

Cheers,
/fuad

Cc: stable@vger.kernel.org

Fuad Tabba (4):
  KVM: arm64: Hide S1POE from guests when not supported by the host
  KVM: arm64: Optimise away S1POE handling when not supported by host
  KVM: arm64: Fix ID register initialization for non-protected pKVM
    guests
  KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state()

 arch/arm64/include/asm/kvm_host.h |  3 ++-
 arch/arm64/kvm/hyp/nvhe/pkvm.c    | 37 ++++++++++++++++++++++++++++---
 arch/arm64/kvm/sys_regs.c         |  3 +++
 3 files changed, 39 insertions(+), 4 deletions(-)


base-commit: 05f7e89ab9731565d8a62e3b5d1ec206485eeb0b
-- 
2.53.0.273.g2a3d683680-goog


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

* [PATCH v2 1/4] KVM: arm64: Hide S1POE from guests when not supported by the host
  2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
@ 2026-02-13 14:38 ` Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 2/4] KVM: arm64: Optimise away S1POE handling when not supported by host Fuad Tabba
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Fuad Tabba @ 2026-02-13 14:38 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel
  Cc: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
	catalin.marinas, will, tabba, stable

When CONFIG_ARM64_POE is disabled, KVM does not save/restore POR_EL1.
However, ID_AA64MMFR3_EL1 sanitisation currently exposes the feature to
guests whenever the hardware supports it, ignoring the host kernel
configuration.

If a guest detects this feature and attempts to use it, the host will
fail to context-switch POR_EL1, potentially leading to state corruption.

Fix this by masking ID_AA64MMFR3_EL1.S1POE in the sanitised system
registers, preventing KVM from advertising the feature when the host
does not support it (i.e. system_supports_poe() is false).

Fixes: 70ed7238297f ("KVM: arm64: Sanitise ID_AA64MMFR3_EL1")
Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/sys_regs.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 88a57ca36d96..237e8bd1cf29 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -1816,6 +1816,9 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
 		       ID_AA64MMFR3_EL1_SCTLRX |
 		       ID_AA64MMFR3_EL1_S1POE |
 		       ID_AA64MMFR3_EL1_S1PIE;
+
+		if (!system_supports_poe())
+			val &= ~ID_AA64MMFR3_EL1_S1POE;
 		break;
 	case SYS_ID_MMFR4_EL1:
 		val &= ~ID_MMFR4_EL1_CCIDX;
-- 
2.53.0.273.g2a3d683680-goog


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

* [PATCH v2 2/4] KVM: arm64: Optimise away S1POE handling when not supported by host
  2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 1/4] KVM: arm64: Hide S1POE from guests when not supported by the host Fuad Tabba
@ 2026-02-13 14:38 ` Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 3/4] KVM: arm64: Fix ID register initialization for non-protected pKVM guests Fuad Tabba
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Fuad Tabba @ 2026-02-13 14:38 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel
  Cc: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
	catalin.marinas, will, tabba, stable

Although ID register sanitisation prevents guests from seeing the
feature, adding this check to the helper allows the compiler to entirely
eliminate S1POE-specific code paths (such as context switching POR_EL1)
when the host kernel is compiled without support (CONFIG_ARM64_POE is
disabled).

This aligns with the pattern used for other optional features like SVE
(kvm_has_sve()) and FPMR (kvm_has_fpmr()), ensuring no POE logic if the
host lacks support, regardless of the guest configuration state.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/include/asm/kvm_host.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ac7f970c7883..7af72ca749a6 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -1592,7 +1592,8 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
 	(kvm_has_feat((k), ID_AA64MMFR3_EL1, S1PIE, IMP))
 
 #define kvm_has_s1poe(k)				\
-	(kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
+	(system_supports_poe() &&			\
+	 kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
 
 #define kvm_has_ras(k)					\
 	(kvm_has_feat((k), ID_AA64PFR0_EL1, RAS, IMP))
-- 
2.53.0.273.g2a3d683680-goog


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

* [PATCH v2 3/4] KVM: arm64: Fix ID register initialization for non-protected pKVM guests
  2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 1/4] KVM: arm64: Hide S1POE from guests when not supported by the host Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 2/4] KVM: arm64: Optimise away S1POE handling when not supported by host Fuad Tabba
@ 2026-02-13 14:38 ` Fuad Tabba
  2026-02-13 14:38 ` [PATCH v2 4/4] KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state() Fuad Tabba
  2026-02-13 14:58 ` [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Marc Zyngier
  4 siblings, 0 replies; 6+ messages in thread
From: Fuad Tabba @ 2026-02-13 14:38 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel
  Cc: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
	catalin.marinas, will, tabba, stable

In protected mode, the hypervisor maintains a separate instance of
the `kvm` structure for each VM. For non-protected VMs, this structure is
initialized from the host's `kvm` state.

Currently, `pkvm_init_features_from_host()` copies the
`KVM_ARCH_FLAG_ID_REGS_INITIALIZED` flag from the host without the
underlying `id_regs` data being initialized. This results in the
hypervisor seeing the flag as set while the ID registers remain zeroed.

Consequently, `kvm_has_feat()` checks at EL2 fail (return 0) for
non-protected VMs. This breaks logic that relies on feature detection,
such as `ctxt_has_tcrx()` for TCR2_EL1 support. As a result, certain
system registers (e.g., TCR2_EL1, PIR_EL1, POR_EL1) are not
saved/restored during the world switch, which could lead to state
corruption.

Fix this by explicitly copying the ID registers from the host `kvm` to
the hypervisor `kvm` for non-protected VMs during initialization, since
we trust the host with its non-protected guests' features. Also ensure
`KVM_ARCH_FLAG_ID_REGS_INITIALIZED` is cleared initially in
`pkvm_init_features_from_host` so that `vm_copy_id_regs` can properly
initialize them and set the flag once done.

Fixes: 41d6028e28bd ("KVM: arm64: Convert the SVE guest vcpu flag to a vm flag")
Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 35 ++++++++++++++++++++++++++++++++--
 1 file changed, 33 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 12b2acfbcfd1..59a010221818 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -345,6 +345,7 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc
 	/* No restrictions for non-protected VMs. */
 	if (!kvm_vm_is_protected(kvm)) {
 		hyp_vm->kvm.arch.flags = host_arch_flags;
+		hyp_vm->kvm.arch.flags &= ~BIT_ULL(KVM_ARCH_FLAG_ID_REGS_INITIALIZED);
 
 		bitmap_copy(kvm->arch.vcpu_features,
 			    host_kvm->arch.vcpu_features,
@@ -471,6 +472,35 @@ static int pkvm_vcpu_init_sve(struct pkvm_hyp_vcpu *hyp_vcpu, struct kvm_vcpu *h
 	return ret;
 }
 
+static int vm_copy_id_regs(struct pkvm_hyp_vcpu *hyp_vcpu)
+{
+	struct pkvm_hyp_vm *hyp_vm = pkvm_hyp_vcpu_to_hyp_vm(hyp_vcpu);
+	const struct kvm *host_kvm = hyp_vm->host_kvm;
+	struct kvm *kvm = &hyp_vm->kvm;
+
+	if (!test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &host_kvm->arch.flags))
+		return -EINVAL;
+
+	if (test_and_set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags))
+		return 0;
+
+	memcpy(kvm->arch.id_regs, host_kvm->arch.id_regs, sizeof(kvm->arch.id_regs));
+
+	return 0;
+}
+
+static int pkvm_vcpu_init_sysregs(struct pkvm_hyp_vcpu *hyp_vcpu)
+{
+	int ret = 0;
+
+	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
+		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
+	else
+		ret = vm_copy_id_regs(hyp_vcpu);
+
+	return ret;
+}
+
 static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
 			      struct pkvm_hyp_vm *hyp_vm,
 			      struct kvm_vcpu *host_vcpu)
@@ -490,8 +520,9 @@ static int init_pkvm_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu,
 	hyp_vcpu->vcpu.arch.cflags = READ_ONCE(host_vcpu->arch.cflags);
 	hyp_vcpu->vcpu.arch.mp_state.mp_state = KVM_MP_STATE_STOPPED;
 
-	if (pkvm_hyp_vcpu_is_protected(hyp_vcpu))
-		kvm_init_pvm_id_regs(&hyp_vcpu->vcpu);
+	ret = pkvm_vcpu_init_sysregs(hyp_vcpu);
+	if (ret)
+		goto done;
 
 	ret = pkvm_vcpu_init_traps(hyp_vcpu);
 	if (ret)
-- 
2.53.0.273.g2a3d683680-goog


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

* [PATCH v2 4/4] KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state()
  2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
                   ` (2 preceding siblings ...)
  2026-02-13 14:38 ` [PATCH v2 3/4] KVM: arm64: Fix ID register initialization for non-protected pKVM guests Fuad Tabba
@ 2026-02-13 14:38 ` Fuad Tabba
  2026-02-13 14:58 ` [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Marc Zyngier
  4 siblings, 0 replies; 6+ messages in thread
From: Fuad Tabba @ 2026-02-13 14:38 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel
  Cc: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
	catalin.marinas, will, tabba, stable

The `sve_state` pointer in `hyp_vcpu->vcpu.arch` is initialized as a
hypervisor virtual address during vCPU initialization in
`pkvm_vcpu_init_sve()`.

`unpin_host_sve_state()` calls `kern_hyp_va()` on this address. Since
`kern_hyp_va()` is idempotent, it's not a bug. However, it is
unnecessary and potentially confusing. Remove the redundant conversion.

Signed-off-by: Fuad Tabba <tabba@google.com>
---
 arch/arm64/kvm/hyp/nvhe/pkvm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 59a010221818..389fa5f09c3d 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -392,7 +392,7 @@ static void unpin_host_sve_state(struct pkvm_hyp_vcpu *hyp_vcpu)
 	if (!vcpu_has_feature(&hyp_vcpu->vcpu, KVM_ARM_VCPU_SVE))
 		return;
 
-	sve_state = kern_hyp_va(hyp_vcpu->vcpu.arch.sve_state);
+	sve_state = hyp_vcpu->vcpu.arch.sve_state;
 	hyp_unpin_shared_mem(sve_state,
 			     sve_state + vcpu_sve_state_size(&hyp_vcpu->vcpu));
 }
-- 
2.53.0.273.g2a3d683680-goog


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

* Re: [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization
  2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
                   ` (3 preceding siblings ...)
  2026-02-13 14:38 ` [PATCH v2 4/4] KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state() Fuad Tabba
@ 2026-02-13 14:58 ` Marc Zyngier
  4 siblings, 0 replies; 6+ messages in thread
From: Marc Zyngier @ 2026-02-13 14:58 UTC (permalink / raw)
  To: kvm, kvmarm, linux-arm-kernel, Fuad Tabba
  Cc: joey.gouly, suzuki.poulose, yuzenghui, catalin.marinas, will,
	stable, Oliver Upton

On Fri, 13 Feb 2026 14:38:11 +0000, Fuad Tabba wrote:
> This series addresses state management and feature synchronization
> vulnerabilities in both standard KVM and pKVM implementations on arm64.
> The primary focus is ensuring that the hypervisor correctly handles
> architectural extensions during context switches to prevent state
> corruption.
> 
> Changes since v1 [1]:
> - Moved optimising away S1POE handling when not supported by host to a
>   separate patch.
> - Fixed clearing, checking and setting KVM_ARCH_FLAG_ID_REGS_INITIALIZED
> 
> [...]

Applied to fixes, thanks!

[1/4] KVM: arm64: Hide S1POE from guests when not supported by the host
      commit: f66857bafd4f151c5cc6856e47be2e12c1721e43
[2/4] KVM: arm64: Optimise away S1POE handling when not supported by host
      commit: 9cb0468d0b335ccf769bd8e161cc96195e82d8b1
[3/4] KVM: arm64: Fix ID register initialization for non-protected pKVM guests
      commit: 7e7c2cf0024d89443a7af52e09e47b1fe634ab17
[4/4] KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state()
      commit: 02471a78a052b631204aed051ab718e4d14ae687

Cheers,

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



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

end of thread, other threads:[~2026-02-13 14:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-13 14:38 [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Fuad Tabba
2026-02-13 14:38 ` [PATCH v2 1/4] KVM: arm64: Hide S1POE from guests when not supported by the host Fuad Tabba
2026-02-13 14:38 ` [PATCH v2 2/4] KVM: arm64: Optimise away S1POE handling when not supported by host Fuad Tabba
2026-02-13 14:38 ` [PATCH v2 3/4] KVM: arm64: Fix ID register initialization for non-protected pKVM guests Fuad Tabba
2026-02-13 14:38 ` [PATCH v2 4/4] KVM: arm64: Remove redundant kern_hyp_va() in unpin_host_sve_state() Fuad Tabba
2026-02-13 14:58 ` [PATCH v2 0/4] KVM: arm64: Fix guest feature sanitization and pKVM state synchronization Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox