• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 filesystem_mark_unsupported;
80 
81 static unsigned long long event_set[EVENT_MAX];
82 
83 static char event_buf[EVENT_BUF_LEN];
84 
test_fanotify(unsigned int n)85 static void test_fanotify(unsigned int n)
86 {
87 	struct tcase *tc = &tcases[n];
88 	struct fanotify_mark_type *mark = &tc->mark;
89 	int fd, ret, len, i = 0, test_num = 0;
90 	int tst_count = 0;
91 
92 	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
93 
94 	if (fan_report_fid_unsupported && (tc->init_flags & FAN_REPORT_FID)) {
95 		FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_FID, fan_report_fid_unsupported);
96 		return;
97 	}
98 
99 	if (filesystem_mark_unsupported && mark->flag == FAN_MARK_FILESYSTEM) {
100 		tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?");
101 		return;
102 	}
103 
104 	fd_notify = SAFE_FANOTIFY_INIT(tc->init_flags, O_RDONLY);
105 
106 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag,
107 			  FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname);
108 
109 	/*
110 	 * generate sequence of events
111 	 */
112 	fd = SAFE_OPEN(fname, O_RDONLY);
113 	event_set[tst_count] = FAN_OPEN;
114 	tst_count++;
115 
116 	SAFE_READ(0, fd, buf, BUF_SIZE);
117 	event_set[tst_count] = FAN_ACCESS;
118 	tst_count++;
119 
120 	SAFE_CLOSE(fd);
121 	event_set[tst_count] = FAN_CLOSE_NOWRITE;
122 	tst_count++;
123 
124 	/*
125 	 * Get list of events so far. We get events here to avoid
126 	 * merging of following events with the previous ones.
127 	 */
128 	ret = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
129 	len = ret;
130 
131 	fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
132 	event_set[tst_count] = FAN_OPEN;
133 	tst_count++;
134 
135 	SAFE_WRITE(1, fd, fname, strlen(fname));
136 	event_set[tst_count] = FAN_MODIFY;
137 	tst_count++;
138 
139 	SAFE_CLOSE(fd);
140 	event_set[tst_count] = FAN_CLOSE_WRITE;
141 	tst_count++;
142 
143 	/*
144 	 * get another list of events
145 	 */
146 	ret = SAFE_READ(0, fd_notify, event_buf + len,
147 			EVENT_BUF_LEN - len);
148 	len += ret;
149 
150 	/*
151 	 * Ignore mask testing
152 	 */
153 
154 	/* Ignore access events */
155 	SAFE_FANOTIFY_MARK(fd_notify,
156 			  FAN_MARK_ADD | mark->flag | FAN_MARK_IGNORED_MASK,
157 			  FAN_ACCESS, AT_FDCWD, fname);
158 
159 	fd = SAFE_OPEN(fname, O_RDWR);
160 	event_set[tst_count] = FAN_OPEN;
161 	tst_count++;
162 
163 	/* This event should be ignored */
164 	SAFE_READ(0, fd, buf, BUF_SIZE);
165 
166 	/*
167 	 * get another list of events to verify the last one got ignored
168 	 */
169 	ret = SAFE_READ(0, fd_notify, event_buf + len,
170 			EVENT_BUF_LEN - len);
171 	len += ret;
172 
173 	SAFE_LSEEK(fd, 0, SEEK_SET);
174 	/* Generate modify event to clear ignore mask */
175 	SAFE_WRITE(1, fd, fname, 1);
176 	event_set[tst_count] = FAN_MODIFY;
177 	tst_count++;
178 
179 	/*
180 	 * This event shouldn't be ignored because previous modification
181 	 * should have removed the ignore mask
182 	 */
183 	SAFE_READ(0, fd, buf, BUF_SIZE);
184 	event_set[tst_count] = FAN_ACCESS;
185 	tst_count++;
186 
187 	SAFE_CLOSE(fd);
188 	event_set[tst_count] = FAN_CLOSE_WRITE;
189 	tst_count++;
190 
191 	/* Read events to verify previous access was properly generated */
192 	ret = SAFE_READ(0, fd_notify, event_buf + len,
193 			EVENT_BUF_LEN - len);
194 	len += ret;
195 
196 	/*
197 	 * Now ignore open & close events regardless of file
198 	 * modifications
199 	 */
200 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag |
201 			  FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY,
202 			  FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname);
203 
204 	/* This event should be ignored */
205 	fd = SAFE_OPEN(fname, O_RDWR);
206 
207 	SAFE_WRITE(1, fd, fname, 1);
208 	event_set[tst_count] = FAN_MODIFY;
209 	tst_count++;
210 
211 	/* This event should be still ignored */
212 	SAFE_CLOSE(fd);
213 
214 	/* This event should still be ignored */
215 	fd = SAFE_OPEN(fname, O_RDWR);
216 
217 	/* Read events to verify open & close were ignored */
218 	ret = SAFE_READ(0, fd_notify, event_buf + len,
219 			EVENT_BUF_LEN - len);
220 	len += ret;
221 
222 	/* Now remove open and close from ignored mask */
223 	SAFE_FANOTIFY_MARK(fd_notify,
224 			  FAN_MARK_REMOVE | mark->flag | FAN_MARK_IGNORED_MASK,
225 			  FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname);
226 
227 	SAFE_CLOSE(fd);
228 	event_set[tst_count] = FAN_CLOSE_WRITE;
229 	tst_count++;
230 
231 	/* Read events to verify close was generated */
232 	ret = SAFE_READ(0, fd_notify, event_buf + len,
233 			EVENT_BUF_LEN - len);
234 	len += ret;
235 
236 	if (TST_TOTAL != tst_count) {
237 		tst_brk(TBROK,
238 			"TST_TOTAL (%d) and tst_count (%d) are not "
239 			"equal", TST_TOTAL, tst_count);
240 	}
241 	tst_count = 0;
242 
243 	/*
244 	 * check events
245 	 */
246 	while (i < len) {
247 		struct fanotify_event_metadata *event;
248 
249 		event = (struct fanotify_event_metadata *)&event_buf[i];
250 		if (test_num >= TST_TOTAL) {
251 			tst_res(TFAIL,
252 				"got unnecessary event: mask=%llx "
253 				"pid=%u fd=%d",
254 				(unsigned long long)event->mask,
255 				(unsigned)event->pid, event->fd);
256 		} else if (!(event->mask & event_set[test_num])) {
257 			tst_res(TFAIL,
258 				"got event: mask=%llx (expected %llx) "
259 				"pid=%u fd=%d",
260 				(unsigned long long)event->mask,
261 				event_set[test_num],
262 				(unsigned)event->pid, event->fd);
263 		} else if (event->pid != getpid()) {
264 			tst_res(TFAIL,
265 				"got event: mask=%llx pid=%u "
266 				"(expected %u) fd=%d",
267 				(unsigned long long)event->mask,
268 				(unsigned)event->pid,
269 				(unsigned)getpid(),
270 				event->fd);
271 		} else {
272 			if (event->fd == -2 || (event->fd == FAN_NOFD &&
273 			    (tc->init_flags & FAN_REPORT_FID)))
274 				goto pass;
275 			ret = read(event->fd, buf, BUF_SIZE);
276 			if (ret != (int)strlen(fname)) {
277 				tst_res(TFAIL,
278 					"cannot read from returned fd "
279 					"of event: mask=%llx pid=%u "
280 					"fd=%d ret=%d (errno=%d)",
281 					(unsigned long long)event->mask,
282 					(unsigned)event->pid,
283 					event->fd, ret, errno);
284 			} else if (memcmp(buf, fname, strlen(fname))) {
285 				tst_res(TFAIL,
286 					"wrong data read from returned fd "
287 					"of event: mask=%llx pid=%u "
288 					"fd=%d",
289 					(unsigned long long)event->mask,
290 					(unsigned)event->pid,
291 					event->fd);
292 			} else {
293 pass:
294 				tst_res(TPASS,
295 					"got event: mask=%llx pid=%u fd=%d",
296 					(unsigned long long)event->mask,
297 					(unsigned)event->pid, event->fd);
298 			}
299 		}
300 		/*
301 		 * We have verified the data now so close fd and
302 		 * invalidate it so that we don't check it again
303 		 * unnecessarily
304 		 */
305 		if (event->fd >= 0)
306 			SAFE_CLOSE(event->fd);
307 		event->fd = -2;
308 		event->mask &= ~event_set[test_num];
309 		/* No events left in current mask? Go for next event */
310 		if (event->mask == 0) {
311 			i += event->event_len;
312 		}
313 		test_num++;
314 	}
315 	for (; test_num < TST_TOTAL; test_num++) {
316 		tst_res(TFAIL, "didn't get event: mask=%llx",
317 			event_set[test_num]);
318 
319 	}
320 	/* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */
321 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE | mark->flag,
322 			  FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN,
323 			  AT_FDCWD, fname);
324 
325 	SAFE_CLOSE(fd_notify);
326 }
327 
setup(void)328 static void setup(void)
329 {
330 	int fd;
331 
332 	/* Check for kernel fanotify support */
333 	fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
334 	SAFE_CLOSE(fd);
335 
336 	sprintf(fname, MOUNT_PATH"/tfile_%d", getpid());
337 	SAFE_FILE_PRINTF(fname, "1");
338 
339 	fan_report_fid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_FID, fname);
340 	filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM);
341 }
342 
cleanup(void)343 static void cleanup(void)
344 {
345 	if (fd_notify > 0)
346 		SAFE_CLOSE(fd_notify);
347 }
348 
349 static struct tst_test test = {
350 	.test = test_fanotify,
351 	.tcnt = ARRAY_SIZE(tcases),
352 	.setup = setup,
353 	.cleanup = cleanup,
354 	.needs_root = 1,
355 	.mount_device = 1,
356 	.mntpoint = MOUNT_PATH,
357 };
358 
359 #else
360 	TST_TEST_TCONF("system doesn't have required fanotify support");
361 #endif
362