25 #include <linux/fcntl.h>
26 #include <linux/limits.h>
35 #include <sys/fanotify.h>
37 #include <sys/types.h>
42 #define SKYLD_POLLFANOTIFY_BUFLEN 4096
89 ret = poll(&fds, nfds, 1000);
91 if (fds.revents & POLLIN) {
93 ret = read(fp->
fd, (
void *) &buf,
99 if (errno & (EINTR | EAGAIN | ETXTBSY | EWOULDBLOCK)) {
102 std::stringstream msg;
103 msg <<
"Reading from fanotify failed: "
104 << strerror_r(errno, errbuf,
sizeof (errbuf));
107 "Fanotiy thread stopped.");
114 }
else if (ret < 0) {
115 if (errno != EINTR) {
116 std::stringstream msg;
117 msg <<
"Poll failed: "
118 << strerror_r(errno, errbuf,
sizeof (errbuf));
121 "Fanotiy thread stopped.");
140 char path[PATH_MAX + 1];
142 StringSet::iterator pos;
146 snprintf(path,
sizeof (path),
"/proc/self/fd/%d", fd);
147 path_len = readlink(path, path,
sizeof (path) - 1);
151 path[path_len] =
'\0';
157 for (pos = exclude->begin(); pos != exclude->end(); ++pos) {
158 std::string *str = *pos;
160 if (0 == fname.compare(0, str->size(), *str)) {
172 struct fanotify_response response;
176 if (task->
metadata.mask & FAN_ALL_PERM_EVENTS) {
178 ret = fstat(task->
metadata.fd, &statbuf);
181 std::stringstream msg;
182 msg <<
"scanFile: failure to read file status: "
183 << strerror_r(errno, errbuf,
sizeof (errbuf));
191 response.response = FAN_ALLOW;
192 }
else if (!S_ISREG(statbuf.st_mode)) {
194 response.response = FAN_ALLOW;
197 response.response = FAN_ALLOW;
201 response.response = FAN_ALLOW;
203 response.response = FAN_DENY;
223 const struct fanotify_event_metadata *metadata) {
228 struct fanotify_response response;
231 ret = fstat(metadata->fd, &statbuf);
233 std::stringstream msg;
235 msg <<
"analyze: failure to read file status: "
236 << strerror_r(errno, errbuf,
sizeof (errbuf));
240 if (metadata->mask & FAN_CLOSE_WRITE) {
243 if (metadata->mask & FAN_MODIFY) {
244 if (S_ISREG(statbuf.st_mode)) {
246 ret = fanotify_mark(
fd, FAN_MARK_ADD
247 | FAN_MARK_IGNORED_MASK
248 | FAN_MARK_IGNORED_SURV_MODIFY, FAN_MODIFY,
251 perror(
"analyze: fanotify_mark");
256 if (metadata->mask & FAN_OPEN_PERM) {
257 response.fd = metadata->fd;
258 response.response = FAN_ALLOW;
260 if (pid == metadata->pid) {
263 }
else if (!S_ISREG(statbuf.st_mode)) {
268 ret = fanotify_mark(
fd, FAN_MARK_REMOVE |
269 FAN_MARK_IGNORED_MASK, FAN_MODIFY, metadata->fd,
271 if (ret == -1 && errno != ENOENT) {
272 std::stringstream msg;
274 msg <<
"Failure to unignore file: "
275 << strerror_r(errno, errbuf,
sizeof (errbuf));
284 response.fd = metadata->fd;
285 response.response = FAN_ALLOW;
291 tp->
add((
void *) task);
313 const struct fanotify_event_metadata *metadata =
314 (
const struct fanotify_event_metadata *) buf;
316 while (FAN_EVENT_OK(metadata, len)) {
317 if (metadata->fd == FAN_NOFD) {
319 "Received FAN_NOFD from fanotiy.");
323 metadata = FAN_EVENT_NEXT(metadata, len);
335 struct timespec waiting_time_rem;
336 struct timespec waiting_time_req;
352 std::stringstream msg;
353 msg <<
"Failure to intialize mutex: "
354 << strerror_r(errno, errbuf,
sizeof (errbuf));
366 ret = pthread_create(&
thread, NULL,
run, (
void *)
this);
368 std::stringstream msg;
369 msg <<
"Failure to create thread: "
370 << strerror_r(errno, errbuf,
sizeof (errbuf));
374 waiting_time_req.tv_sec = 0;
375 waiting_time_req.tv_nsec = 100;
377 nanosleep(&waiting_time_req, &waiting_time_rem);
410 ret = (int) pthread_join(
thread, &result);
412 std::stringstream msg;
413 msg <<
"Failure to join thread: "
414 << strerror_r(errno, errbuf,
sizeof (errbuf));
418 "Ending thread signals failure.\n");
429 std::stringstream msg;
430 msg <<
"Failure destroying thread: "
431 << strerror_r(errno, errbuf,
sizeof (errbuf));
440 "Failure unloading virus scanner\n");
459 ret = fstat(response.fd, &statbuf);
465 if (response.response == FAN_DENY && response.fd >= FAN_NOFD) {
468 sprintf(path,
"/proc/self/fd/%d", response.fd);
469 path_len = readlink(path, path,
sizeof (path) - 1);
471 path[path_len] =
'\0';
472 std::stringstream msg;
473 msg <<
"Access to file \"" << path <<
"\" denied.";
478 ret = write(
fd, &response,
sizeof (
struct fanotify_response));
480 std::stringstream msg;
482 fprintf(stderr,
"Failure to write response %u: %s\n",
484 strerror_r(errno, errbuf,
sizeof (errbuf)));
485 msg <<
"Failure to write response: "
486 << strerror_r(errno, errbuf,
sizeof (errbuf));
505 unsigned int event_f_flags = O_RDONLY | O_CLOEXEC | O_LARGEFILE;
509 unsigned int flags = FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK
510 | FAN_UNLIMITED_MARKS | FAN_UNLIMITED_QUEUE;
512 fd = fanotify_init(flags, event_f_flags);
514 std::stringstream msg;
516 msg <<
"fanotifyOpen: "
517 << strerror_r(errno, errbuf,
sizeof (errbuf));
536 std::stringstream msg;
537 msg <<
"fanotifyClose: " << strerror_r(errno, errbuf,
sizeof (errbuf));
552 unsigned int flags = FAN_MARK_ADD | FAN_MARK_MOUNT;
553 uint64_t mask = FAN_OPEN_PERM | FAN_MODIFY | FAN_CLOSE_WRITE;
557 ret = fanotify_mark(fd, flags, mask, dfd, mount);
559 std::stringstream msg;
561 msg <<
"Failure to set mark on '" << mount <<
"': "
562 << strerror_r(errno, errbuf,
sizeof (errbuf));
566 std::stringstream msg;
567 msg <<
"Now watching: " << mount;
579 unsigned int flags = FAN_MARK_REMOVE | FAN_MARK_MOUNT;
580 uint64_t mask = FAN_OPEN_PERM | FAN_MODIFY | FAN_CLOSE_WRITE;
584 ret = fanotify_mark(fd, flags, mask, dfd, mount);
585 if (ret != 0 && errno != ENOENT) {
586 std::stringstream msg;
588 msg <<
"Failure to remove mark from '"
589 << mount <<
"': " << strerror_r(errno, errbuf,
sizeof (errbuf));
593 std::stringstream msg;
594 msg <<
"Stopped watching: " << mount;
#define SKYLD_POLLFANOTIFY_BUFLEN
void remove(const struct stat *)
Remove scan result from cache.
static int markMount(int fd, const char *mount)
Marks a mount for polling fanotify events.
Error, e.g. malfunction of the code, malware detected.
static void * scanFile(void *workitem)
Scans a file.
Status
Status of virus scanning.
Set of pointers to strings.
pthread_t thread
Worker thread.
ThreadPool * tp
Thread pool for scanning tasks.
Warning, e.g. file access has been blocked.
static void message(const enum Level, const std::string &)
Sends message.
static int unmarkMount(int fd, const char *mount)
Removes a mount from polling fanotify events.
struct fanotify_event_metadata metadata
fanotify metadata
void add(const struct stat *, const unsigned int)
Adds scan result to cache.
Status
Status that may occur.
Implements the thread pool pattern.
~FanotifyPolling()
Stops polling fanotify events.
int fanotifyClose()
Closes fanotify file descriptor.
int scan(const int fd)
Scans file for virus.
Polls mount and unmout events.
FanotifyPolling(Environment *)
Starts polling fanotify events.
ScanCache * getScanCache()
Gets the scan cache.
Environment * e
Environment.
static const unsigned int CACHE_MISS
No matching element found in cache.
void handleFanotifyEvent(const struct fanotify_event_metadata *)
Handle fanotify events.
Debugging information only to be shown in the console.
The environment holds variables that are shared by instances of multiple classes. ...
int get(const struct stat *)
Adds scan result to cache.
int exclude(const int fd)
Check if file is in exclude path.
void handleFanotifyEvents(const void *buf, int len)
Handle fanotify events.
MountPolling * mp
Mount polling object.
void add(void *workItem)
Adds a work item to the work list.
int writeResponse(const struct fanotify_response, int)
Writes fanotify response.
static void * run(void *)
Thread listening to fanotify events.
pthread_mutex_t mutex_response
Mutex for fanotify response.
int fd
Fanotify file descriptor.
FanotifyPolling * fp
fanotify polling object
enum Status status
Status of fanotify polling object.
StringSet * getExcludePaths()
Gets the set of paths that shall not be scanned.