Re: [PATCH v18 03/14] KVM: arm64: Manage GCS access and registers for guests
[email protected] Mon, 03 Aug 2026 23:31:36 +0000
| Newsgroups | dev.linux.lists.kvmarm |
|---|---|
| Message-ID | <[email protected]> |
Thank you for your contribution! Sashiko AI review found 3 potential issue(= s) to consider: - [High] EL1 Guarded Control Stack (GCS) registers are incorrectly nested i= nside S1PIE and TCRX capability checks. - [High] EL2 Guarded Control Stack (GCS) registers are incorrectly nested i= nside TCRX capability checks, with asymmetric save/restore logic for GCSPR_= EL2. - [Medium] GCSPR_EL0 and GCSCRE0_EL1 are incorrectly classified as SR_LOC_M= EMORY when in a nested hypervisor context. -- --- Patch [3]: [PATCH v18 03/14] KVM: arm64: Manage GCS access and register= s for guests --- commit 408aec21b1f27709492e1981fcc42dc3f0f70337 Author: Mark Brown <[email protected]> Subject: KVM: arm64: Manage GCS access and registers for guests This patch adds support for exposing and context switching Guarded Control Stack (GCS) registers for guests. It also configures HCRX_EL2.GCSEn to enable GCS instructions. > diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/= hyp/include/hyp/sysreg-sr.h > index a17cbe7582de9..053d7b3c5104d 100644 > --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h > +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h > @@ -144,6 +161,10 @@ static inline void __sysreg_save_el1_state(struct kv= m_cpu_context *ctxt) > if (ctxt_has_s1pie(ctxt)) { > ctxt_sys_reg(ctxt, PIR_EL1) =3D read_sysreg_el1(SYS_PIR); > ctxt_sys_reg(ctxt, PIRE0_EL1) =3D read_sysreg_el1(SYS_PIRE0); > + if (ctxt_has_gcs(ctxt)) { > + ctxt_sys_reg(ctxt, GCSPR_EL1) =3D read_sysreg_el1(SYS_GCSPR); > + ctxt_sys_reg(ctxt, GCSCR_EL1) =3D read_sysreg_el1(SYS_GCSCR); > + } > } [Severity: High] Are the EL1 Guarded Control Stack (GCS) registers incorrectly nested inside the S1PIE and TCRX capability checks? FEAT_GCS, FEAT_S1PIE, and FEAT_TCR2 (TCRX) are architecturally independent = CPU features. If a guest is configured with GCS enabled but S1PIE or TCRX disabled, the host will entirely skip saving the guest's GCSPR_EL1 and GCSCR_EL1 registers during context switches. Does this leave stale host or prior-guest state in these hardware registers, leading to guest state corruption or cross-guest information leaks? > @@ -239,6 +265,11 @@ static inline void __sysreg_restore_el1_state(struct= kvm_cpu_context *ctxt, > if (ctxt_has_s1pie(ctxt)) { > write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1), SYS_PIR); > write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1), SYS_PIRE0); > + > + if (ctxt_has_gcs(ctxt)) { > + write_sysreg_el1(ctxt_sys_reg(ctxt, GCSPR_EL1), SYS_GCSPR); > + write_sysreg_el1(ctxt_sys_reg(ctxt, GCSCR_EL1), SYS_GCSCR); > + } > } [Severity: High] Similarly, is the restoration of GCSPR_EL1 and GCSCR_EL1 incorrectly nested inside the S1PIE and TCRX checks, causing restoration to be skipped when these independent features are disabled? > diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/= sysreg-sr.c > index be685b63e8cf2..2431c18f57928 100644 > --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c > +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c > @@ -61,6 +61,9 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *v= cpu) > =20 > if (ctxt_has_s1poe(&vcpu->arch.ctxt)) > __vcpu_assign_sys_reg(vcpu, POR_EL2, read_sysreg_el1(SYS_POR)); > + > + if (ctxt_has_gcs(&vcpu->arch.ctxt)) > + __vcpu_assign_sys_reg(vcpu, GCSCR_EL2, read_sysreg_el1(SYS_GCSCR)); > } > =20 > /* > @@ -77,6 +80,8 @@ static void __sysreg_save_vel2_state(struct kvm_vcpu *v= cpu) > __vcpu_assign_sys_reg(vcpu, SP_EL2, read_sysreg(sp_el1)); > __vcpu_assign_sys_reg(vcpu, ELR_EL2, read_sysreg_el1(SYS_ELR)); > __vcpu_assign_sys_reg(vcpu, SPSR_EL2, read_sysreg_el1(SYS_SPSR)); > + if (ctxt_has_gcs(&vcpu->arch.ctxt)) > + __vcpu_assign_sys_reg(vcpu, GCSPR_EL2, read_sysreg_el1(SYS_GCSPR)); > =20 > if (ctxt_has_sctlr2(&vcpu->arch.ctxt)) > __vcpu_assign_sys_reg(vcpu, SCTLR2_EL2, read_sysreg_el1(SYS_SCTLR2)); [Severity: High] Is the GCSCR_EL2 save erroneously nested inside the ctxt_has_tcrx() block, while GCSPR_EL2 is saved asymmetrically outside of it? Since GCS does not depend on TCR2 (TCRX), a nested hypervisor running with = GCS but without TCR2 will not have GCSCR_EL2 saved correctly. Furthermore, the asymmetric save logic between the two registers creates an unbalanced cycle that can lead to corrupted nested guest states. > @@ -133,6 +138,11 @@ static void __sysreg_restore_vel2_state(struct kvm_v= cpu *vcpu) > =20 > if (ctxt_has_s1poe(&vcpu->arch.ctxt)) > write_sysreg_el1(__vcpu_sys_reg(vcpu, POR_EL2), SYS_POR); > + > + if (ctxt_has_gcs(&vcpu->arch.ctxt)) { > + write_sysreg_el1(__vcpu_sys_reg(vcpu, GCSCR_EL2), SYS_GCSCR); > + write_sysreg_el1(__vcpu_sys_reg(vcpu, GCSPR_EL2), SYS_GCSPR); > + } > } > =20 > write_sysreg_el1(__vcpu_sys_reg(vcpu, ESR_EL2), SYS_ESR); [Severity: High] Are both EL2 GCS registers erroneously restored inside the ctxt_has_tcrx() block? GCSPR_EL2 was saved unconditionally outside this block in __sysreg_save_vel2_state(), meaning it might be saved but never restored if TCRX is absent. > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 5d5c579d45790..d18ada283809e 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -109,6 +109,10 @@ static enum sr_loc_attr locate_direct_register(const= struct kvm_vcpu *vcpu, > case PIR_EL1: > case PIRE0_EL1: > case POR_EL1: > + case GCSCRE0_EL1: > + case GCSPR_EL0: > + case GCSCR_EL1: > + case GCSPR_EL1: > case ESR_EL1: > case AFSR0_EL1: > case AFSR1_EL1: [Severity: Medium] Are GCSPR_EL0 and GCSCRE0_EL1 incorrectly classified as SR_LOC_MEMORY when = in a nested hypervisor context? These registers are eagerly loaded onto the physical hardware via __sysreg_save_user_state() and __sysreg_restore_user_state(), and they have= no EL2 aliases. They are always resident on the physical CPU when the vCPU is running, regardless of whether the guest is in vEL1 or vEL2 context. Classifying them as SR_LOC_MEMORY when is_hyp_ctxt(vcpu) is true means any host-side access will read the stale vcpu->arch.ctxt.sys_regs array instead= of the active hardware register. Should they unconditionally return SR_LOC_LOA= DED like TPIDR_EL0? --=20 Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260803-arm64-gcs-= [email protected]?part=3D3