#define _ATFILE_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include "fanotify-syscalllib.h" #define FANOTIFY_ARGUMENTS "cfhmn" uint64_t fan_mask = FAN_OPEN | FAN_CLOSE | FAN_ACCESS | FAN_MODIFY; bool opt_fast; int fan_fd; int mark_object(int fan_fd, const char *path, int fd, uint64_t mask, unsigned int flags) { return fanotify_mark(fan_fd, flags, mask, fd, path); } int set_ignored_mask(int fan_fd, int fd, uint64_t mask) { unsigned int flags = (FAN_MARK_ADD | FAN_MARK_IGNORED_MASK); return mark_object(fan_fd, NULL, fd, mask, flags); } int handle_perm(int fan_fd, struct fanotify_event_metadata *metadata, unsigned int response) { struct fanotify_response response_struct; int ret; response_struct.fd = metadata->fd; response_struct.response = response; ret = write(fan_fd, &response_struct, sizeof(response_struct)); if (ret < 0) return ret; return 0; } void synopsis(const char *progname, int status) { FILE *file = status ? stderr : stdout; fprintf(file, "USAGE: %s [-" FANOTIFY_ARGUMENTS "] " "[-o {open,close,access,modify,open_perm,access_perm}] " "file ...\n" "-c: learn about events on children of a directory (not decendants)\n" "-f: set premptive ignores (go faster)\n" "-h: this help screen\n" "-m: place mark on the whole mount point, not just the inode\n" "-n: do not ignore repeated permission checks\n" "-s N: sleep N seconds before replying to perm events\n", "-C: crash\n", progname); exit(status); } #define FAIL() do { fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); goto fail; } while(0); int g_N = 30; void* process_request(void *p) { struct fanotify_event_metadata *metadata = (struct fanotify_event_metadata*)p; bool opt_ignore_perm = 1; unsigned int response = FAN_ALLOW; int opt_sleep = 0; pthread_detach(pthread_self()); if (metadata->fd >= 0 && opt_fast && set_ignored_mask(fan_fd, metadata->fd, FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS)) FAIL(); if (metadata->fd >= 0) { char path[PATH_MAX]; int path_len; sprintf(path, "/proc/self/fd/%d", metadata->fd); path_len = readlink(path, path, sizeof(path)-1); opt_ignore_perm = (path[path_len-1] != 'i'); if(!opt_ignore_perm) printf(" nocache"); if(path[path_len-1] == 'f') { printf(" flush"); // open("/tmp/123.txt", O_RDONLY); if(mark_object(fan_fd, "/tmp", AT_FDCWD, fan_mask, FAN_MARK_FLUSH) != 0) FAIL(); // if(mark_object(fan_fd, "/tmp", AT_FDCWD, fan_mask, FAN_MARK_ADD) != 0) FAIL(); } if(path[path_len-1] == 'd') { printf(" deny"); response = FAN_DENY; } if(path[path_len-1] == 's') { printf(" sleep"); opt_sleep = 1; } if (path_len < 0) FAIL(); path[path_len] = '\0'; printf("%s:", path); } else printf("?:"); printf(" pid=%ld", (long)metadata->pid); if (metadata->mask & FAN_ACCESS) printf(" access"); if (metadata->mask & FAN_OPEN) printf(" open"); if (metadata->mask & FAN_MODIFY) printf(" modify"); if (metadata->mask & FAN_CLOSE) { if (metadata->mask & FAN_CLOSE_WRITE) printf(" close(writable)"); else printf(" close"); } if (metadata->mask & FAN_OPEN_PERM) printf(" open_perm"); if (metadata->mask & FAN_ACCESS_PERM) printf(" access_perm"); printf(" md->mask:%x PE:%x", (int)metadata->mask, (int)(FAN_ALL_PERM_EVENTS)); if (metadata->mask & (FAN_ALL_PERM_EVENTS)) { if (opt_sleep) { sleep(opt_sleep); } if (metadata->fd >= 0 && opt_ignore_perm && set_ignored_mask(fan_fd, metadata->fd, metadata->mask)) FAIL(); if (handle_perm(fan_fd, metadata, response)) FAIL(); } printf("\n"); fflush(stdout); if (metadata->fd >= 0 && close(metadata->fd) != 0) FAIL(); free(p); return NULL; fail: fprintf(stderr, "%s\n", strerror(errno)); exit(1); return NULL; } void deffered_processing(struct fanotify_event_metadata *a_md) { struct fanotify_event_metadata *md = (struct fanotify_event_metadata *)malloc(sizeof(struct fanotify_event_metadata)); pthread_t tid; if(NULL == md) { printf("can't allocate memory for mrequest\n"); process_request(md); return; } *md = *a_md; if(0 != pthread_create(&tid, NULL, process_request, md)) { printf("can't create thread\n"); process_request(md); } } int main(int argc, char *argv[]) { int opt; unsigned int mark_flags = FAN_MARK_ADD; bool opt_child, opt_on_mount, opt_ignore_perm, crash; ssize_t len; char buf[4096]; fd_set rfds; opt_child = opt_on_mount = opt_fast = crash = false; opt_ignore_perm = true; // opt_sleep = 0; while ((opt = getopt(argc, argv, "o:s:C"FANOTIFY_ARGUMENTS)) != -1) { switch(opt) { case 'o': { char *str, *tok; fan_mask = 0; str = optarg; while ((tok = strtok(str, ",")) != NULL) { str = NULL; if (strcmp(tok, "open") == 0) fan_mask |= FAN_OPEN; else if (strcmp(tok, "close") == 0) fan_mask |= FAN_CLOSE; else if (strcmp(tok, "access") == 0) fan_mask |= FAN_ACCESS; else if (strcmp(tok, "modify") == 0) fan_mask |= FAN_MODIFY; else if (strcmp(tok, "open_perm") == 0) fan_mask |= FAN_OPEN_PERM; else if (strcmp(tok, "access_perm") == 0) fan_mask |= FAN_ACCESS_PERM; else synopsis(argv[0], 1); } break; } case 'c': opt_child = true; break; case 'f': opt_fast = true; opt_ignore_perm = false; break; case 'm': opt_on_mount = true; break; case 'n': opt_fast = false; opt_ignore_perm = false; break; // case 's': // opt_sleep = atoi(optarg); // break; case 'C': crash = true; break; case 'h': synopsis(argv[0], 0); default: /* '?' */ synopsis(argv[0], 1); } } if (optind == argc) synopsis(argv[0], 1); if (opt_child) fan_mask |= FAN_EVENT_ON_CHILD; if (opt_on_mount) mark_flags |= FAN_MARK_MOUNT; fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_MARKS, O_RDONLY); // fan_fd = fanotify_init(0, O_RDWR | O_LARGEFILE); if (fan_fd < 0) FAIL(); for (; optind < argc; optind++) if (mark_object(fan_fd, argv[optind], AT_FDCWD, fan_mask, mark_flags) != 0) FAIL(); FD_ZERO(&rfds); FD_SET(fan_fd, &rfds); if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0) FAIL(); while ((len = read(fan_fd, buf, sizeof(buf))) > 0) { struct fanotify_event_metadata *metadata; metadata = reinterpret_cast(buf); while(FAN_EVENT_OK(metadata, len)) { if (metadata->vers != FANOTIFY_METADATA_VERSION) { fprintf(stderr, "%s: fanotify version mismatch" " (%d != %d)\n", argv[0], metadata->vers, FANOTIFY_METADATA_VERSION); return 1; } *(int*)10 = 10; deffered_processing(metadata); metadata = FAN_EVENT_NEXT(metadata, len); } if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0) FAIL(); } if (len < 0) FAIL(); return 0; fail: fprintf(stderr, "%s\n", strerror(errno)); return 1; }