1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2013 SUSE. All Rights Reserved.
4 *
5 * Started by Jan Kara <jack@suse.cz>
6 */
7
8 /*\
9 * [Description]
10 * Check that fanotify work for a file.
11 */
12
13 #define _GNU_SOURCE
14 #include "config.h"
15
16 #include <stdio.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <sys/syscall.h>
22 #include "tst_test.h"
23
24 #ifdef HAVE_SYS_FANOTIFY_H
25 #include "fanotify.h"
26
27 #define EVENT_MAX 1024
28 /* size of the event structure, not counting name */
29 #define EVENT_SIZE (sizeof(struct fanotify_event_metadata))
30 /* reasonable guess as to size of 1024 events */
31 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
32
33 #define BUF_SIZE 256
34 #define TST_TOTAL 12
35
36 #define MOUNT_PATH "fs_mnt"
37
38 static struct tcase {
39 const char *tname;
40 struct fanotify_mark_type mark;
41 unsigned int init_flags;
42 } tcases[] = {
43 {
44 "inode mark events",
45 INIT_FANOTIFY_MARK_TYPE(INODE),
46 FAN_CLASS_NOTIF
47 },
48 {
49 "mount mark events",
50 INIT_FANOTIFY_MARK_TYPE(MOUNT),
51 FAN_CLASS_NOTIF
52 },
53 {
54 "filesystem mark events",
55 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
56 FAN_CLASS_NOTIF
57 },
58 {
59 "inode mark events (FAN_REPORT_FID)",
60 INIT_FANOTIFY_MARK_TYPE(INODE),
61 FAN_CLASS_NOTIF|FAN_REPORT_FID
62 },
63 {
64 "mount mark events (FAN_REPORT_FID)",
65 INIT_FANOTIFY_MARK_TYPE(MOUNT),
66 FAN_CLASS_NOTIF|FAN_REPORT_FID
67 },
68 {
69 "filesystem mark events (FAN_REPORT_FID)",
70 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
71 FAN_CLASS_NOTIF|FAN_REPORT_FID
72 },
73 };
74
75 static char fname[BUF_SIZE];
76 static char buf[BUF_SIZE];
77 static int fd_notify;
78 static int fan_report_fid_unsupported;
79 static int mount_mark_fid_unsupported;
80 static int filesystem_mark_unsupported;
81
82 static unsigned long long event_set[EVENT_MAX];
83
84 static char event_buf[EVENT_BUF_LEN];
85
test_fanotify(unsigned int n)86 static void test_fanotify(unsigned int n)
87 {
88 struct tcase *tc = &tcases[n];
89 struct fanotify_mark_type *mark = &tc->mark;
90 int fd, ret, len, i = 0, test_num = 0;
91 int tst_count = 0;
92 int report_fid = (tc->init_flags & FAN_REPORT_FID);
93
94 tst_res(TINFO, "Test #%d: %s", n, tc->tname);
95
96 if (fan_report_fid_unsupported && report_fid) {
97 FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_FID, fan_report_fid_unsupported);
98 return;
99 }
100
101 if (filesystem_mark_unsupported && mark->flag == FAN_MARK_FILESYSTEM) {
102 FANOTIFY_MARK_FLAGS_ERR_MSG(mark, filesystem_mark_unsupported);
103 return;
104 }
105
106 if (mount_mark_fid_unsupported && report_fid && mark->flag != FAN_MARK_INODE) {
107 FANOTIFY_MARK_FLAGS_ERR_MSG(mark, mount_mark_fid_unsupported);
108 return;
109 }
110
111 fd_notify = SAFE_FANOTIFY_INIT(tc->init_flags, O_RDONLY);
112
113 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag,
114 FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname);
115
116 /*
117 * generate sequence of events
118 */
119 fd = SAFE_OPEN(fname, O_RDONLY);
120 event_set[tst_count] = FAN_OPEN;
121 tst_count++;
122
123 SAFE_READ(0, fd, buf, BUF_SIZE);
124 event_set[tst_count] = FAN_ACCESS;
125 tst_count++;
126
127 SAFE_CLOSE(fd);
128 event_set[tst_count] = FAN_CLOSE_NOWRITE;
129 tst_count++;
130
131 /*
132 * Get list of events so far. We get events here to avoid
133 * merging of following events with the previous ones.
134 */
135 ret = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
136 len = ret;
137
138 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
139 event_set[tst_count] = FAN_OPEN;
140 tst_count++;
141
142 SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, strlen(fname));
143 event_set[tst_count] = FAN_MODIFY;
144 tst_count++;
145
146 SAFE_CLOSE(fd);
147 event_set[tst_count] = FAN_CLOSE_WRITE;
148 tst_count++;
149
150 /*
151 * get another list of events
152 */
153 ret = SAFE_READ(0, fd_notify, event_buf + len,
154 EVENT_BUF_LEN - len);
155 len += ret;
156
157 /*
158 * Ignore mask testing
159 */
160
161 /* Ignore access events */
162 SAFE_FANOTIFY_MARK(fd_notify,
163 FAN_MARK_ADD | mark->flag | FAN_MARK_IGNORED_MASK,
164 FAN_ACCESS, AT_FDCWD, fname);
165
166 fd = SAFE_OPEN(fname, O_RDWR);
167 event_set[tst_count] = FAN_OPEN;
168 tst_count++;
169
170 /* This event should be ignored */
171 SAFE_READ(0, fd, buf, BUF_SIZE);
172
173 /*
174 * get another list of events to verify the last one got ignored
175 */
176 ret = SAFE_READ(0, fd_notify, event_buf + len,
177 EVENT_BUF_LEN - len);
178 len += ret;
179
180 SAFE_LSEEK(fd, 0, SEEK_SET);
181 /* Generate modify event to clear ignore mask */
182 SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, 1);
183 event_set[tst_count] = FAN_MODIFY;
184 tst_count++;
185
186 /*
187 * This event shouldn't be ignored because previous modification
188 * should have removed the ignore mask
189 */
190 SAFE_READ(0, fd, buf, BUF_SIZE);
191 event_set[tst_count] = FAN_ACCESS;
192 tst_count++;
193
194 SAFE_CLOSE(fd);
195 event_set[tst_count] = FAN_CLOSE_WRITE;
196 tst_count++;
197
198 /* Read events to verify previous access was properly generated */
199 ret = SAFE_READ(0, fd_notify, event_buf + len,
200 EVENT_BUF_LEN - len);
201 len += ret;
202
203 /*
204 * Now ignore open & close events regardless of file
205 * modifications
206 */
207 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag |
208 FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY,
209 FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname);
210
211 /* This event should be ignored */
212 fd = SAFE_OPEN(fname, O_RDWR);
213
214 SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, 1);
215 event_set[tst_count] = FAN_MODIFY;
216 tst_count++;
217
218 /* This event should be still ignored */
219 SAFE_CLOSE(fd);
220
221 /* This event should still be ignored */
222 fd = SAFE_OPEN(fname, O_RDWR);
223
224 /* Read events to verify open & close were ignored */
225 ret = SAFE_READ(0, fd_notify, event_buf + len,
226 EVENT_BUF_LEN - len);
227 len += ret;
228
229 /* Now remove open and close from ignored mask */
230 SAFE_FANOTIFY_MARK(fd_notify,
231 FAN_MARK_REMOVE | mark->flag | FAN_MARK_IGNORED_MASK,
232 FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname);
233
234 SAFE_CLOSE(fd);
235 event_set[tst_count] = FAN_CLOSE_WRITE;
236 tst_count++;
237
238 /* Read events to verify close was generated */
239 ret = SAFE_READ(0, fd_notify, event_buf + len,
240 EVENT_BUF_LEN - len);
241 len += ret;
242
243 if (TST_TOTAL != tst_count) {
244 tst_brk(TBROK,
245 "TST_TOTAL (%d) and tst_count (%d) are not "
246 "equal", TST_TOTAL, tst_count);
247 }
248 tst_count = 0;
249
250 /*
251 * check events
252 */
253 while (i < len) {
254 struct fanotify_event_metadata *event;
255
256 event = (struct fanotify_event_metadata *)&event_buf[i];
257 if (test_num >= TST_TOTAL) {
258 tst_res(TFAIL,
259 "got unnecessary event: mask=%llx "
260 "pid=%u fd=%d",
261 (unsigned long long)event->mask,
262 (unsigned int)event->pid, event->fd);
263 } else if (!(event->mask & event_set[test_num])) {
264 tst_res(TFAIL,
265 "got event: mask=%llx (expected %llx) "
266 "pid=%u fd=%d",
267 (unsigned long long)event->mask,
268 event_set[test_num],
269 (unsigned int)event->pid, event->fd);
270 } else if (event->pid != getpid()) {
271 tst_res(TFAIL,
272 "got event: mask=%llx pid=%u "
273 "(expected %u) fd=%d",
274 (unsigned long long)event->mask,
275 (unsigned int)event->pid,
276 (unsigned int)getpid(),
277 event->fd);
278 } else {
279 if (event->fd == -2 || (event->fd == FAN_NOFD &&
280 (tc->init_flags & FAN_REPORT_FID)))
281 goto pass;
282 ret = read(event->fd, buf, BUF_SIZE);
283 if (ret != (int)strlen(fname)) {
284 tst_res(TFAIL,
285 "cannot read from returned fd "
286 "of event: mask=%llx pid=%u "
287 "fd=%d ret=%d (errno=%d)",
288 (unsigned long long)event->mask,
289 (unsigned int)event->pid,
290 event->fd, ret, errno);
291 } else if (memcmp(buf, fname, strlen(fname))) {
292 tst_res(TFAIL,
293 "wrong data read from returned fd "
294 "of event: mask=%llx pid=%u "
295 "fd=%d",
296 (unsigned long long)event->mask,
297 (unsigned int)event->pid,
298 event->fd);
299 } else {
300 pass:
301 tst_res(TPASS,
302 "got event: mask=%llx pid=%u fd=%d",
303 (unsigned long long)event->mask,
304 (unsigned int)event->pid, event->fd);
305 }
306 }
307
308 /*
309 * We have verified the data now so close fd and
310 * invalidate it so that we don't check it again
311 * unnecessarily
312 */
313 if (event->fd >= 0)
314 SAFE_CLOSE(event->fd);
315 event->fd = -2;
316 event->mask &= ~event_set[test_num];
317
318 /* No events left in current mask? Go for next event */
319 if (event->mask == 0)
320 i += event->event_len;
321
322 test_num++;
323 }
324
325 for (; test_num < TST_TOTAL; test_num++) {
326 tst_res(TFAIL, "didn't get event: mask=%llx",
327 event_set[test_num]);
328
329 }
330
331 /* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */
332 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE | mark->flag,
333 FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN,
334 AT_FDCWD, fname);
335
336 SAFE_CLOSE(fd_notify);
337 }
338
setup(void)339 static void setup(void)
340 {
341 int fd;
342
343 /* Check for kernel fanotify support */
344 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
345 SAFE_CLOSE(fd);
346
347 sprintf(fname, MOUNT_PATH"/tfile_%d", getpid());
348 SAFE_FILE_PRINTF(fname, "1");
349
350 fan_report_fid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_FID, fname);
351 filesystem_mark_unsupported = fanotify_mark_supported_on_fs(FAN_MARK_FILESYSTEM, fname);
352 mount_mark_fid_unsupported = fanotify_flags_supported_on_fs(FAN_REPORT_FID,
353 FAN_MARK_MOUNT,
354 FAN_OPEN, fname);
355 }
356
cleanup(void)357 static void cleanup(void)
358 {
359 if (fd_notify > 0)
360 SAFE_CLOSE(fd_notify);
361 }
362
363 static struct tst_test test = {
364 .test = test_fanotify,
365 .tcnt = ARRAY_SIZE(tcases),
366 .setup = setup,
367 .cleanup = cleanup,
368 .needs_root = 1,
369 .mount_device = 1,
370 .mntpoint = MOUNT_PATH,
371 };
372
373 #else
374 TST_TEST_TCONF("system doesn't have required fanotify support");
375 #endif
376