diff options
| author | Devin Teske <dteske@FreeBSD.org> | 2026-08-16 00:58:19 +0000 |
|---|---|---|
| committer | Devin Teske <dteske@FreeBSD.org> | 2026-08-16 00:58:43 +0000 |
| commit | bdb561843e865eaa5bbdc5394ed9d9c91136240c (patch) | |
| tree | 7fe259ff3acd58946f51470a14653efde87650ca /contrib/csup/(developers-only) | |
| parent | 5b48968c1a57bd1a7f086d7e09add59afa158340 (diff) | |
Bridge the Linux memory protection key syscalls to FreeBSD's native
MPK support instead of returning ENOSYS. Modern Linux software
probes these at startup: Chromium-based browsers (found via
www/linux-brave) use protection keys for V8's heap and JIT
sandboxing, and glibc >= 2.27 exposes the full API.
pkey_alloc() allocates from a per-process bitmap kept in the process
emuldata (key 0 implicitly allocated, matching Linux's
mm_pkey_allocation_map; ENOSPC once keys 1..15 are exhausted or when
PKU is absent, as Linux returns on such hardware) and applies the
requested initial access rights to the calling thread's PKRU, located
in the XSAVE area via xsave_area_offset(). pkey_free() is
bookkeeping only: as on Linux, freeing neither untags pages nor
updates PKRU. pkey_mprotect() performs the protection change and
tags the range through amd64_pkru_update(), factored out of
sysarch(2)'s AMD64_SET_PKRU/AMD64_CLEAR_PKRU implementation so that
both share the same argument checking and map read lock
synchronization with a parallel pmap_vmspace_copy() on fork; tags die
with the mapping, matching Linux VMA semantics. A pkey of -1
degrades to plain mprotect.
The allocation map is inherited on fork and reset on exec. At exec
the Linux sysvecs initialize PKRU to 0x55555554, Linux's init_pkru
default (access disabled for keys 1..15), so memory tagged with a
not yet allocated key is inaccessible to threads that were never
granted rights -- the property V8's thread isolation relies on.
Setting PKRU at exec initializes the user FPU state slightly earlier
than the lazy first-use path; the state would be initialized moments
later in rtld/libc startup regardless. Protection key faults
already deliver SEGV_PKUERR through the existing siginfo
translation.
The common code carries no architecture ifdefs. Machine-dependent
state lives in struct linux_pemuldata_md, embedded in the process
emuldata in the manner of struct mdthread, and common code calls
per-arch lifecycle hooks (linux_pemuldata_init_md/_exec_md) and pkey
back ends after performing the parameter validation Linux applies
regardless of hardware support. On amd64 the implementation lives
in sys/amd64/linux/linux_pkru.c, compiled into linux_common and
serving both the 64-bit and 32-bit Linux ABIs. Elsewhere (arm64,
i386) linux_emul_md.c provides stubs returning what Linux returns on
hardware without protection keys (ENOSPC from pkey_alloc;
pkey_mprotect with a pkey of -1 acts as plain mprotect), so
applications take their normal no-PKU fallback instead of the ENOSYS
path.
PR: 297427
MFC after: 1 month
Reviewed by: kib
Differential Revision: https://reviews.freebsd.org/D58782
Diffstat (limited to 'contrib/csup/(developers-only)')
0 files changed, 0 insertions, 0 deletions
