[PATCH 21/35] arm64: mte: Add in-kernel tag fault handler

Catalin Marinas catalin.marinas at arm.com
Fri Aug 28 05:56:41 EDT 2020


On Thu, Aug 27, 2020 at 12:14:26PM -0700, Evgenii Stepanov wrote:
> On Thu, Aug 27, 2020 at 7:56 AM Catalin Marinas <catalin.marinas at arm.com> wrote:
> > On Thu, Aug 27, 2020 at 03:34:42PM +0200, Andrey Konovalov wrote:
> > > On Thu, Aug 27, 2020 at 3:10 PM Catalin Marinas <catalin.marinas at arm.com> wrote:
> > > > On Thu, Aug 27, 2020 at 02:31:23PM +0200, Andrey Konovalov wrote:
> > > > > On Thu, Aug 27, 2020 at 11:54 AM Catalin Marinas
> > > > > <catalin.marinas at arm.com> wrote:
> > > > > > On Fri, Aug 14, 2020 at 07:27:03PM +0200, Andrey Konovalov wrote:
> > > > > > > +static int do_tag_recovery(unsigned long addr, unsigned int esr,
> > > > > > > +                        struct pt_regs *regs)
> > > > > > > +{
> > > > > > > +     report_tag_fault(addr, esr, regs);
> > > > > > > +
> > > > > > > +     /* Skip over the faulting instruction and continue: */
> > > > > > > +     arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
> > > > > >
> > > > > > Ooooh, do we expect the kernel to still behave correctly after this? I
> > > > > > thought the recovery means disabling tag checking altogether and
> > > > > > restarting the instruction rather than skipping over it.
> > [...]
> > > > > Can we disable MTE, reexecute the instruction, and then reenable MTE,
> > > > > or something like that?
> > > >
> > > > If you want to preserve the MTE enabled, you could single-step the
> > > > instruction or execute it out of line, though it's a bit more convoluted
> > > > (we have a similar mechanism for kprobes/uprobes).
> > > >
> > > > Another option would be to attempt to set the matching tag in memory,
> > > > under the assumption that it is writable (if it's not, maybe it's fine
> > > > to panic). Not sure how this interacts with the slub allocator since,
> > > > presumably, the logical tag in the pointer is wrong rather than the
> > > > allocation one.
> > > >
> > > > Yet another option would be to change the tag in the register and
> > > > re-execute but this may confuse the compiler.
> > >
> > > Which one of these would be simpler to implement?
> >
> > Either 2 or 3 would be simpler (re-tag the memory location or the
> > pointer) with the caveats I mentioned. Also, does the slab allocator
> > need to touch the memory on free with a tagged pointer? Otherwise slab
> > may hit an MTE fault itself.
> 
> Changing the memory tag can cause faults in other threads, and that
> could be very confusing.

It could indeed trigger a chain of faults. It's not even other threads,
it could be the same thread in a different function.

> Probably the safest thing is to retag the register, single step and
> then retag it back, but be careful with the instructions that change
> the address register (like ldr x0, [x0]).

This gets complicated if you have to parse the opcode. If you can
single-step, just set PSTATE.TCO for the instruction. But the
single-step machinery gets more complicated, probably interacts badly
with kprobes.

I think the best option is to disable the MTE checks in TCF on an
_unhandled_ kernel fault, report and continue. For the KASAN tests, add
accessors similar to get_user/put_user which are able to handle the
fault and return an error. Such accessors, since they have a fixup
handler, would not lead to the MTE checks being disabled.

-- 
Catalin



More information about the linux-arm-kernel mailing list