PTHREAD_JIT_WRITE_PROTECT_NP(3) | Library Functions Manual | PTHREAD_JIT_WRITE_PROTECT_NP(3) |
pthread_jit_write_protect_supported_np
,
pthread_jit_write_protect_np
,
pthread_jit_write_with_callback_np
,
pthread_jit_write_freeze_callbacks_np
—
thread JIT region write protection settings
#include
<pthread.h>
int
pthread_jit_write_protect_supported_np
(void);
void
pthread_jit_write_protect_np
(int
enabled);
typedef int (*pthread_jit_write_callback_t)(void
*);
int
pthread_jit_write_with_callback_np
(pthread_jit_write_callback_t
callback, void
*ctx);
void
pthread_jit_write_freeze_callbacks_np
(void);
The
pthread_jit_write_protect_supported_np
()
function returns whether per-thread write protection on the MAP_JIT region
is supported on this platform.
On platforms where
pthread_jit_write_protect_supported_np
()
is true, MAP_JIT regions are never writeable and executable simultaneously.
When write protection is enabled for the thread, writes by the thread to the
MAP_JIT region are denied and the MAP_JIT region is executable. When write
protection is disabled for the thread, writes by the thread to the MAP_JIT
region are allowed and the MAP_JIT region is not executable.
The
pthread_jit_write_protect_np
()
function sets whether MAP_JIT region write protection is enabled for this
thread. Pass a non-zero value for the enabled
parameter to enable thread JIT region write protection and allow execution.
Pass a zero value for the enabled parameter to disable
thread JIT write protection and deny execution.
The
pthread_jit_write_with_callback_np
()
function disables write protection, calls the supplied
callback with ctx to write to
the JIT region after validating its input for safety according to
application logic, and then re-enables write protection. That is, it's
roughly equivalent to:
pthread_jit_write_protect_np(false); int rc = callback(ctx); pthread_jit_write_protect_np(true); return rc;
However,
pthread_jit_write_with_callback_np
()
enforces that the callback function must have been
previously enumerated in a static list of allowed JIT write callbacks
declared using the PTHREAD_JIT_WRITE_ALLOW_CALLBACKS_NP macro. Note
that each image (i.e. main executable or framework/dylib) can specify its
own list, and each image may specify at most one list. For example, an
invocation of PTHREAD_JIT_WRITE_ALLOW_CALLBACKS_NP to allow a JIT
write callback jit_write_cb() would be:
static void *jit_region; int jit_write_cb(void *ctx) { size_t len = 0; void *insns = validate_instructions(ctx, &len); if (!insns) { __builtin_trap(); } memcpy(jit_region, insns, len); return 0; } PTHREAD_JIT_WRITE_ALLOW_CALLBACKS_NP(jit_write_cb);
By default, JIT write
callbacks are not allowed in frameworks/dylibs dynamically loaded at runtime
via dlopen(3). However, applications
that need JIT write callbacks in dynamically loaded code can take an
additional entitlement (see
ENTITLEMENTS) to allow them in any
code loaded up until the
pthread_jit_write_freeze_callbacks_np
()
function is called.
On platforms where
pthread_jit_write_protect_supported_np
()
is false, MAP_JIT regions are simultaenously writeable and executable. Calls
to pthread_jit_write_protect_np
() are no-ops on
unsupported platforms. Calls to
pthread_jit_write_with_callback_np
() result in a
direct call to callback on unsupported platforms.
If supported, the
pthread_jit_write_protect_supported_np
() function
will return one. Otherwise the function will return zero.
pthread_jit_write_with_callback_np
()
returns the result returned by the callback
function.
The purpose of per-thread JIT region write protection is to serve as a hardening measure against attacks that attempt to gain code execution by exploiting vulnerabilities to write unintended code into the JIT region.
Some attacks may attempt to defeat JIT write protection by
inducing unexpected/unintended calls to
pthread_jit_write_protect_np
(), e.g. dynamically via
dlsym
(). To further harden against such attacks, the
pthread_jit_write_with_callback_np
() interface is
intended to allow even tighter control over code permitted to write to the
JIT region; in applications that adopt the
com.apple.security.cs.jit-write-allowlist entitlement, only callbacks
specifically enumerated in an invocation of
PTHREAD_JIT_WRITE_ALLOW_CALLBACKS_NP can do so, and
pthread_jit_write_protect_np
() is disabled.
Applications and frameworks should prefer to use
pthread_jit_write_with_callback_np
() as a
defense-in-depth hardening if relevant for their threat model.
Allowed callbacks should assume that their input is attacker-controlled and make an effort to validate that the instructions to be written should be permitted.
com.apple.security.cs.jit-write-allowlist
pthread_jit_write_protect_np
()
should be disabled and
pthread_jit_write_with_callback_np
() must be used
instead to write to the JIT region.com.apple.security.cs.jit-write-allowlist-freeze-late
pthread_jit_write_freeze_callbacks_np
() before
"freezing" the set of allowed JIT write callbacks, to allow the
application to dynamically load code containing JIT write callbacks that
should be allowed.May 1, 2020 | macOS 14.6 |