[PATCH 2/2] arm64: allow TCR_EL1.TBID0 to be configured

Peter Collingbourne pcc at google.com
Mon Jun 21 22:13:25 PDT 2021


On Wed, Jun 16, 2021 at 5:56 AM Szabolcs Nagy <szabolcs.nagy at arm.com> wrote:
>
> The 06/15/2021 16:41, Peter Collingbourne wrote:
> > On Wed, Nov 25, 2020 at 6:38 AM Szabolcs Nagy <szabolcs.nagy at arm.com> wrote:
> > >
> > > The 11/24/2020 11:18, Peter Collingbourne wrote:
> > > > On Tue, Nov 24, 2020 at 10:47 AM Catalin Marinas
> > > > <catalin.marinas at arm.com> wrote:
> > > > > On Sat, Nov 21, 2020 at 01:59:03AM -0800, Peter Collingbourne wrote:
> > > > > > Introduce a Kconfig option that controls whether TCR_EL1.TBID0 is
> > > > > > set at boot time.
> > > > > >
> > > > > > Setting TCR_EL1.TBID0 increases the number of signature bits used by
> > > > > > the pointer authentication instructions for instruction addresses by 8,
> > > > > > which improves the security of pointer authentication, but it also has
> > > > > > the consequence of changing the operation of the branch instructions
> > > > > > so that they no longer ignore the top byte of the target address but
> > > > > > instead fault if they are non-zero. Since this is a change to the
> > > > > > userspace ABI the option defaults to off.
> > > > > >
> > > > > > Signed-off-by: Peter Collingbourne <pcc at google.com>
> > > > > > Link: https://linux-review.googlesource.com/id/Ife724ad708142bc475f42e8c1d9609124994bbbd
> > > > > > ---
> > > > > > This is more of an RFC. An open question is how to expose this.
> > > > > > Having it be a build-time flag is probably the simplest option
> > > > > > but I guess it could also be a boot flag. Since it involves an
> > > > > > ABI change we may also want a prctl() so that userspace can
> > > > > > figure out which mode it is in.
> > > > > >
> > > > > > I think we should try to avoid it being a per-task property
> > > > > > so that we don't need to swap yet another system register on
> > > > > > task switch.
> > > > >
> > > > > Having it changed per task at run-time is problematic as this bit may be
> > > > > cached in the TLB, so it would require a synchronisation across all CPUs
> > > > > followed by TLBI. It's not even clear to me from the ARM ARM whether
> > > > > this bit is tagged by ASID, which, if not, would make a per-process
> > > > > setting impossible.
> > > > >
> > > > > So this leaves us with a cmdline option. If we are confident that no
> > > > > software makes use of tagged instruction pointers, we could have it
> > > > > default on.
> > > >
> > > > I would be concerned about turning it on by default because tagged
> > > > instruction pointers may end up being used unintentionally as a result
> > > > of emergent behavior. For example, when booting Android under FVP with
> > > > this enabled I discovered that SwiftShader would crash when entering
> > > > JITed code because the code was being stored at a tagged address
> > > > (tagged because it had been allocated using Scudo's MTE allocator).
> > > > Arguably software shouldn't be storing executable code in memory owned
> > > > by the allocator as this would require changing the permissions of
> > > > memory that it doesn't own, but from the kernel's perspective it is
> > > > valid.
> > >
> > > it might be still possible to change this abi on linux by
> > > default, but i don't know what's the right way to manage the
> > > abi transition. i will have to think about it.
> > >
> > > i dont think PROT_MTE|PROT_EXEC is architecturally well
> > > supported (e.g. to have different colored functions or
> > > similar, pc relative addressing doesn't work right).
> > >
> > > (tbi for instruction pointers is unlikely to be useful, but
> > > extra 8 bits for pac is useful. i think we should be able to
> > > move to an abi that is compatible with either setting.)
> > >
> > > (i think supporting mmap/munmap/madvise/mprotect on malloced
> > > memory is problematic in general not just with heap tagging
> > > so it would be nice to fix whatever jit that marks malloced
> > > memory as executable.)
> >
> > Hi Szabolcs,
> >
> > Did you get a chance to think about this?
> >
> > I propose that we start with a command line option that defaults to
> > off. If/when any ABI transition happens we can change the default.
>
> a default off per boot option sounds safe even if
> there are some incompatible binaries.

Okay, let's start with that then, although I'm about 75% sure we
should be able to change the default if we push for it. I've sent a v2
with that implemented.

> (i assume virtualization works: host and guest can
> have different settings, so users can always run
> old systems in kvm.)
>
> however it would be nice to make this part of the
> linux platform abi and avoid fragmentation.
> the difficult bits are
>
> - unclear trade-off: does the abi change have
>   adverse effect on potential tbi/mte/.. use?
>   or even existing usage? (data only tbi is a
>   more complicated concept than plain tbi)

I think it's unlikely that there will be such an effect, at least for
existing usage. Note that Apple has been shipping kernels that enable
TBID0 for several years now and I'm not aware of any consequent
breakage as a result (and as far as I know Apple is a more heavy user
of TBI than anything in the Linux world, sanitizers excepted, given
that e.g. the Swift implementation relies on it).

> - incompatibility cannot be statically detected.
>   (toolchain cannot diagnose or enforce it,
>   it is only detectable at runtime, on a system
>   with the changed setting.)

That is unfortunate, although it later occurred to me that in most
cases the incompatibility should manifest in a particular form, where
the program sets a tagged PC and we enter an instruction abort. This
puts us in the kernel, which may choose to handle the abort by
clearing the tag and resuming the program. At that point, the TBID
feature is basically unobservable for programs that do not use PAC
instructions.

This would of course slow down programs that rely on tagged
instruction pointers, and basically destroys the security of PAC for
instruction pointers by making the hardware error code ineffective (at
least on machines that do not implement enhanced PAC2), so I would
view this as purely an opt-in compatibility scheme to keep old
programs (which by virtue of being old wouldn't be using PAC
instructions) working (albeit more slowly and less securely) rather
than something that new programs should use.

I'm not sure if we should implement this scheme straight away. But I
think the more important thing is that it can be done, which means
that I think it should be relatively safe to turn on the ABI
system-wide and rely on such a scheme to keep old programs working (if
any).

> i think in c the usability of tbi is very limited
> now. the libc and compiler needs a tbi abi for it
> to work (e.g. different tags on pointers to the
> same object break pointer comparision). if tagged
> pointers are not dereferenced and don't escape
> then tbi is not needed. so only custom runtimes
> and implementation internal tooling like hwasan
> or heap tagging can use it. arbitrary user tagged
> pointer is not supported in libc now.

Yes, I think that's a good reason why this is unlikely to break anything.

Peter



More information about the linux-arm-kernel mailing list