A process can pass ordinary filesystem permission checks and still wait before its file operation completes. Linux fanotify permission events let a monitoring group intercept selected operations and require a user-space listener to return an allow or deny response. The mechanism inserts a synchronous decision point into the access path rather than merely reporting activity after it occurs.
That distinction makes fanotify useful for security products that need content inspection or policy evaluation close to file access. It also creates a dependency that ordinary notification systems do not have: the kernel may be holding another process at a permission event while user space decides its fate.
Permission events differ from ordinary notifications
Most fanotify events are informational. A listener receives metadata describing activity such as an open or modification, but the operation itself does not depend on a response to that notification.
Permission events have different semantics. Event masks such as FAN_OPEN_PERM, FAN_ACCESS_PERM, and FAN_OPEN_EXEC_PERM represent operations for which the listener can participate in the decision. A fanotify group configured for permission handling receives the event, evaluates it, then writes a fanotify_response carrying FAN_ALLOW or FAN_DENY.
The control path is therefore synchronous:
process requests file operation
|
normal kernel checks
|
fanotify permission event
|
user-space listener
/ \
FAN_ALLOW FAN_DENY
| |
continue rejectFanotify does not replace discretionary access control, ACLs, Linux Security Modules, mount restrictions, or other checks. It adds another decision boundary where the configured event and mark coverage apply.
Marks define the interception surface
A fanotify group does not automatically mediate every file on the machine. fanotify_mark() establishes the objects and event masks associated with the group. Marks can target supported objects such as a filesystem or mount, subject to the API rules and kernel support for the selected mark type and event.
This scope is part of the security property. A daemon watching one mount cannot claim to enforce policy on an unrelated mount. Exclusions and ignored masks can further alter event delivery. The effective enforcement surface is the intersection of group configuration, marks, event masks, filesystem support, and the operation actually performed.
Path topology also matters operationally. A policy daemon may reason about a file by name, yet the event is tied to the kernel object reached by the access. Renames, bind mounts, namespaces, and alternate paths can make pathname-only policy models incomplete even when event delivery itself is functioning correctly.
The event file descriptor is a capability to the object
For permission events that supply an object file descriptor, the metadata read from the fanotify descriptor includes an fd referring to the affected object. The listener can inspect that descriptor rather than reopening a pathname that may have changed between event generation and policy evaluation.
This property reduces a common race in file scanners. Reopening a reported path creates a second lookup that can resolve to a different object after a rename or replacement. Inspecting the event-provided descriptor keeps evaluation attached to the object associated with the event.
The descriptor still requires disciplined lifecycle handling. The listener must close event descriptors after processing them. Leaking one descriptor per event can exhaust process or system resources and turn a security control into an availability problem.
A pathname may still be useful as policy context, but it should not silently become the identity of the object when the decision requires stable object identity.
A response releases the blocked operation
The response structure associates a decision with the event file descriptor. A minimal conceptual response has this shape:
struct fanotify_response response = {
.fd = event_fd,
.response = FAN_ALLOW,
};
write(fanotify_fd, &response, sizeof(response));Production code must validate event records, handle partial or failed I/O correctly, close descriptors, and apply a deliberate policy for errors. The snippet only shows the binding between the event descriptor and the decision.
An allow response means fanotify does not block that operation at this permission decision point. It is not a grant that overrides an earlier or later kernel denial. A deny response rejects the mediated operation through the fanotify boundary.
This distinction prevents a dangerous policy assumption: a scanner cannot use FAN_ALLOW to manufacture access that the caller otherwise lacks.
Listener availability becomes part of access availability
Synchronous mediation couples file access latency to the listener. If policy evaluation requires hashing a large file, contacting another service, waiting on storage, or performing expensive parsing, the requesting process remains delayed for that decision.
The security architecture therefore includes an availability boundary. A listener that stalls can stall covered operations. A listener that consumes events too slowly can also encounter queue pressure. Fanotify exposes queue-overflow reporting, and deployments must treat overflow as a policy-state event rather than as ordinary telemetry loss.
There is no universally correct failure policy. A malware scanner protecting execution may prefer denial when it cannot establish an acceptable result. A service protecting availability may accept a narrower fail-open condition. That choice belongs to deployment policy and must be explicit; the fanotify API does not convert operational failure into a universal security answer.
The listener itself also becomes sensitive infrastructure. Its scheduling, resource limits, restart behavior, and dependency graph can affect every process whose operations fall inside the mediated surface.
Content inspection has a time-of-decision boundary
Holding an event descriptor gives the listener a stable reference to the object, but it does not automatically freeze mutable file contents. Another actor with suitable authority may be able to modify a file while inspection is in progress or after an allow decision.
This limits claims that can be made from scanning alone. An allow decision can state that the listener accepted the state it evaluated under its synchronization assumptions. It does not inherently make the file immutable for the remainder of its lifetime.
Systems that require a stronger property need another mechanism to bind approved content to later use. Read-only storage, integrity mechanisms, immutable deployment artifacts, or application-specific coordination can narrow the mutation window. The correct mechanism depends on the object and threat model.
The same boundary applies to metadata. Policy based on owner, labels, or path context must account for which properties can change concurrently and which kernel references remain stable during evaluation.
Event identity and process identity need separate treatment
Fanotify metadata can identify the process associated with an event, but process identifiers and object descriptors represent different kinds of identity. A numeric PID is not a permanent principal name; process lifetime and PID reuse make long-delayed decisions based only on stored numeric values fragile.
Modern fanotify configurations can request additional information records where supported, including records designed to improve process-reference handling. Applications should base authorization on the identity data and kernel features they actually requested and received rather than infer stronger guarantees from a bare PID.
This is especially relevant when a listener delegates policy evaluation to another component. Passing only a pathname and PID across a long asynchronous pipeline can discard the stable references that made the original event useful.
Permission mediation is narrower than complete sandboxing
Fanotify operates on supported filesystem events. It is not a general system-call policy engine and does not confine network access, IPC, process creation, memory operations, or arbitrary kernel interfaces. Even inside the filesystem domain, enforcement only covers event types and objects selected by the group.
A robust deployment therefore treats fanotify as one enforcement component. LSM policy can impose mandatory access rules, namespace and mount design can constrain visibility, integrity controls can bind content state, and fanotify can add a user-space decision where dynamic inspection is required.
The durable property is precise: for covered permission events, the kernel can suspend a file operation until the responsible fanotify group returns a decision. That power is useful because it is synchronous and object-oriented, but the same properties make listener correctness, coverage, latency, and failure handling part of the security boundary.