1 /*
2 * Copyright (c) 2013 SUSE. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Started by Jan Kara <jack@suse.cz>
24 *
25 * DESCRIPTION
26 * Check that fanotify work for a file
27 */
28 #define _GNU_SOURCE
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <sys/syscall.h>
38 #include "tst_test.h"
39 #include "fanotify.h"
40
41 #if defined(HAVE_SYS_FANOTIFY_H)
42 #include <sys/fanotify.h>
43
44 #define EVENT_MAX 1024
45 /* size of the event structure, not counting name */
46 #define EVENT_SIZE (sizeof (struct fanotify_event_metadata))
47 /* reasonable guess as to size of 1024 events */
48 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
49
50 #define BUF_SIZE 256
51 #define TST_TOTAL 12
52
53 static char fname[BUF_SIZE];
54 static char buf[BUF_SIZE];
55 static int fd, fd_notify;
56
57 static unsigned long long event_set[EVENT_MAX];
58
59 static char event_buf[EVENT_BUF_LEN];
60
test01(void)61 void test01(void)
62 {
63 int ret, len, i = 0, test_num = 0;
64
65 int tst_count = 0;
66
67 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | FAN_MODIFY |
68 FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
69 tst_brk(TBROK | TERRNO,
70 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
71 "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
72 "failed", fd_notify, fname);
73 }
74
75 /*
76 * generate sequence of events
77 */
78 fd = SAFE_OPEN(fname, O_RDONLY);
79 event_set[tst_count] = FAN_OPEN;
80 tst_count++;
81
82 SAFE_READ(0, fd, buf, BUF_SIZE);
83 event_set[tst_count] = FAN_ACCESS;
84 tst_count++;
85
86 SAFE_CLOSE(fd);
87 event_set[tst_count] = FAN_CLOSE_NOWRITE;
88 tst_count++;
89
90 /*
91 * Get list of events so far. We get events here to avoid
92 * merging of following events with the previous ones.
93 */
94 ret = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
95 len = ret;
96
97 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
98 event_set[tst_count] = FAN_OPEN;
99 tst_count++;
100
101 SAFE_WRITE(1, fd, fname, strlen(fname));
102 event_set[tst_count] = FAN_MODIFY;
103 tst_count++;
104
105 SAFE_CLOSE(fd);
106 event_set[tst_count] = FAN_CLOSE_WRITE;
107 tst_count++;
108
109 /*
110 * get another list of events
111 */
112 ret = SAFE_READ(0, fd_notify, event_buf + len,
113 EVENT_BUF_LEN - len);
114 len += ret;
115
116 /*
117 * Ignore mask testing
118 */
119
120 /* Ignore access events */
121 if (fanotify_mark(fd_notify,
122 FAN_MARK_ADD | FAN_MARK_IGNORED_MASK,
123 FAN_ACCESS, AT_FDCWD, fname) < 0) {
124 tst_brk(TBROK | TERRNO,
125 "fanotify_mark (%d, FAN_MARK_ADD | "
126 "FAN_MARK_IGNORED_MASK, FAN_ACCESS, "
127 "AT_FDCWD, %s) failed", fd_notify, fname);
128 }
129
130 fd = SAFE_OPEN(fname, O_RDWR);
131 event_set[tst_count] = FAN_OPEN;
132 tst_count++;
133
134 /* This event should be ignored */
135 SAFE_READ(0, fd, buf, BUF_SIZE);
136
137 /*
138 * get another list of events to verify the last one got ignored
139 */
140 ret = SAFE_READ(0, fd_notify, event_buf + len,
141 EVENT_BUF_LEN - len);
142 len += ret;
143
144 lseek(fd, 0, SEEK_SET);
145 /* Generate modify event to clear ignore mask */
146 SAFE_WRITE(1, fd, fname, 1);
147 event_set[tst_count] = FAN_MODIFY;
148 tst_count++;
149
150 /*
151 * This event shouldn't be ignored because previous modification
152 * should have removed the ignore mask
153 */
154 SAFE_READ(0, fd, buf, BUF_SIZE);
155 event_set[tst_count] = FAN_ACCESS;
156 tst_count++;
157
158 SAFE_CLOSE(fd);
159 event_set[tst_count] = FAN_CLOSE_WRITE;
160 tst_count++;
161
162 /* Read events to verify previous access was properly generated */
163 ret = SAFE_READ(0, fd_notify, event_buf + len,
164 EVENT_BUF_LEN - len);
165 len += ret;
166
167 /*
168 * Now ignore open & close events regardless of file
169 * modifications
170 */
171 if (fanotify_mark(fd_notify,
172 FAN_MARK_ADD | FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY,
173 FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
174 tst_brk(TBROK | TERRNO,
175 "fanotify_mark (%d, FAN_MARK_ADD | "
176 "FAN_MARK_IGNORED_MASK | "
177 "FAN_MARK_IGNORED_SURV_MODIFY, FAN_OPEN | "
178 "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
179 fname);
180 }
181
182 /* This event should be ignored */
183 fd = SAFE_OPEN(fname, O_RDWR);
184
185 SAFE_WRITE(1, fd, fname, 1);
186 event_set[tst_count] = FAN_MODIFY;
187 tst_count++;
188
189 /* This event should be still ignored */
190 SAFE_CLOSE(fd);
191
192 /* This event should still be ignored */
193 fd = SAFE_OPEN(fname, O_RDWR);
194
195 /* Read events to verify open & close were ignored */
196 ret = SAFE_READ(0, fd_notify, event_buf + len,
197 EVENT_BUF_LEN - len);
198 len += ret;
199
200 /* Now remove open and close from ignored mask */
201 if (fanotify_mark(fd_notify,
202 FAN_MARK_REMOVE | FAN_MARK_IGNORED_MASK,
203 FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
204 tst_brk(TBROK | TERRNO,
205 "fanotify_mark (%d, FAN_MARK_REMOVE | "
206 "FAN_MARK_IGNORED_MASK, FAN_OPEN | "
207 "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
208 fname);
209 }
210
211 SAFE_CLOSE(fd);
212 event_set[tst_count] = FAN_CLOSE_WRITE;
213 tst_count++;
214
215 /* Read events to verify close was generated */
216 ret = SAFE_READ(0, fd_notify, event_buf + len,
217 EVENT_BUF_LEN - len);
218 len += ret;
219
220 if (TST_TOTAL != tst_count) {
221 tst_brk(TBROK,
222 "TST_TOTAL (%d) and tst_count (%d) are not "
223 "equal", TST_TOTAL, tst_count);
224 }
225 tst_count = 0;
226
227 /*
228 * check events
229 */
230 while (i < len) {
231 struct fanotify_event_metadata *event;
232
233 event = (struct fanotify_event_metadata *)&event_buf[i];
234 if (test_num >= TST_TOTAL) {
235 tst_res(TFAIL,
236 "get unnecessary event: mask=%llx "
237 "pid=%u fd=%u",
238 (unsigned long long)event->mask,
239 (unsigned)event->pid, event->fd);
240 } else if (!(event->mask & event_set[test_num])) {
241 tst_res(TFAIL,
242 "get event: mask=%llx (expected %llx) "
243 "pid=%u fd=%u",
244 (unsigned long long)event->mask,
245 event_set[test_num],
246 (unsigned)event->pid, event->fd);
247 } else if (event->pid != getpid()) {
248 tst_res(TFAIL,
249 "get event: mask=%llx pid=%u "
250 "(expected %u) fd=%u",
251 (unsigned long long)event->mask,
252 (unsigned)event->pid,
253 (unsigned)getpid(),
254 event->fd);
255 } else {
256 if (event->fd == -2)
257 goto pass;
258 ret = read(event->fd, buf, BUF_SIZE);
259 if (ret != (int)strlen(fname)) {
260 tst_res(TFAIL,
261 "cannot read from returned fd "
262 "of event: mask=%llx pid=%u "
263 "fd=%u ret=%d (errno=%d)",
264 (unsigned long long)event->mask,
265 (unsigned)event->pid,
266 event->fd, ret, errno);
267 } else if (memcmp(buf, fname, strlen(fname))) {
268 tst_res(TFAIL,
269 "wrong data read from returned fd "
270 "of event: mask=%llx pid=%u "
271 "fd=%u",
272 (unsigned long long)event->mask,
273 (unsigned)event->pid,
274 event->fd);
275 } else {
276 pass:
277 tst_res(TPASS,
278 "get event: mask=%llx pid=%u fd=%u",
279 (unsigned long long)event->mask,
280 (unsigned)event->pid, event->fd);
281 }
282 }
283 /*
284 * We have verified the data now so close fd and
285 * invalidate it so that we don't check it again
286 * unnecessarily
287 */
288 close(event->fd);
289 event->fd = -2;
290 event->mask &= ~event_set[test_num];
291 /* No events left in current mask? Go for next event */
292 if (event->mask == 0) {
293 i += event->event_len;
294 }
295 test_num++;
296 }
297 for (; test_num < TST_TOTAL; test_num++) {
298 tst_res(TFAIL, "didn't get event: mask=%llx",
299 event_set[test_num]);
300
301 }
302 /* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */
303 if (fanotify_mark(fd_notify, FAN_MARK_REMOVE, FAN_ACCESS | FAN_MODIFY |
304 FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
305 tst_brk(TBROK | TERRNO,
306 "fanotify_mark (%d, FAN_MARK_REMOVE, FAN_ACCESS | "
307 "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
308 "failed", fd_notify, fname);
309 }
310 }
311
setup(void)312 static void setup(void)
313 {
314 sprintf(fname, "tfile_%d", getpid());
315 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
316 SAFE_WRITE(1, fd, fname, 1);
317 /* close the file we have open */
318 SAFE_CLOSE(fd);
319
320 fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
321 }
322
cleanup(void)323 static void cleanup(void)
324 {
325 if (fd_notify > 0)
326 SAFE_CLOSE(fd_notify);
327 }
328
329 static struct tst_test test = {
330 .test_all = test01,
331 .setup = setup,
332 .cleanup = cleanup,
333 .needs_tmpdir = 1,
334 .needs_root = 1
335 };
336
337 #else
338 TST_TEST_TCONF("system doesn't have required fanotify support");
339 #endif
340