From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 23E62CCA490 for ; Sun, 18 Oct 2026 17:37:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Subject:Cc:To:From: Message-ID:Date:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=MXN0uxdpPF8mfxNUdX5WRrP0OYPFZhAl37bZ+oP5xko=; b=E60zp4GAhc7shTvpL8AY1v+FOm 1/mhpyQ+DQV+WEUw3/7Vu6UOWw/d0t/Q7WaDmgT9Y3kAkOxeEt3bOQup7G+J0Wv+Z7fTHLXnBcpje qFlyTPNZdy8OluPnlqVd7uTkitpbVpb7hbkSzg/72+uopI+nqpLR/109vMuYfBnIAhCPX3ZnCiOGM DFUpI1nnFCbbTrd1xSmNfxpZBsTK9udv/8ceizMHlhKaXQyHGHiY3yVl2lOKBrnXnvbvBXopRRlxa 5ygl0YeELynwF1BMmt6ATxU+SLZ3mMC8eTMewKzADvlh+3Amkxra84+QehViYQ+fduBbYVtCF5lZs xAZdePsg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1xIUpL-000000066Gm-0TbE; Sun, 18 Oct 2026 17:37:43 +0000 Received: from sea.source.kernel.org ([2600:3c0a:e001:78e:0:1991:8:25]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1xIUpJ-000000066GI-3mt0 for linux-arm-kernel@lists.infradead.org; Sun, 18 Oct 2026 17:37:41 +0000 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by sea.source.kernel.org (Postfix) with ESMTP id C863143C60; Sun, 18 Oct 2026 17:37:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8B4C51F000C5; Sun, 18 Oct 2026 17:37:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1792345060; bh=MXN0uxdpPF8mfxNUdX5WRrP0OYPFZhAl37bZ+oP5xko=; h=Date:From:To:Cc:Subject:In-Reply-To:References; b=KQbQQkNgV907agrD+gqyyskJfcCpa/zjXM9SgGFpIqVzrXhqV241AUsRGQkY3n1z+ Qh/zz8x8j3U9oa6cIx5xtCXd1g+8Cz3qyWj/ztvHAD0pQ114+KspAghpwX20wWFYGm W9jzAFQW1g9UHCAgCbiaUVBt06NqZZkbZAGHvNrL5TlPcUZLuahyONyZxLJc4Ez8Rx knoHuXsDEXMKqkUjr1h71OT9gVy1h4DJv6cu9axfiG/YguadLCOwMYQzJ8H5KX5Qy2 o8VChqcPEC38NWH/H64Lym0ef9qQTzRMr6/FaXdehLSApWQAWbLpTn6jrqtOtLJEJ3 g1wAk7t2mc7kQ== Received: from sofa.misterjones.org ([185.219.108.64] helo=goblin-girl.misterjones.org) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1xIUpG-00000004Npl-1655; Sun, 18 Oct 2026 17:37:38 +0000 Date: Sun, 18 Oct 2026 18:37:37 +0100 Message-ID: <8633u229lq.wl-maz@kernel.org> From: Marc Zyngier To: Fuad Tabba Cc: Oliver Upton , kvmarm@lists.linux.dev, linux-arm-kernel@lists.infradead.org, Joey Gouly , Steffen Eiden , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Mark Rutland , Mark Brown , Lorenzo Stoakes , Fuad Tabba , linux-kernel@vger.kernel.org Subject: Re: [PATCH v2] KVM: arm64: Only enable S1PIE and S1POE with the features they imply In-Reply-To: <20261018080921.3942517-1-fuad.tabba@linux.dev> References: <20261018080921.3942517-1-fuad.tabba@linux.dev> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM-LB/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL-LB/10.8 EasyPG/1.0.0 Emacs/30.1 (aarch64-unknown-linux-gnu) MULE/6.0 (HANACHIRUSATO) MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: fuad.tabba@linux.dev, oupton@kernel.org, kvmarm@lists.linux.dev, linux-arm-kernel@lists.infradead.org, joey.gouly@arm.com, seiden@linux.ibm.com, suzuki.poulose@arm.com, yuzenghui@huawei.com, catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com, broonie@kernel.org, ljs@kernel.org, tabba@google.com, linux-kernel@vger.kernel.org X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Sun, 18 Oct 2026 09:09:20 +0100, Fuad Tabba wrote: >=20 > The world switch skips PIR_EL1, PIRE0_EL1 and POR_EL1 for a guest > without TCR2, but KVM doesn't trap them for a guest with S1PIE or > S1POE. Userspace can hide TCR2 while leaving either visible, and such a > guest then accesses registers that are neither trapped nor switched. >=20 > Under VHE, that leaks values between guests. POR_EL1, which the host > kernel doesn't use, leaks between guests in every mode. On nVHE and > hVHE, pKVM included, the host's own EL1 registers are saved and restored > according to the running guest's features, so the host kernel resumes > with its stage-1 permissions taken from the guest's PIR_EL1 and > PIRE0_EL1. >=20 > As per the architecture, S1PIE and S1POE imply TCR2 and ATS1A, and > S1POE also implies HPDS. Only enable each for a guest that has the > features it implies. A guest that has S1PIE or S1POE without them still > sees the feature in its ID registers, but its accesses to that > feature's registers UNDEF. >=20 > Fixes: 70ed7238297fb ("KVM: arm64: Sanitise ID_AA64MMFR3_EL1") > Fixes: d4a89e5aee23e ("KVM: arm64: Expose S1PIE to guests") > Reported-by: Mark Brown > Link: https://lore.kernel.org/r/20260930-arm64-gcs-v21-2-3556644cd927@ker= nel.org > Suggested-by: Marc Zyngier > Link: https://lore.kernel.org/r/86fqyn2che.wl-maz@kernel.org > Cc: stable@vger.kernel.org > Signed-off-by: Fuad Tabba > --- > Changes in v2: > - Also require FEAT_HPDS for S1POE (Marc) > - Link to v1: https://lore.kernel.org/r/20261015153041.3770032-1-fuad.tab= ba@linux.dev >=20 > Based on Linux 7.3-rc3 (fd73f4a665989). >=20 > arch/arm64/kvm/config.c | 28 ++++++++++++++++++++++++---- > 1 file changed, 24 insertions(+), 4 deletions(-) I'm afraid that this only addresses part of the problem. Ultimately, the idregs themselves require some sanitisation because KVM uses this as the source of truth. I was pointing this in my reply to Broonie, and this is (probably) what sashiko is blabbing on about. I hacked something that could be used as the bases for such sanitisation, although it is quite crude and doesn't cover all of the possible requirements, see below. I've only boot-tested it in a nested guest, and I'm not even sure it actually works (my test box doesn't have these features). M. =46rom 6632cbcebbf4b384f209e988deab0924f03dfff8 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 18 Oct 2026 12:07:09 +0100 Subject: [PATCH] KVM: arm64: Sanitise ID_AA64MMFR3_EL1.S1P[IO]E Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/config.c | 59 +++++++++++++++++++++++++++++++ arch/arm64/kvm/sys_regs.c | 2 ++ 3 files changed, 62 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 6be90f8e19813..ab68ddca234c4 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -1742,6 +1742,7 @@ static inline bool kvm_arch_has_irq_bypass(void) return true; } =20 +void kvm_idregs_enforce_dependencies(struct kvm *kvm); void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt); struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg); void check_feature_map(void); diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c index 6d2650427c5fc..f037a288c9d46 100644 --- a/arch/arm64/kvm/config.c +++ b/arch/arm64/kvm/config.c @@ -59,6 +59,7 @@ struct reg_feat_map_desc { const struct reg_bits_to_feat_map feat_map; const struct reg_bits_to_feat_map *bit_feat_map; const unsigned int bit_feat_map_sz; + const unsigned int idreg_idx; }; =20 #define __NEEDS_FEAT_3(m, f, w, id, fld, lim) \ @@ -130,6 +131,21 @@ struct reg_feat_map_desc { .bit_feat_map_sz =3D ARRAY_SIZE(m), \ } =20 +/* + * Declare the dependency between the features advertised in an id + * register, and the set of other features they depend on. This + * generates a struct reg_feat_map_desc. + */ +#define DECLARE_IDREG_FEAT_MAP(n, r, m, f) \ + struct reg_feat_map_desc n =3D { \ + .name =3D #r, \ + .feat_map =3D NEEDS_FEAT(~(r##_RES0 | \ + r##_RES1), f), \ + .bit_feat_map =3D m, \ + .bit_feat_map_sz =3D ARRAY_SIZE(m), \ + .idreg_idx =3D IDREG_IDX(SYS_##r), \ + } + #define FEAT_SPE ID_AA64DFR0_EL1, PMSVer, IMP #define FEAT_BRBE ID_AA64DFR0_EL1, BRBE, IMP #define FEAT_TRC_SR ID_AA64DFR0_EL1, TraceVer, IMP @@ -1319,6 +1335,14 @@ static const struct reg_bits_to_feat_map vtcr_el2_fe= at_map[] =3D { static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2, vtcr_el2_feat_map, FEAT_AA64EL2); =20 +static const struct reg_bits_to_feat_map id_aa64mmfr3_el1_feat_map[] =3D { + NEEDS_FEAT(ID_AA64MMFR3_EL1_S1PIE, feat_s1pie), + NEEDS_FEAT(ID_AA64MMFR3_EL1_S1POE, feat_s1poe), +}; + +static const DECLARE_IDREG_FEAT_MAP(id_aa64mmfr3_el1_desc, ID_AA64MMFR3_EL= 1, + id_aa64mmfr3_el1_feat_map, FEAT_AA64EL1); + static const struct reg_bits_to_feat_map ich_hfgrtr_feat_map[] =3D { NEEDS_FEAT(ICH_HFGRTR_EL2_ICC_APR_EL1 | ICH_HFGRTR_EL2_ICC_IDRn_EL1 | @@ -1428,6 +1452,41 @@ void __init check_feature_map(void) check_reg_desc(&ich_hfgitr_desc); } =20 +static const struct reg_feat_map_desc *idreg_feat_maps[] =3D { + &id_aa64mmfr3_el1_desc, +}; + +static bool idreg_deps(struct kvm *kvm, + const struct reg_feat_map_desc *r) +{ + struct resx resx =3D {}; + u64 val; + + for (int i =3D 0; i < r->bit_feat_map_sz; i++) { + if ((r->bit_feat_map[i].flags & CALL_FUNC) && + !r->bit_feat_map[i].match(kvm)) + resx.res0 |=3D reg_feat_map_bits(&r->bit_feat_map[i]); + } + + val =3D kvm->arch.id_regs[r->idreg_idx]; + kvm->arch.id_regs[r->idreg_idx] &=3D ~resx.res0; + kvm->arch.id_regs[r->idreg_idx] |=3D resx.res1; + + return val !=3D kvm->arch.id_regs[r->idreg_idx]; +} + +void kvm_idregs_enforce_dependencies(struct kvm *kvm) +{ + bool again; + + do { + again =3D false; + + for (int i =3D 0; i < ARRAY_SIZE(idreg_feat_maps); i++) + again |=3D idreg_deps(kvm, idreg_feat_maps[i]); + } while (again); +} + static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_fea= t_map *map) { u64 regval =3D kvm->arch.id_regs[map->regidx]; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4f18ed2793c33..0687b78cd7c2b 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -5872,6 +5872,8 @@ static int kvm_vm_finalize_sys_regs(struct kvm *kvm) if (kvm_id_regs_final(kvm)) return 0; =20 + kvm_idregs_enforce_dependencies(kvm); + /* * This hacks into the ID registers, so only perform it when the * first vcpu runs, or the kvm_set_vm_id_reg() helper will scream. --=20 2.47.3 --=20 Without deviation from the norm, progress is not possible.