Speaker
Description
We have been supporting pkeys [1] on Linux for 10 years now, and they
are no longer specific to x86: arm64 and powerpc support them too.
Unfortunately, important gaps remain in the kernel-user ABI, making it
difficult to deploy pkeys robustly for key use-cases.
pkeys work in a fairly simple way: the user allocates a new pkey and
then assigns that pkey to a VMA. Access to that VMA is then restricted
by a user-controlled register, which defines RWX permissions for every
pkey. The restrictions apply to both user and kernel accesses (uaccess
and GUP).
Difficulties arise when the kernel interrupts a user thread and then
accesses its memory, or invokes a signal handler. In those cases, it is
unclear which pkeys authority the kernel should use, whether userspace
should be able to configure it, and how to avoid spurious crashes or
confused deputy situations. This is what the current ABI is lacking.
This BoF is especially intended for arch/mm maintainers, libc/runtime
developers, and userspace developers already familiar with pkeys or
deploying pkey-based isolation. The goal is not to present a finished
design, but to agree on the programming model that future ABI work
should follow.
A few important use-cases are currently difficult or impossible to
implement robustly:
-
Isolating the alternate signal stack: mapping it with a non-default
pkey that only signal handlers are allowed to access. -
Sandboxing with pkeys: preventing some context from accessing
even the default pkey (0).
Problematic situations include:
-
Signal delivery [2]: signal handlers may be called asynchronously and
are conceptually independent of the interrupted context.
Userspace may need the pkey register to be reset to a specific value
both for writing the signal frame and invoking the signal handler. -
rseq [3]: the kernel writes to the registered struct rseq when context
switching, which can happen at any point. This is again independent of
the interrupted context, which may not be allowed to write to that
struct. -
io_uring worker threads: these are kernel threads that access user
memory asynchronously. They have their own pkey register value
restricting those accesses, but userspace is not currently able to
configure it. -
Other cases, such as BPF helpers accessing user memory and
process_vm_readv(self) bypassing pkeys completely.
All these issues lead to a set of questions that we need to answer to
create a consistent and unsurprising ABI:
-
Which contexts need a dedicated or userspace-configurable pkey
register value? -
Are there accesses that should intentionally bypass pkeys, and if so,
how should that be documented? -
Can these issues be handled with targeted fixes, or do we need a more
unified ABI design for asynchronous kernel access to pkey-protected
memory?
As Thomas Gleixner put it:
We really need to sit down and actually define a proper programming
model first instead of trying to duct tape the current ill defined
mess forever.
The intended outcome of this BoF is a shared direction for documenting
and extending the pkeys ABI, so that pkeys can be used reliably as
intra-process privilege boundaries rather than only as a best-effort
hardening mechanism.
[1] https://docs.kernel.org/core-api/protection-keys.html
[2] https://inbox.sourceware.org/libc-alpha/fc31e639-f1eb-42d6-9dea-3665d9507f12@arm.com/
[3] https://lore.kernel.org/all/87ikexhbah.ffs@tglx/