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 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 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 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