Kernel-Level Enforcement
Shell hooks and application-level integrations (covered in
Interception & Proxying) can be bypassed by any process
that opens a protected file directly, without going through a shell or a hooked
application. Closing that gap requires mediation inside the OS's own access-control
path — before the open() call succeeds.
The decision function
Kernel mediation on any platform reduces to one pure function: given the current policy, a protection-core health report, and an access request (path, requesting process identity), return allow or deny, plus a reason and an audit hash.
%%{init: {"theme": "base", "themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif", "primaryColor": "#eef2f7", "primaryTextColor": "#0b0b0b", "primaryBorderColor": "#5b6b7c", "lineColor": "#5b6b7c", "secondaryColor": "#eef4ff", "tertiaryColor": "#f4f3f0", "clusterBkg": "#f9f9f7", "clusterBorder": "#c3c2b7", "edgeLabelBackground": "#fcfcfb", "actorBkg": "#eef2f7", "actorBorder": "#5b6b7c", "actorTextColor": "#0b0b0b", "actorLineColor": "#5b6b7c", "signalColor": "#52514e", "signalTextColor": "#0b0b0b", "labelBoxBkgColor": "#eef4ff", "labelBoxBorderColor": "#5b6b7c", "labelTextColor": "#0b0b0b", "loopTextColor": "#0b0b0b", "noteBkgColor": "#fdf3d9", "noteBorderColor": "#c98500", "noteTextColor": "#3d2f00", "activationBorderColor": "#5b6b7c", "activationBkgColor": "#eef4ff", "sequenceNumberColor": "#ffffff"}}}%%
flowchart LR
Req["Process requests\nfile open"] --> Unprot{"Path is\nprotected?"}
Unprot -- "no" --> Allow1["Allow\n(no evaluation needed)"]
Unprot -- "yes" --> Health{"Protection core\nhealthy?"}
Health -- "degraded / unavailable" --> Deny1["Deny\n(fail-closed:\nstrict_fallback)"]
Health -- "healthy" --> Ctx{"Process context\nmatches an\napproved selector?"}
Ctx -- "unknown / unclassifiable" --> Deny2["Deny\n(fail-closed default)"]
Ctx -- "explicitly blocked" --> Deny3["Deny\n(blocked wins over approved)"]
Ctx -- "explicitly approved" --> Allow2["Allow"]
style Deny1 fill:#fbe4e4,stroke:#d03b3b,color:#5c1616
style Deny2 fill:#fbe4e4,stroke:#d03b3b,color:#5c1616
style Deny3 fill:#fbe4e4,stroke:#d03b3b,color:#5c1616
Two properties of this function matter more than any platform-specific mechanism:
- Unknown is denied. A process the system cannot classify is treated as untrusted by default.
- An unhealthy protection core denies protected-path access outright. Unprotected paths remain usable so the workstation isn't bricked, but the specific guarantee this component exists to provide degrades to a fully closed, deny-all state.
Linux — fanotify (real kernel enforcement, in production)
Linux mediation uses fanotify with FAN_CLASS_CONTENT and
FAN_OPEN_PERM / FAN_OPEN_EXEC_PERM — a genuine kernel permission hook: the
kernel blocks the calling process until the monitor responds, and the monitor's response
is authoritative. Marks are placed filesystem-wide where the kernel supports it, falling
back to mount-level marks otherwise. This is combined with two additional layers for
defense in depth:
%%{init: {"theme": "base", "themeVariables": {"fontFamily": "-apple-system, Segoe UI, Helvetica, Arial, sans-serif", "primaryColor": "#eef2f7", "primaryTextColor": "#0b0b0b", "primaryBorderColor": "#5b6b7c", "lineColor": "#5b6b7c", "secondaryColor": "#eef4ff", "tertiaryColor": "#f4f3f0", "clusterBkg": "#f9f9f7", "clusterBorder": "#c3c2b7", "edgeLabelBackground": "#fcfcfb", "actorBkg": "#eef2f7", "actorBorder": "#5b6b7c", "actorTextColor": "#0b0b0b", "actorLineColor": "#5b6b7c", "signalColor": "#52514e", "signalTextColor": "#0b0b0b", "labelBoxBkgColor": "#eef4ff", "labelBoxBorderColor": "#5b6b7c", "labelTextColor": "#0b0b0b", "loopTextColor": "#0b0b0b", "noteBkgColor": "#fdf3d9", "noteBorderColor": "#c98500", "noteTextColor": "#3d2f00", "activationBorderColor": "#5b6b7c", "activationBkgColor": "#eef4ff", "sequenceNumberColor": "#ffffff"}}}%%
flowchart TB
L1["Layer 1 — profile.d shell hook\n(covers interactive shells)"]
L2["Layer 2 — LD_PRELOAD\n(covers dynamically linked processes)"]
L3["Layer 3 — fanotify FAN_OPEN_PERM\n(kernel-level, covers everything else,\nincluding statically linked binaries)"]
L1 -.bypassed by non-shell processes.-> L3
L2 -.bypassed by static binaries.-> L3
style L3 fill:#2a78d6,stroke:#184f95,color:#ffffff,stroke-width:2px
Layer 3 is the actual security boundary; layers 1–2 exist for low-overhead common-case handling and better error messages.
macOS — Endpoint Security Framework (implemented, gated on an Apple entitlement)
The macOS design uses Apple's Endpoint Security framework, subscribing to
AUTH_OPEN-class authorization events from a dedicated protection-core process, with
the same classification model as Linux (exec path, code-signing identity, team ID, parent
process chain) and the same health states (healthy, degraded, unavailable,
unsupported) feeding the same fail-closed decision function.
Four alternatives were weighed before choosing Endpoint Security: three rejected on technical merits, one deferred:
| Alternative | Disposition | Reasoning |
|---|---|---|
| Shell-hook mediation only | Rejected | Cannot cover a process that opens a file directly, bypassing any shell |
| FSEvents / audit logs / periodic scans | Rejected | Observational and delayed — can only report after the fact, cannot block before a read completes |
| Sandbox profiles / TCC / filesystem permissions | Rejected | Cannot express this product's process-identity-based policy model cleanly |
| Linux-style kernel module / eBPF equivalent | Deferred, not evaluated on technical merits | The decision to build Endpoint Security first was sequencing (proving the model on the hardest platform first), not a finding that a Linux-style mechanism doesn't apply to macOS — this alternative simply wasn't assessed for macOS at this stage |
Continue to Interception & Proxying.