[PATCH v1 4/5] arm64: Inject UNDEF when accessing MTE sysregs with MTE disabled

Fuad Tabba tabba at google.com
Fri Nov 28 00:53:34 PST 2025


Hi Marc,

On Fri, 28 Nov 2025 at 08:43, Marc Zyngier <maz at kernel.org> wrote:
>
> On Thu, 27 Nov 2025 14:41:24 +0000,
> Fuad Tabba <tabba at google.com> wrote:
> >
> > Hi Marc,
> >
> > On Thu, 27 Nov 2025 at 14:17, Marc Zyngier <maz at kernel.org> wrote:
> > >
> > > On Thu, 27 Nov 2025 12:22:09 +0000,
> > > Fuad Tabba <tabba at google.com> wrote:
> > > >
> > > > When MTE hardware is present but disabled via software (arm64.nomte or
> > > > CONFIG_ARM64_MTE=n), HCR_EL2.ATA is cleared to prevent use of MTE
> > > > instructions. However, this alone doesn't fully emulate hardware that
> > > > lacks MTE support.
> > > >
> > > > With HCR_EL2.ATA cleared, accesses to certain MTE system registers trap
> > > > to EL2 with exception class ESR_ELx_EC_SYS64. To faithfully emulate
> > > > hardware without MTE (where such accesses would cause an Undefined
> > > > Instruction exception), inject UNDEF into the host.
> > > >
> > > > Signed-off-by: Fuad Tabba <tabba at google.com>
> > > > ---
> > > >  arch/arm64/kvm/hyp/nvhe/hyp-main.c | 44 ++++++++++++++++++++++++++++++
> > > >  1 file changed, 44 insertions(+)
> > > >
> > > > diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > > index 29430c031095..f542e4c17156 100644
> > > > --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > > +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> > > > @@ -686,6 +686,46 @@ static void handle_host_smc(struct kvm_cpu_context *host_ctxt)
> > > >       kvm_skip_host_instr();
> > > >  }
> > > >
> > > > +static void inject_undef64(void)
> > > > +{
> > > > +     unsigned long sctlr, vbar, old, new;
> > > > +     u64 offset, esr;
> > > > +
> > > > +     vbar = read_sysreg_el1(SYS_VBAR);
> > > > +     sctlr = read_sysreg_el1(SYS_SCTLR);
> > > > +     old = read_sysreg_el2(SYS_SPSR);
> > > > +     new = get_except64_cpsr(old, system_supports_mte(), sctlr, PSR_MODE_EL1h);
> > > > +     offset = get_except64_offset(old, PSR_MODE_EL1h, except_type_sync);
> > > > +     esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT) | ESR_ELx_IL;
> > > > +
> > > > +     write_sysreg_el1(esr, SYS_ESR);
> > > > +     write_sysreg_el1(read_sysreg_el2(SYS_ELR), SYS_ELR);
> > > > +     write_sysreg_el1(old, SYS_SPSR);
> > > > +     write_sysreg_el2(vbar + offset, SYS_ELR);
> > > > +     write_sysreg_el2(new, SYS_SPSR);
> > > > +}
> > > > +
> > > > +static bool handle_host_mte(u64 esr)
> > > > +{
> > > > +     /* If we're here for any reason other than MTE, then it's a bug. */
> > > > +
> > > > +     if (read_sysreg(HCR_EL2) & HCR_ATA)
> > > > +             return false;
> > > > +
> > > > +     switch (esr_sys64_to_sysreg(esr)) {
> > > > +     case SYS_RGSR_EL1:
> > > > +     case SYS_GCR_EL1:
> > > > +     case SYS_TFSR_EL1:
> > > > +     case SYS_TFSRE0_EL1:
> > >
> > > How about other things, such as DC GVA? Don't you need to trap and
> > > UNDEF it (which has the side effect of also trapping DC ZVA)?
> > >
> > > Same question for all the DC {C,I,CI}GVA{C,P} instructions.
> >
> > As far as I could tell, none of these are trapped by ATA. The spec
> > says that in the absence of MTE, their behavior is undefined --- which
> > is the same for the ones I'm actually handling here...
> >
> > The reasons I've only handled these is that, when booting a system
> > with a misadvertised MTE, the kernel accesses these registers, and
> > injecting an UNDEF resulted in a nicer failure mode.
>
> But it all comes down to *why* is MTE disabled. Is it because the user
> cannot be arsed with MTE's abysmal^Wstellar performance? Or because
> this is a memory corruption vector on a misconfigured platform?
>
> > What do you suggest, drop this patch (and the one before it), since
> > trying to access MTE is UNDEF, and the kernel that does it is just
> > shooting itself in the foot (no security implications)? Or edit the
> > commit message to make it clear that this is best effort, based on
> > what ATA traps?
>
> No, what I am simply pointing out that that there is more to MTE than
> what gets trapped by ATA, and my hunch is that when MTE is disabled on
> machine that actually has it, it is because something is deeply broken
> with tag management (I have one such machine).
>
> So depending which side of the problem you're on, this could be either
> perfectly valid, or just missing the point.

I see your point. Of course, my main concern is security and
protecting the guest and the hypervisor from a malicious host (and of
course the other way around, but that's the case in non-protected mode
as well). When MTE is disabled, I think most (if not all) MTE-related
instructions are UNDEFINED.

As far as I know, for the devices I've run into, the reason to disable
MTE has been either performance or lack of support. So for that case,
I think that this solution is enough. On the other hand, if the
hardware is broken, then we can try to mitigate as much as possible,
but I think that at the end there is so much we can do.

So for now, I would think that this is enough. If we encounter cases
that require more hardening, we could add that later.

What do you think?
/fuad

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



More information about the linux-arm-kernel mailing list