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.