Skip to content

Commit 07ed1d3

Browse files
committed
improvements and alternative version for fileaccess monitoring
1 parent 3a0c812 commit 07ed1d3

File tree

2 files changed

+216
-6
lines changed

2 files changed

+216
-6
lines changed

UTILS/FileIOGraph/monitor_fileaccess.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ std::string getcmd(pid_t pid)
6464
fclose(file);
6565
for (int byte = 0; byte < bytesRead; ++byte) {
6666
if (buffer[byte] == '\0') {
67-
buffer[byte] == '@';
67+
buffer[byte] = '@';
6868
}
6969
}
7070
return std::string(buffer);
@@ -98,7 +98,7 @@ int main(int argc, char** argv)
9898
{
9999
int fan;
100100
char buf[4096];
101-
char fdpath[32];
101+
char fdpath[64];
102102
char path[PATH_MAX + 1];
103103
ssize_t buflen, linklen;
104104
struct fanotify_event_metadata* metadata;
@@ -114,11 +114,11 @@ int main(int argc, char** argv)
114114
auto MAX_MOTHER_PID_ENV = getenv("MAXMOTHERPID");
115115
int max_mother_pid = 1; // everything
116116
if (MAX_MOTHER_PID_ENV != nullptr) {
117-
std::cerr << "found env variablen";
117+
std::cerr << "found env variable MAX_MOTHER_PID_ENV";
118118
max_mother_pid = std::atoi(MAX_MOTHER_PID_ENV);
119119
std::cerr << "Setting topmost mother process to " << max_mother_pid << "\n";
120120
} else {
121-
std::cerr << "No environment given\n";
121+
std::cerr << "No environment given. Monitoring globally.\n";
122122
}
123123

124124
auto thispid = getpid();
@@ -174,10 +174,10 @@ int main(int argc, char** argv)
174174
}
175175

176176
if (metadata->mask & FAN_CLOSE_WRITE) {
177-
printf("%s,write,%s\n", path, parentspid->c_str());
177+
printf("\"%s\",write,%s\n", path, parentspid->c_str());
178178
}
179179
if (metadata->mask & FAN_CLOSE_NOWRITE) {
180-
printf("%s,read,%s\n", path, parentspid->c_str());
180+
printf("\"%s\",read,%s\n", path, parentspid->c_str());
181181
}
182182
}
183183

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#include <fcntl.h>
2+
#include <limits.h>
3+
#include <poll.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <unistd.h>
7+
#include <sys/fanotify.h>
8+
#include <sys/stat.h>
9+
#include <sys/types.h>
10+
#include <string.h>
11+
#include <unordered_map>
12+
#include <sstream>
13+
#include <iostream>
14+
15+
#define CHK(expr, errcode) \
16+
if ((expr) == errcode) \
17+
{ \
18+
perror(#expr); \
19+
exit(EXIT_FAILURE); \
20+
}
21+
22+
#define MAXBUF (BUFSIZ * 2)
23+
24+
int getppid_safe(int pid)
25+
{
26+
int ppid = 0;
27+
char buf[MAXBUF];
28+
char procname[64]; // big enough for /proc/<pid>/status
29+
FILE *fp;
30+
31+
snprintf(procname, sizeof(procname), "/proc/%d/status", pid);
32+
fp = fopen(procname, "r");
33+
if (fp != NULL)
34+
{
35+
size_t ret = fread(buf, sizeof(char), MAXBUF - 1, fp);
36+
if (ret > 0)
37+
buf[ret] = '\0';
38+
fclose(fp);
39+
}
40+
char *ppid_loc = strstr(buf, "\nPPid:");
41+
if (ppid_loc)
42+
{
43+
if (sscanf(ppid_loc, "\nPPid:%d", &ppid) != 1)
44+
return 0;
45+
return ppid;
46+
}
47+
return 0;
48+
}
49+
50+
std::string getcmd(pid_t pid)
51+
{
52+
if (pid == 0 || pid == 1)
53+
return std::string("");
54+
55+
char path[64];
56+
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
57+
58+
FILE *file = fopen(path, "r");
59+
if (file)
60+
{
61+
char buffer[1024]; // max 1k command line
62+
size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);
63+
fclose(file);
64+
for (size_t i = 0; i < bytesRead; ++i)
65+
{
66+
if (buffer[i] == '\0')
67+
buffer[i] = '@';
68+
}
69+
return std::string(buffer, bytesRead);
70+
}
71+
return std::string("");
72+
}
73+
74+
std::unordered_map<int, bool> good_pid_cache;
75+
std::unordered_map<int, std::string> pid_to_parents;
76+
std::unordered_map<int, std::string> pid_to_command;
77+
78+
bool is_good_pid(int pid, int maxparent)
79+
{
80+
auto iter = good_pid_cache.find(pid);
81+
if (iter != good_pid_cache.end())
82+
return iter->second;
83+
84+
if (pid == maxparent)
85+
return good_pid_cache[pid] = true;
86+
if (pid == 0)
87+
return good_pid_cache[pid] = false;
88+
89+
return good_pid_cache[pid] = is_good_pid(getppid_safe(pid), maxparent);
90+
}
91+
92+
std::string build_parent_chain(int pid, int maxparent)
93+
{
94+
auto iter = pid_to_parents.find(pid);
95+
if (iter != pid_to_parents.end())
96+
return iter->second;
97+
98+
std::stringstream str;
99+
int current = pid;
100+
str << current;
101+
while (current != maxparent && current != 0)
102+
{
103+
if (pid_to_command.find(current) == pid_to_command.end())
104+
{
105+
std::string cmd = getcmd(current);
106+
pid_to_command[current] = cmd;
107+
fprintf(stdout, "pid-to-command:%i:%s\n", current, cmd.c_str());
108+
}
109+
int next = getppid_safe(current);
110+
current = next;
111+
str << ";" << current;
112+
}
113+
pid_to_parents[pid] = str.str();
114+
return str.str();
115+
}
116+
117+
int main(int argc, char **argv)
118+
{
119+
int fan;
120+
char buf[8192];
121+
char fdpath[64];
122+
char path[PATH_MAX + 1];
123+
ssize_t buflen, linklen;
124+
struct fanotify_event_metadata *metadata;
125+
126+
// init fanotify
127+
CHK(fan = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY), -1);
128+
CHK(fanotify_mark(fan, FAN_MARK_ADD | FAN_MARK_MOUNT,
129+
FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE | FAN_EVENT_ON_CHILD,
130+
AT_FDCWD, "/"),
131+
-1);
132+
133+
// read env for filtering
134+
auto MAX_MOTHER_PID_ENV = getenv("MAXMOTHERPID");
135+
int max_mother_pid = 1; // default: allow everything
136+
if (MAX_MOTHER_PID_ENV != nullptr)
137+
{
138+
max_mother_pid = std::atoi(MAX_MOTHER_PID_ENV);
139+
std::cerr << "Setting topmost mother process to " << max_mother_pid << "\n";
140+
}
141+
else
142+
{
143+
std::cerr << "No MAXMOTHERPID environment given\n";
144+
}
145+
146+
auto thispid = getpid();
147+
148+
struct pollfd fds[1];
149+
fds[0].fd = fan;
150+
fds[0].events = POLLIN;
151+
152+
for (;;)
153+
{
154+
int pollres = poll(fds, 1, -1); // wait indefinitely
155+
if (pollres == -1)
156+
{
157+
perror("poll");
158+
continue;
159+
}
160+
161+
if (fds[0].revents & POLLIN)
162+
{
163+
buflen = read(fan, buf, sizeof(buf));
164+
if (buflen == -1)
165+
{
166+
perror("read");
167+
continue;
168+
}
169+
metadata = (struct fanotify_event_metadata *)&buf;
170+
while (FAN_EVENT_OK(metadata, buflen))
171+
{
172+
if (metadata->mask & FAN_Q_OVERFLOW)
173+
{
174+
fprintf(stderr, "Queue overflow!\n");
175+
continue;
176+
}
177+
snprintf(fdpath, sizeof(fdpath), "/proc/self/fd/%d", metadata->fd);
178+
linklen = readlink(fdpath, path, sizeof(path) - 1);
179+
if (linklen >= 0)
180+
{
181+
path[linklen] = '\0';
182+
int pid = metadata->pid;
183+
184+
bool record = true;
185+
record = record && pid != thispid;
186+
record = record && (metadata->mask & (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE));
187+
record = record && is_good_pid(pid, max_mother_pid);
188+
189+
if (record)
190+
{
191+
std::string parent_chain = build_parent_chain(pid, max_mother_pid);
192+
193+
if (metadata->mask & FAN_CLOSE_WRITE)
194+
{
195+
printf("\"%s\",write,%s\n", path, parent_chain.c_str());
196+
fflush(stdout);
197+
}
198+
if (metadata->mask & FAN_CLOSE_NOWRITE)
199+
{
200+
printf("\"%s\",read,%s\n", path, parent_chain.c_str());
201+
fflush(stdout);
202+
}
203+
}
204+
}
205+
close(metadata->fd);
206+
metadata = FAN_EVENT_NEXT(metadata, buflen);
207+
}
208+
}
209+
}
210+
}

0 commit comments

Comments
 (0)