]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: Trap MTE access and discovery when MTE is disabled
authorFuad Tabba <tabba@google.com>
Thu, 22 Jan 2026 11:22:16 +0000 (11:22 +0000)
committerMarc Zyngier <maz@kernel.org>
Fri, 23 Jan 2026 11:28:48 +0000 (11:28 +0000)
If MTE is not supported by the hardware, or is disabled in the kernel
configuration (`CONFIG_ARM64_MTE=n`) or command line (`arm64.nomte`),
the kernel stops advertising MTE to userspace and avoids using MTE
instructions. However, this is a software-level disable only.

When MTE hardware is present and enabled by EL3 firmware, leaving
`HCR_EL2.ATA` set allows the host to execute MTE instructions (STG, LDG,
etc.) and access allocation tags in physical memory.

Prevent this by clearing `HCR_EL2.ATA` when MTE is disabled. Remove it
from the `HCR_HOST_NVHE_FLAGS` default, and conditionally set it in
`cpu_prepare_hyp_mode()` only when `system_supports_mte()` returns true.
This causes MTE instructions to trap to EL2 when `HCR_EL2.ATA` is
cleared.

Additionally, set `HCR_EL2.TID5` when MTE is disabled. This traps reads
of `GMID_EL1` (Multiple tag transfer ID register) to EL2, preventing the
discovery of MTE parameters (such as tag block size) when the feature is
suppressed.

Early boot code in `head.S` temporarily keeps `HCR_ATA` set to avoid
special-casing initialization paths. This is safe because this code
executes before untrusted code runs and will clear `HCR_ATA` if MTE is
disabled.

Signed-off-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20260122112218.531948-3-tabba@google.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_arm.h
arch/arm64/kernel/head.S
arch/arm64/kvm/arm.c

index e500600e4b9b8cf555a5b555db21b935dc6f83c1..752e3e1604e84426b12fa2720742e2c4b24f5384 100644 (file)
                         HCR_BSU_IS | HCR_FB | HCR_TACR | \
                         HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \
                         HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1)
-#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA)
+#define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK)
 #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H | HCR_AMO | HCR_IMO | HCR_FMO)
 
index ca04b338cb0d173f6d9f5bcee52f6d3d06552599..87a822e5c4ca83c279c733a54c79e64bb41870db 100644 (file)
@@ -299,7 +299,7 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
        isb
 0:
 
-       init_el2_hcr    HCR_HOST_NVHE_FLAGS
+       init_el2_hcr    HCR_HOST_NVHE_FLAGS | HCR_ATA
        init_el2_state
 
        /* Hypervisor stub */
index 4f80da0c0d1de89abc0c0dfd90c8adf318a8c9be..aeac113e5e74ce71b1af1c01320c8f18fc7ab6f7 100644 (file)
@@ -2044,6 +2044,12 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits)
                params->hcr_el2 = HCR_HOST_NVHE_PROTECTED_FLAGS;
        else
                params->hcr_el2 = HCR_HOST_NVHE_FLAGS;
+
+       if (system_supports_mte())
+               params->hcr_el2 |= HCR_ATA;
+       else
+               params->hcr_el2 |= HCR_TID5;
+
        if (cpus_have_final_cap(ARM64_KVM_HVHE))
                params->hcr_el2 |= HCR_E2H;
        params->vttbr = params->vtcr = 0;