Page MenuHomeFreeBSD

Add arm64 pointer authentication support
Needs ReviewPublic

Authored by andrew on Jul 21 2021, 3:32 PM.

Details

Summary

Pointer authentication allows userspace to add instructions to insert
a Pointer Authentication Code (PAC) into a register based on an address
and modifier and check if the PAC is correct. If the check fails it will
either return an invalid address or fault to the kernel.

As many of these instructions are a NOP when disabled and in earlier
revisions of the architecture this can be used, for example, to sign
the return address before pushing it to the stack making Return-oriented
programming (ROP) attack more difficult on hardware that supports them.

The kernel manages five 128 bit signing keys: 2 instruction keys, 2 data
keys, and a generic key. The instructions then use one of these when
signing the registers. Instructions that use the first four store the
PAC in the register being signed, however the instructions that use the
generic key store the PAC in a separate register.

Currently all userspace threads share all the keys within a process
with a new set of userspace keys being generated when executing a new
process. This means a forked child will share its keys with its parent
until it calls an appropriate exec system call.

In the kernel we allow the use of one of the instruction keys, the ia
key. This will be used to sign return addresses in function calls.
Unlike userspace each kernel thread has its own randomly generated.

Thread0 has a static key as does the early code on secondary CPUs.
This should be safe as there is minimal user interaction with these
threads, however we could generate random keys when the Armv8.5
Random number generation instructions are present.

Diff Detail

Repository
R10 FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

Is this significant enough to warrant a config option to turn it off (or maybe a tunable)?

sys/arm64/arm64/locore.S
154

This could benefit from a comment about why initarm doesn't just call ptrauth_start (obvious once you see the problem, but not if you don't...)

sys/arm64/arm64/ptrauth.c
228

Update based on comments from Jess

sys/arm64/arm64/pmap.c
6671–6672

The comment is stalled, it seems

Rebase and update the comment for pmap_switch

share/mk/bsd.cpu.mk
11 ↗(On Diff #93438)

We're enabling this without a knob here - I think we should have a comment explaining why this is OK (NOP on earlier architectures etc.)

share/mk/bsd.cpu.mk
11 ↗(On Diff #93438)

Would people ever want to disable this on a per-program basis?

156 ↗(On Diff #93438)

Same question....

sys/conf/files.arm64
69

This likely warrants a comment in ptrauth.c. It's kinda obvious... but years from now when we're cleaning up we'll want to know why.

share/mk/bsd.cpu.mk
11 ↗(On Diff #93438)

I didn't intend to include this in this review. This was just the simplest way to test.

Remove an unintended change to enable use of pac in the compiler

Check pointer authentication is disabled for ptrauth.c

Add a tunable to disable pac

I'm planning on committing this soon. I was holding off until the ptrace changes are ready, but that will also need lldb/gdb changes to allow for debugging. I decided it was easier to just commit this before the ptrace parts, then come back to the ptrace & lldb changes before enabling building the kernel and userspace for PAC.

This revision was not accepted when it landed; it landed in state Needs Review.Jan 12 2022, 3:28 PM
This revision was automatically updated to reflect the committed changes.

I just did an aarch64 kernel build and it failed with lots of errors on sys/arm64/arm64/ptrauth.c. Reverting this made the build succeed.

Confirmed:

This was on a 13.0-RELEASE-p4 image, so this may work if building on HEAD.

Does it build if you run make kernel-toolchain first?

Ugh, different kernel build environment than I'm used to. Didn't realize the kernel build environment area was that different from the host build. So looks like make kernel-toolchain fixed it. Sorry about the noise.

I think this does mean there is now a hard requirement on LLVM 12 or newer (and some unknown GNU toolchain version) if you want to build an arm64 kernel. Given there's no kernel config option to disable any of this, only a tunable, there isn't a way to work around that. This may be an issue for people using external toolchains.

I think this does mean there is now a hard requirement on LLVM 12 or newer (and some unknown GNU toolchain version) if you want to build an arm64 kernel. Given there's no kernel config option to disable any of this, only a tunable, there isn't a way to work around that. This may be an issue for people using external toolchains.

Yeah, this just broke CheriBSD today when trying to merge this as Morello LLVM is still LLVM 11 (-ish). I have not yet tried to build this with GCC 9 which is the newest GCC toolchain we currently have. This is going to need a COMPILER_FEATURE type thing to control enabling using it, and maybe a fallback using manually assembled instructions or the like for older compilers in ptrauth.c.