int main(int argc, char** argv) { int fan_fd, len; char buf[sizeof(struct fanotify_event_metadata)*1024]; struct fanotify_event_metadata *metadata; if (argc != 3) { printf("Usage: %s <root-dir> <procfs>\n", argv[0]); return 1; } procfs = argv[2]; fan_fd = fanotify_init(0, 0); if (fan_fd == -1) { perror("fanotify_init"); return 1; } fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS, AT_FDCWD, argv[1]); if (fan_fd == -1) { perror("fanotify_mark"); return 1; } while (1) { len = read(fan_fd, buf, sizeof(buf)); metadata = (struct fanotify_event_metadata*)&buf; while (FAN_EVENT_OK(metadata, len)) { print_filename(metadata->fd); close(metadata->fd); metadata = FAN_EVENT_NEXT(metadata, len); } } }
static void setup(void) { tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); fd_notify = fanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY); if (fd_notify < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } if (fanotify_mark(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_MOUNT | FAN_MARK_ADD, " "FAN_OPEN, AT_FDCWD, \".\") failed", fd_notify); } }
static void setup(void) { tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); sprintf(fname, "tfile_%d", getpid()); fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700); SAFE_WRITE(cleanup, 1, fd, fname, 1); /* close the file we have open */ SAFE_CLOSE(cleanup, fd); if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } }
static void setup(void) { int fd; tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); sprintf(fname, "fname_%d", getpid()); fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0644); SAFE_CLOSE(cleanup, fd); sprintf(sname, "symlink_%d", getpid()); SAFE_SYMLINK(cleanup, fname, sname); sprintf(dir, "dir_%d", getpid()); SAFE_MKDIR(cleanup, dir, 0755); if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY)) < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } }
static int open_fanotify_fds(void) { struct objhead *head; unsigned int i; head = get_objhead(OBJ_GLOBAL, OBJ_FD_FANOTIFY); head->destroy = &fanotifyfd_destructor; for (i = 0; i < NR_INOTIFYFDS; i++) { struct object *obj; unsigned long flags, eventflags; int fd; eventflags = get_fanotify_init_event_flags(); flags = get_fanotify_init_flags(); fd = fanotify_init(flags, eventflags); if (fd < 0) continue; obj = alloc_object(); obj->fanotifyfd = fd; add_object(obj, OBJ_GLOBAL, OBJ_FD_FANOTIFY); output(2, "fd[%d] = fanotify_init(%lx, %lx)\n", fd, flags, eventflags); } //FIXME: right now, returning FALSE means "abort everything", not // "skip this provider", so on -ENOSYS, we have to still register. return TRUE; }
static int do_test (void) { int fd, ret; fd = fanotify_init (0, 0); if (fd < 0) { switch (errno) { case ENOSYS: puts ("SKIP: missing support for fanotify (check CONFIG_FANOTIFY=y)"); return 0; case EPERM: puts ("SKIP: missing proper permissions for runtime test"); return 0; } perror ("fanotify_init (0, 0) failed"); return 1; } ret = fanotify_mark (fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_ACCESS | FAN_MODIFY | FAN_OPEN | FAN_CLOSE | FAN_ONDIR | FAN_EVENT_ON_CHILD, AT_FDCWD, "."); if (ret) { perror ("fanotify_mark (...) failed"); return 1; } puts ("All OK"); return 0; }
int main() { unsigned int init_flags = FAN_CLASS_CONTENT | FAN_UNLIMITED_MARKS | FAN_NONBLOCK; int connection = fanotify_init(init_flags, O_RDONLY | O_LARGEFILE); // TODO: O_RDWR and fallback enable flag if gets into 2.6.37 if (connection < 0) { PRINT("Can't connect to fanotify" << errno); return 1; } // threading const unsigned int THREAD_COUNT = 5; typedef std::vector<ScannerThread*> ScannerThreadList; ScannerThreadList scannerThreads; for (unsigned int i=0;i<THREAD_COUNT;i++) { scannerThreads.push_back(new ScannerThread(connection)); } for (ScannerThreadList::const_iterator it=scannerThreads.begin();it!=scannerThreads.end();it++) { (*it)->start(); } // Mark filesystems markMount(connection, ROOT_DIR); markMount(connection, ECRYPT_DIR); // Scanning for(unsigned int i=0;i<120;i++) { sleep(1); time_t now = time(0); for (ScannerThreadList::const_iterator it=scannerThreads.begin();it!=scannerThreads.end();it++) { (*it)->printIfStale(now); } } unmarkMount(connection, ROOT_DIR); unmarkMount(connection, ECRYPT_DIR); sleep(10); // Allow pending requests time_t now = time(0); for (ScannerThreadList::const_iterator it=scannerThreads.begin();it!=scannerThreads.end();it++) { (*it)->printIfStale(now); } close(connection); return 0; }
int main(void) { struct fanotify_event_metadata* event; int file_fd; int fd = fanotify_init(0, O_RDONLY); if (fd == -1 && errno == EPERM) { atomic_puts("fanotify requires CAP_SYS_ADMIN (in the root namespace) but " "we don't have those privileges; skipping tests"); atomic_puts("EXIT-SUCCESS"); return 0; } if (fd == -1 && errno == ENOSYS) { atomic_puts("fanotify is not available in this kernel; skipping tests"); atomic_puts("EXIT-SUCCESS"); return 0; } test_assert(fd >= 0); file_fd = open("foo", O_WRONLY | O_CREAT, 0777); test_assert(file_fd >= 0); test_assert(0 == close(file_fd)); test_assert(0 == fanotify_mark(fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, "foo")); file_fd = open("foo", O_WRONLY | O_CREAT, 0777); test_assert(file_fd >= 0); test_assert(0 == close(file_fd)); ALLOCATE_GUARD(event, 'x'); test_assert(sizeof(*event) == read(fd, event, sizeof(*event))); VERIFY_GUARD(event); test_assert(event->event_len == sizeof(*event)); test_assert(event->vers == FANOTIFY_METADATA_VERSION); test_assert(event->mask == FAN_OPEN); test_assert(event->fd >= 0); test_assert(event->pid == getpid()); test_assert(0 == unlink("foo")); atomic_puts("EXIT-SUCCESS"); return 0; }
/** * Inits and starts fanotify notifications * @param opt : a filled options_t * structure that contains all options * by default, read into the file or selected in the command line. */ gint start_fanotify(options_t *opt) { gint fanotify_fd = -1; GSList *head = NULL; /** Leaving only FAN_CLOSE_WRITE for some tests */ /* Setup fanotify notifications (FAN) mask. All these defined in linux/fanotify.h. */ static uint64_t event_mask = (FAN_CLOSE_WRITE | /* Writtable file closed */ FAN_ONDIR | /* We want to be reported of events in the directory */ FAN_EVENT_ON_CHILD); /* We want to be reported of events in files of the directory */ unsigned int mark_flags = FAN_MARK_ADD | FAN_MARK_MOUNT; if (opt != NULL) { /* Create new fanotify device */ if ((fanotify_fd = fanotify_init(FAN_CLOEXEC, O_RDONLY | O_CLOEXEC | O_LARGEFILE)) < 0) { print_error(__FILE__, __LINE__, _("Couldn't setup new fanotify device: %s\n"), strerror(errno)); } else { head = opt->dirname_list; while (head != NULL) { if (fanotify_mark(fanotify_fd, mark_flags, event_mask, AT_FDCWD, head->data) < 0) { print_error(__FILE__, __LINE__, _("Couldn't add monitor in directory %s: %s\n"), head->data , strerror(errno)); } else { print_debug(_("Started monitoring directory %s\n"), head->data); } head = g_slist_next(head); } } } return fanotify_fd; }
static void setup(void) { tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); sprintf(fname, "fname_%d", getpid()); if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } }
int FileNotifyInit(const char *Path, int Flags) { char *Token=NULL, *ptr; int fd; fd=fanotify_init(Flags, O_RDWR); if (fd==-1) return(fd); ptr=GetToken(Path,":",&Token,0); while (ptr) { fanotify_mark(fd, FAN_MARK_ADD, FAN_CLOSE_WRITE, -1, NULL); ptr=GetToken(ptr,":",&Token,0); } DestroyString(Token); return(fd); }
int safe_fanotify_init(const char *file, const int lineno, unsigned int flags, unsigned int event_f_flags) { int rval; #ifdef HAVE_SYS_FANOTIFY_H rval = fanotify_init(flags, event_f_flags); if (rval == -1) { if (errno == ENOSYS) { tst_brk(TCONF, "fanotify is not configured in this kernel."); } tst_brk(TBROK | TERRNO, "%s:%d: fanotify_init() failed", file, lineno); } #else tst_brk(TCONF, "Header <sys/fanotify.h> is not present"); #endif /* HAVE_SYS_FANOTIFY_H */ return rval; }
void GonkDiskSpaceWatcher::DoStart() { NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(), "Not on the correct message loop"); mFd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC | O_LARGEFILE); if (mFd == -1) { if (errno == ENOSYS) { // Don't change these printf_stderr since we need these logs even // in opt builds. printf_stderr("Warning: No fanotify support in this device's kernel.\n"); #if ANDROID_VERSION >= 19 MOZ_CRASH("Fanotify support must be enabled in the kernel."); #endif } else { printf_stderr("Error calling fanotify_init()"); } return; } if (fanotify_mark(mFd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_CLOSE, 0, kWatchedPath) < 0) { NS_WARNING("Error calling fanotify_mark"); close(mFd); mFd = -1; return; } if (!MessageLoopForIO::current()->WatchFileDescriptor( mFd, /* persistent = */ true, MessageLoopForIO::WATCH_READ, &mReadWatcher, gHalDiskSpaceWatcher)) { NS_WARNING("Unable to watch fanotify fd."); close(mFd); mFd = -1; } }
static void setup(void) { int fd; tst_sig(FORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); sprintf(fname, "fname_%d", getpid()); fd = SAFE_OPEN(cleanup, fname, O_CREAT | O_RDWR, 0644); SAFE_WRITE(cleanup, 1, fd, fname, 1); SAFE_CLOSE(cleanup, fd); if ((fd_notify = fanotify_init(FAN_CLASS_CONTENT, O_RDONLY)) < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM | FAN_OPEN_PERM, AT_FDCWD, fname) < 0) { if (errno == EINVAL) { tst_brkm(TCONF | TERRNO, cleanup, "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not " "configured in kernel?"); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | " "FAN_OPEN_PERM, AT_FDCWD, %s) failed.", fd_notify, fname); } } }
void *fan_th(void *arg) { struct thrarg *tharg = (struct thrarg *) arg; sigset_t sigset; struct sigaction act; const struct optstruct *pt; short int scan; int sizelimit = 0, extinfo; STATBUF sb; uint64_t fan_mask = FAN_ACCESS | FAN_EVENT_ON_CHILD; int fan_fd; fd_set rfds; char buf[4096]; ssize_t bread; struct fanotify_event_metadata *fmd; char fname[1024]; int ret, len; char err[128]; /* ignore all signals except SIGUSR1 */ sigfillset(&sigset); sigdelset(&sigset, SIGUSR1); /* The behavior of a process is undefined after it ignores a * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ sigdelset(&sigset, SIGFPE); sigdelset(&sigset, SIGILL); sigdelset(&sigset, SIGSEGV); #ifdef SIGBUS sigdelset(&sigset, SIGBUS); #endif pthread_sigmask(SIG_SETMASK, &sigset, NULL); memset(&act, 0, sizeof(struct sigaction)); act.sa_handler = fan_exit; sigfillset(&(act.sa_mask)); sigaction(SIGUSR1, &act, NULL); sigaction(SIGSEGV, &act, NULL); fan_fd = fanotify_init(0, O_RDONLY); if(fan_fd < 0) { logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err))); if(errno == EPERM) logg("ScanOnAccess: clamd must be started by root\n"); return NULL; } if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { while(pt) { if(fanotify_mark(fan_fd, FAN_MARK_ADD, fan_mask, fan_fd, pt->strarg) != 0) { logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); return NULL; } else logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg); pt = (struct optstruct *) pt->nextarg; } } else { logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); return NULL; } if((pt = optget(tharg->opts, "OnAccessExcludePath"))->enabled) { while(pt) { if(fanotify_mark(fan_fd, FAN_MARK_REMOVE, fan_mask, fan_fd, pt->strarg) != 0) { logg("!ScanOnAccess: Can't exclude path %s\n", pt->strarg); return NULL; } else logg("ScanOnAccess: Excluded path %s\n", pt->strarg); pt = (struct optstruct *) pt->nextarg; } } sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg; if(sizelimit) logg("ScanOnAccess: Max file size limited to %d bytes\n", sizelimit); else logg("ScanOnAccess: File size limit disabled\n"); extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; FD_ZERO(&rfds); FD_SET(fan_fd, &rfds); do { ret = select(fan_fd + 1, &rfds, NULL, NULL, NULL); } while(ret == -1 && errno == EINTR); while((bread = read(fan_fd, buf, sizeof(buf))) > 0) { fmd = (struct fanotify_event_metadata *) buf; while(FAN_EVENT_OK(fmd, bread)) { scan = 1; if(fmd->fd >= 0) { sprintf(fname, "/proc/self/fd/%d", fmd->fd); len = readlink(fname, fname, sizeof(fname) - 1); if(len == -1) { close(fmd->fd); logg("!ScanOnAccess: Internal error (readlink() failed)\n"); return NULL; } fname[len] = 0; if(fan_checkowner(fmd->pid, tharg->opts)) { scan = 0; logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname); } if(sizelimit) { if(FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) { scan = 0; /* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */ } } if(fan_scanfile(fan_fd, fname, fmd, scan, extinfo, tharg) == -1) { close(fmd->fd); return NULL; } if(close(fmd->fd) == -1) { printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd); close(fmd->fd); return NULL; } } fmd = FAN_EVENT_NEXT(fmd, bread); } do { ret = select(fan_fd + 1, &rfds, NULL, NULL, NULL); } while(ret == -1 && errno == EINTR); } if(bread < 0) logg("!ScanOnAccess: Internal error (failed to read data)\n"); return NULL; }
int main() { fd = creat(fname, S_IREAD|S_IWRITE); close(fd); /* Note that the fanotify calls require root access or the * CAP_SYS_ADMIN capability. */ fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY); //staptest// fanotify_init (FAN_CLASS_NOTIF, O_RDONLY) = NNNN fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS|FAN_MODIFY|FAN_CLOSE|FAN_OPEN, AT_FDCWD, fname); //staptest// fanotify_mark (NNNN, FAN_MARK_ADD, FAN_ACCESS|FAN_MODIFY|FAN_CLOSE_WRITE|FAN_CLOSE_NOWRITE|FAN_OPEN, AT_FDCWD, "testfile") = NNNN // Now, modify the test file. fd = open(fname, O_WRONLY); //staptest// [[[[open (!!!!openat (AT_FDCWD, ]]]]"testfile", O_WRONLY) = NNNN write(fd, fname, strlen(fname) + 1); //staptest// write (NNNN, "testfile", NNNN) = NNNN close(fd); //staptest// close (NNNN) = 0 // Read list of events. read(fd_notify, event_buf, EVENT_BUF_LEN); //staptest// read (NNNN, XXXX, NNNN) = NNNN // A real program would process the list of events. We're not // going to bother. close(fd_notify); //staptest// close (NNNN) = NNNN /* Limit testing. */ fanotify_init(-1, O_RDONLY); //staptest// fanotify_init (XXXX|FAN_[^ ]+|XXXX, O_RDONLY) = -NNNN // Here's we're passing an invalid flags value (we hope) to make // sure this fails. fanotify_init(0x80000000, -1); //staptest// fanotify_init (FAN_CLASS_NOTIF|0x80000000, O_[^ ]+|XXXX) = -NNNN fanotify_mark(-1, FAN_MARK_REMOVE, FAN_ACCESS, AT_FDCWD, fname); //staptest// fanotify_mark (-1, FAN_MARK_REMOVE, FAN_ACCESS, AT_FDCWD, "testfile") = -NNNN fanotify_mark(-1, -1, FAN_MODIFY, AT_FDCWD, fname); //staptest// fanotify_mark (-1, FAN_[^ ]+|XXXX, FAN_MODIFY, AT_FDCWD, "testfile") = -NNNN fanotify_mark(-1, FAN_MARK_FLUSH, -1, AT_FDCWD, fname); //staptest// fanotify_mark (-1, FAN_MARK_FLUSH, FAN_[^ ]+|XXXX, AT_FDCWD, "testfile") = -NNNN fanotify_mark(-1, FAN_MARK_ADD|FAN_MARK_DONT_FOLLOW, FAN_CLOSE_WRITE, -1LL, fname); //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_DONT_FOLLOW, FAN_CLOSE_WRITE, -1, "testfile") = -NNNN fanotify_mark(-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, (char *)-1); #ifdef __s390__ //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, [7]?[f]+) = -NNNN #else //staptest// fanotify_mark (-1, FAN_MARK_ADD|FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE, AT_FDCWD, [f]+) = -NNNN #endif return 0; }
int main(int argc, char **argv) { int i; int fanotify_fd, ret; struct backend *be = NULL; struct stat stbuf; logfd = stdout; memset(frontend_prefix, 0x0, FILENAME_MAX); while ((i = getopt(argc, argv, "b:c:d:m:n:o:p:su:")) != -1) { switch (i) { case 'b': be = new_backend(optarg); if (!be) { err("Invalid backend '%s'\n", optarg); return EINVAL; } break; case 'd': if (stat(optarg, &stbuf) < 0 || !S_ISDIR(stbuf.st_mode)) { err("Frontend prefix %s is not a directory", optarg); return EINVAL; } strncpy(frontend_prefix, optarg, FILENAME_MAX); break; case 'c': return cli_command(CLI_CHECK, optarg); break; case 'm': ret = cli_command(CLI_CHECK, optarg); if (ret) return ret; ret = cli_command(CLI_MIGRATE, optarg); if (ret) return ret; /* Fallthrough */ case 'n': return cli_command(CLI_MONITOR, optarg); break; case 'o': if (!be) { err("No backend selected"); return EINVAL; } if (parse_backend_options(be, optarg) < 0) { err("Invalid backend option '%s'", optarg); return EINVAL; } break; case 'p': log_priority = strtoul(optarg, NULL, 10); if (log_priority > LOG_DEBUG) { err("Invalid logging priority %d (max %d)", log_priority, LOG_DEBUG); exit(1); } break; case 's': return cli_command(CLI_SHUTDOWN, NULL); break; case 'u': ret = cli_command(CLI_CHECK, optarg); if (ret && ret != ENOENT) return ret; ret = cli_command(CLI_SETUP, optarg); if (ret) return ret; return cli_command(CLI_MONITOR, optarg); break; default: fprintf(stderr, "usage: %s [-d <dir>]\n", argv[0]); return EINVAL; } } if (optind < argc) { fprintf(stderr, "usage: %s [-b file] [-p <dir>]\n", argv[0]); return EINVAL; } signal_set(SIGINT, sigend); signal_set(SIGTERM, sigend); fanotify_fd = fanotify_init(FAN_CLASS_PRE_CONTENT, O_RDWR); if (fanotify_fd < 0) { fprintf(stderr, "cannot start fanotify, error %d\n", errno); return errno; } daemon_thr = pthread_self(); watcher_thr = start_watcher(be, fanotify_fd); if (!watcher_thr) return errno; cli_thr = start_cli(be, fanotify_fd); if (!cli_thr) { stop_watcher(watcher_thr); return ENOMEM; } pthread_cond_wait(&exit_cond, &exit_mutex); stop_cli(cli_thr); stop_watcher(watcher_thr); return 0; }
void *onas_fan_th(void *arg) { struct thrarg *tharg = (struct thrarg *) arg; sigset_t sigset; struct sigaction act; const struct optstruct *pt; short int scan; int sizelimit = 0, extinfo; STATBUF sb; uint64_t fan_mask = FAN_EVENT_ON_CHILD | FAN_CLOSE; fd_set rfds; char buf[4096]; ssize_t bread; struct fanotify_event_metadata *fmd; char fname[1024]; int ret, len; char err[128]; pthread_attr_t ddd_attr; struct ddd_thrarg *ddd_tharg = NULL; ddd_pid = 0; /* ignore all signals except SIGUSR1 */ sigfillset(&sigset); sigdelset(&sigset, SIGUSR1); /* The behavior of a process is undefined after it ignores a * SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal */ sigdelset(&sigset, SIGFPE); sigdelset(&sigset, SIGILL); sigdelset(&sigset, SIGSEGV); #ifdef SIGBUS sigdelset(&sigset, SIGBUS); #endif pthread_sigmask(SIG_SETMASK, &sigset, NULL); memset(&act, 0, sizeof(struct sigaction)); act.sa_handler = onas_fan_exit; sigfillset(&(act.sa_mask)); sigaction(SIGUSR1, &act, NULL); sigaction(SIGSEGV, &act, NULL); /* Initialize fanotify */ onas_fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS, O_LARGEFILE | O_RDONLY); if(onas_fan_fd < 0) { logg("!ScanOnAccess: fanotify_init failed: %s\n", cli_strerror(errno, err, sizeof(err))); if(errno == EPERM) logg("ScanOnAccess: clamd must be started by root\n"); return NULL; } if (!tharg) { logg("!Unable to start on-access scanner. Bad thread args.\n"); return NULL; } if (optget(tharg->opts, "OnAccessPrevention")->enabled && !optget(tharg->opts, "OnAccessMountPath")->enabled) { logg("ScanOnAccess: preventing access attempts on malicious files.\n"); fan_mask |= FAN_ACCESS_PERM | FAN_OPEN_PERM; } else { logg("ScanOnAccess: notifying only for access attempts.\n"); fan_mask |= FAN_ACCESS | FAN_OPEN; } if ((pt = optget(tharg->opts, "OnAccessMountPath"))->enabled) { while(pt) { if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT, fan_mask, onas_fan_fd, pt->strarg) != 0) { logg("!ScanOnAccess: Can't include mountpoint '%s'\n", pt->strarg); return NULL; } else logg("ScanOnAccess: Protecting '%s' and rest of mount.\n", pt->strarg); pt = (struct optstruct *) pt->nextarg; } } else if (!optget(tharg->opts, "OnAccessDisableDDD")->enabled) { do { if(pthread_attr_init(&ddd_attr)) break; pthread_attr_setdetachstate(&ddd_attr, PTHREAD_CREATE_JOINABLE); if(!(ddd_tharg = (struct ddd_thrarg *) malloc(sizeof(struct ddd_thrarg)))) break; ddd_tharg->fan_fd = onas_fan_fd; ddd_tharg->fan_mask = fan_mask; ddd_tharg->opts = tharg->opts; ddd_tharg->engine = tharg->engine; ddd_tharg->options = tharg->options; if(!pthread_create(&ddd_pid, &ddd_attr, onas_ddd_th, ddd_tharg)) break; free(ddd_tharg); ddd_tharg=NULL; } while(0); if (!ddd_tharg) logg("!Unable to start dynamic directory determination.\n"); } else { if((pt = optget(tharg->opts, "OnAccessIncludePath"))->enabled) { while(pt) { if(fanotify_mark(onas_fan_fd, FAN_MARK_ADD, fan_mask, onas_fan_fd, pt->strarg) != 0) { logg("!ScanOnAccess: Can't include path '%s'\n", pt->strarg); return NULL; } else logg("ScanOnAccess: Protecting directory '%s'\n", pt->strarg); pt = (struct optstruct *) pt->nextarg; } } else { logg("!ScanOnAccess: Please specify at least one path with OnAccessIncludePath\n"); return NULL; } } /* Load other options. */ sizelimit = optget(tharg->opts, "OnAccessMaxFileSize")->numarg; if(sizelimit) logg("ScanOnAccess: Max file size limited to %d bytes\n", sizelimit); else logg("ScanOnAccess: File size limit disabled\n"); extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled; FD_ZERO(&rfds); FD_SET(onas_fan_fd, &rfds); do { if (reload) sleep(1); ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); } while((ret == -1 && errno == EINTR) || reload); time_t start = time(NULL) - 30; while(((bread = read(onas_fan_fd, buf, sizeof(buf))) > 0) || errno == EOVERFLOW) { if (errno == EOVERFLOW) { if (time(NULL) - start >= 30) { logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); logg("!ScanOnAccess: File too large for fanotify ... recovering and continuing scans...\n"); start = time(NULL); } errno = 0; continue; } fmd = (struct fanotify_event_metadata *) buf; while(FAN_EVENT_OK(fmd, bread)) { scan = 1; if(fmd->fd >= 0) { sprintf(fname, "/proc/self/fd/%d", fmd->fd); len = readlink(fname, fname, sizeof(fname) - 1); if(len == -1) { close(fmd->fd); logg("!ScanOnAccess: Internal error (readlink() failed)\n"); return NULL; } fname[len] = 0; if(onas_fan_checkowner(fmd->pid, tharg->opts)) { scan = 0; logg("*ScanOnAccess: %s skipped (excluded UID)\n", fname); } if(sizelimit) { if(FSTAT(fmd->fd, &sb) != 0 || sb.st_size > sizelimit) { scan = 0; /* logg("*ScanOnAccess: %s skipped (size > %d)\n", fname, sizelimit); */ } } if(onas_fan_scanfile(onas_fan_fd, fname, fmd, scan, extinfo, tharg) == -1) { close(fmd->fd); return NULL; } if(close(fmd->fd) == -1) { printf("!ScanOnAccess: Internal error (close(%d) failed)\n", fmd->fd); close(fmd->fd); return NULL; } } fmd = FAN_EVENT_NEXT(fmd, bread); } do { if (reload) sleep(1); ret = select(onas_fan_fd + 1, &rfds, NULL, NULL, NULL); } while((ret == -1 && errno == EINTR) || reload); } if(bread < 0) logg("!ScanOnAccess: Internal error (failed to read data) ... %s\n", strerror(errno)); return NULL; }
int main(int argc, char *argv[]) { char buf; int fd, poll_num; nfds_t nfds; struct pollfd fds[2]; /* Check mount point is supplied */ if (argc != 2) { fprintf(stderr, "Usage: %s MOUNT\n", argv[0]); exit(EXIT_FAILURE); } printf("Press enter key to terminate.\n"); /* Create the file descriptor for accessing the fanotify API */ fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, O_RDONLY | O_LARGEFILE); if (fd == -1) { perror("fanotify_init"); exit(EXIT_FAILURE); } /* Mark the mount for: - permission events before opening files - notification events after closing a write-enabled file descriptor */ if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD, argv[1]) == -1) { perror("fanotify_mark"); exit(EXIT_FAILURE); } /* Prepare for polling */ nfds = 2; /* Console input */ fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; /* Fanotify input */ fds[1].fd = fd; fds[1].events = POLLIN; /* This is the loop to wait for incoming events */ printf("Listening for events.\n"); while (1) { poll_num = poll(fds, nfds, -1); if (poll_num == -1) { if (errno == EINTR) /* Interrupted by a signal */ continue; /* Restart poll() */ perror("poll"); /* Unexpected error */ exit(EXIT_FAILURE); } if (poll_num > 0) { if (fds[0].revents & POLLIN) { /* Console input is available: empty stdin and quit */ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n') continue; break; } if (fds[1].revents & POLLIN) { /* Fanotify events are available */ handle_events(fd); } } } printf("Listening for events stopped.\n"); exit(EXIT_SUCCESS); }
int main(int argc, char *argv[]) { char buf; int fd, poll_num; nfds_t nfds; struct pollfd fds[2]; /* マウントポイントが指定されたか確認する */ if (argc != 2) { fprintf(stderr, "Usage: %s MOUNT\n", argv[0]); exit(EXIT_FAILURE); } printf("Press enter key to terminate.\n"); /* fanotify API にアクセスするためのファイルディスクリプターを作成する */ fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, O_RDONLY | O_LARGEFILE); if (fd == -1) { perror("fanotify_init"); exit(EXIT_FAILURE); } /* 指定されたマウントに対して以下を監視するようにマークを付ける: - ファイルのオープン前のアクセス許可イベント - 書き込み可能なファイルディスクリプターのクローズ後の 通知イベント */ if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD, argv[1]) == -1) { perror("fanotify_mark"); exit(EXIT_FAILURE); } /* ポーリングの準備(コンソール入力とfanotifyからの入力音2つ */ nfds = 2; /* コンソールの入力 */ fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; /* fanotify の入力 */ fds[1].fd = fd; fds[1].events = POLLIN; /* イベントの発生を待つループ */ printf("Listening for events.\n"); while (1) { poll_num = poll(fds, nfds, -1); if (poll_num == -1) { if (errno == EINTR) /* シグナルに割り込まれた場合 */ continue; /* poll() を再開する */ perror("poll"); /* 予期しないエラー */ exit(EXIT_FAILURE); } if (poll_num > 0) { // コンソール上から改行入力があればwhileループから抜けて処理を終了する。 if (fds[0].revents & POLLIN) { /* コンソールからの入力がある場合: 空の標準入力であれば終了 */ while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n') continue; break; } if (fds[1].revents & POLLIN) { /* fanotify イベントがある場合 */ handle_events(fd); } } } printf("Listening for events stopped.\n"); exit(EXIT_SUCCESS); }