Example #1
0
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);
		}
	}
}
Example #2
0
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);
	}
}
Example #3
0
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");
		}
	}
}
Example #4
0
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");
		}
	}
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #8
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;
}
Example #9
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;
}
Example #10
0
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");
		}
	}
}
Example #11
0
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);
}
Example #12
0
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;
  }
}
Example #14
0
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);
		}
	}

}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
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;
}
Example #18
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;
}
Example #19
0
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);
}
Example #20
0
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);
}