v4.2.9-1bd9a4b
⚠️ This release is affected by GHSA-w253-42qp-5f2x. Update to v5.0.5-caaf673 or later.
Security notice: This version is affected by GHSA-fpmv-5wgw-qhhr. Upgrade to v4.2.14 or later.
v4.2.9 — Engine performance and stability
This release is a focused engine overhaul with no changes to policy behaviour or the GUI. Every commit targets latency, throughput, and correctness of the system extension under load.
Critical stability fix: ES message lifetime
AUTH events from Endpoint Security carry a message pointer that is only valid until the callback returns — unless the caller explicitly retains it. The event processing pipeline was dispatching work asynchronously while still holding raw message pointers, creating a window where the ES framework could reclaim the message before the pipeline called respond. This has been corrected: every AUTH message is retained before being dispatched and released immediately after respond is called, closing the use-after-free.
Two-stage file auth pipeline
File auth events are now processed through a two-stage pipeline:
- Hot path — a single serial consumer handles cheap classifications (globally allowed, no matching rule). Events that can be decided without ancestry data are responded to and exited immediately.
- Slow path — a bounded concurrent worker pool handles events that require process ancestry. Workers wait for the process to appear in the tree (up to a safety margin before the ES deadline), then evaluate and respond.
The separation keeps the common case (allow) off the slow path entirely and bounds the maximum concurrency on the slow path to prevent thread explosion.
Exec events removed from the auth path
EXEC events were previously subscribed as AUTH_EXEC, requiring an explicit allow response for every process exec in the system. Both the main ES client and the jail adapter now subscribe to NOTIFY_EXEC instead. The event carries identical process-image data without needing a response, removing one auth round-trip per exec from the hot path.
XProtect monitoring path narrowed
The ES muting configuration now restricts monitored paths to only the prefixes covered by active policy rules. Previously a broader set of paths was delivered to the pipeline; paths with no matching rule now never reach the extension.
Threading
All concurrency primitives are created once at startup with explicit QoS and named labels visible in Instruments and the system log:
| Queue | QoS | Role |
|---|---|---|
es-adapter |
userInteractive | ES callback dispatch |
es-jail-adapter |
userInteractive | Jail ES callback dispatch |
pipeline.hot |
userInteractive | Fast-path event consumer |
pipeline.slow |
userInitiated (concurrent) | Ancestry-requiring decisions |
process-tree |
userInitiated | Process tree mutations |
post-respond |
background | Audit logging, TTY notifications |
xpc-server |
userInitiated | All XPC handler work |
metrics |
utility | Periodic metrics logging |
cleanup |
background | Autorelease drain |
All queues use .autoreleaseFrequency: .never and a background timer drains autorelease pools once per minute.
ProcessTree: O(1) ancestor lookups
Ancestor resolution previously walked the tree on every lookup. The process tree now maintains a parent-pointer index so ancestor chains are resolved in O(depth) time with no additional allocations.
Reduced ES cache pressure on startup
The ES authorisation cache was being cleared redundantly during startup and on policy sync. Cache clears are now issued only when the policy actually changes, reducing the burst of re-authorisation events after launch.
Event tracing
A correlation UUID is threaded from the ES callback entry point through the pipeline, audit log, and XPC broadcast. All log lines for a single file auth event share the same UUID, making end-to-end traces straightforward to reconstruct. Debug and info log calls have been removed from the event processing path to eliminate string formatting overhead on every event; warning, error, and fault lines are retained.
Full Changelog: v4.2.8-e9ab07b...v4.2.9-1bd9a4b