fanotify_init(2)
Create an fanotify group: VFS-level file access events with live fds and blockable opens.
- Since
- Linux 2.6.37check your kernel →
- glibc
- unknown
- System
- Linux
- Man page
- fanotify_init(2)
Synopsis
#include <fcntl.h> /* Definition of O_* constants */
#include <sys/fanotify.h>
int fanotify_init(unsigned int flags, unsigned int event_f_flags);Rod's take
inotify tells you what happened after it happened, which is useless when you want to say no. fanotify hands you a live fd to the actual file instead of a name that may already be wrong, and with a content-class group it parks the opener in the kernel until your daemon writes FAN_ALLOW or FAN_DENY. That's what the AV and EDR crowd actually hook. The bill: CAP_SYS_ADMIN for anything useful, every event fd must be closed or you bleed descriptors, and a handler that opens files on its own marked filesystem has built itself a deadlock. Sharp tool. Respect it.
Flags and arguments that matter
| Name | What it does |
|---|---|
| FAN_CLASS_NOTIF | Default class. Notification only; no permission decisions possible. |
| FAN_CLASS_CONTENT | Notification plus permission events, for listeners that need files with their final content (e.g. malware scanners). CAP_SYS_ADMIN. |
| FAN_CLASS_PRE_CONTENT | Notification plus permission events, for listeners that may write data before it's accessed (e.g. HSMs). CAP_SYS_ADMIN. |
| FAN_CLOEXEC | Set close-on-exec on the group fd. |
| FAN_NONBLOCK | Make the group fd nonblocking; read(2) returns EAGAIN when the queue is empty. |
| FAN_UNLIMITED_QUEUE | Remove the event queue limit. Requires CAP_SYS_ADMIN. |
| FAN_REPORT_TIDLinux 4.20 | Report the thread ID instead of the process ID in the event metadata pid field. |
| FAN_REPORT_FIDLinux 5.1 | Identify objects by file handle instead of an open fd; not allowed with the CONTENT/PRE_CONTENT classes. |
| FAN_REPORT_DFID_NAME | Synonym for FAN_REPORT_DIR_FID|FAN_REPORT_NAME (both since Linux 5.9): report parent dir handle plus entry name. |
| FAN_REPORT_PIDFDLinux 5.15 and 5.10.220 | Attach a pidfd for the process that caused the event, so PID reuse can't fool you. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EPERM | Caller lacks a required capability (CAP_SYS_ADMIN for the content classes and unlimited flags). |
| EINVAL | Invalid value in flags or event_f_flags. |
| EMFILE | Per-user fanotify group limit exceeded, or the per-process fd limit was hit. |
| ENOSYS | Kernel built without CONFIG_FANOTIFY. |
| ENOMEM | Allocating the notification group failed. |
Example
int fan = fanotify_init(FAN_CLASS_CONTENT | FAN_CLOEXEC,
O_RDONLY | O_LARGEFILE);
if (fan < 0) err(1, "fanotify_init");
if (fanotify_mark(fan, FAN_MARK_ADD | FAN_MARK_FILESYSTEM,
FAN_OPEN_PERM, AT_FDCWD, "/sensitive") < 0)
err(1, "fanotify_mark");
char buf[4096];
ssize_t n = read(fan, buf, sizeof buf);
struct fanotify_event_metadata *ev = (void *)buf;
for (; FAN_EVENT_OK(ev, n); ev = FAN_EVENT_NEXT(ev, n)) {
if (ev->fd == FAN_NOFD) continue; /* queue overflow */
struct fanotify_response r = { .fd = ev->fd, .response = FAN_ALLOW };
if (ev->mask & FAN_OPEN_PERM) write(fan, &r, sizeof r);
close(ev->fd); /* mandatory */
}Trimmed from the full walkthrough in fanotify(7): watch and block file opens at the VFS layer.
BSD equivalent
FreeBSD and OpenBSD: no equivalent. kqueue(2) EVFILT_VNODE gives after-the-fact vnode notifications only, with no permission decisions.
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
