1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2013 SUSE. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Jan Kara <jack@suse.cz> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * Check various fanotify special flags. 11f08c3bdfSopenharmony_ci */ 12f08c3bdfSopenharmony_ci 13f08c3bdfSopenharmony_ci#define _GNU_SOURCE 14f08c3bdfSopenharmony_ci#include "config.h" 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci#include <stdio.h> 17f08c3bdfSopenharmony_ci#include <sys/stat.h> 18f08c3bdfSopenharmony_ci#include <sys/types.h> 19f08c3bdfSopenharmony_ci#include <errno.h> 20f08c3bdfSopenharmony_ci#include <string.h> 21f08c3bdfSopenharmony_ci#include <sys/syscall.h> 22f08c3bdfSopenharmony_ci#include "tst_test.h" 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 25f08c3bdfSopenharmony_ci#include "fanotify.h" 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci/* size of the event structure, not counting name */ 28f08c3bdfSopenharmony_ci#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#define BUF_SIZE 256 31f08c3bdfSopenharmony_ci#define TST_TOTAL 9 32f08c3bdfSopenharmony_ci 33f08c3bdfSopenharmony_cistatic char fname[BUF_SIZE]; 34f08c3bdfSopenharmony_cistatic char sname[BUF_SIZE]; 35f08c3bdfSopenharmony_cistatic char dir[BUF_SIZE]; 36f08c3bdfSopenharmony_cistatic int fd_notify; 37f08c3bdfSopenharmony_cistatic char event_buf[EVENT_SIZE]; 38f08c3bdfSopenharmony_ci 39f08c3bdfSopenharmony_cistatic char *expect_str_fail(int expect) 40f08c3bdfSopenharmony_ci{ 41f08c3bdfSopenharmony_ci if (expect == 0) 42f08c3bdfSopenharmony_ci return "failed"; 43f08c3bdfSopenharmony_ci return "unexpectedly succeeded"; 44f08c3bdfSopenharmony_ci} 45f08c3bdfSopenharmony_ci 46f08c3bdfSopenharmony_cistatic char *expect_str_pass(int expect) 47f08c3bdfSopenharmony_ci{ 48f08c3bdfSopenharmony_ci if (expect == 0) 49f08c3bdfSopenharmony_ci return "succeeded"; 50f08c3bdfSopenharmony_ci return "failed"; 51f08c3bdfSopenharmony_ci} 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_cistatic void check_mark(char *file, unsigned long long flag, char *flagstr, 54f08c3bdfSopenharmony_ci int expect, void (*test_event)(char *)) 55f08c3bdfSopenharmony_ci{ 56f08c3bdfSopenharmony_ci if (fanotify_mark(fd_notify, FAN_MARK_ADD | flag, FAN_OPEN, AT_FDCWD, 57f08c3bdfSopenharmony_ci file) != expect) { 58f08c3bdfSopenharmony_ci tst_res(TFAIL, 59f08c3bdfSopenharmony_ci "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, " 60f08c3bdfSopenharmony_ci "AT_FDCWD, '%s') %s", fd_notify, flagstr, file, 61f08c3bdfSopenharmony_ci expect_str_fail(expect)); 62f08c3bdfSopenharmony_ci } else { 63f08c3bdfSopenharmony_ci tst_res(TPASS, 64f08c3bdfSopenharmony_ci "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, " 65f08c3bdfSopenharmony_ci "AT_FDCWD, '%s') %s", fd_notify, flagstr, file, 66f08c3bdfSopenharmony_ci expect_str_pass(expect)); 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_ci /* If we expected failure there's nothing to clean up */ 69f08c3bdfSopenharmony_ci if (expect == -1) 70f08c3bdfSopenharmony_ci return; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci if (test_event) 73f08c3bdfSopenharmony_ci test_event(file); 74f08c3bdfSopenharmony_ci 75f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE | flag, 76f08c3bdfSopenharmony_ci FAN_OPEN, AT_FDCWD, file); 77f08c3bdfSopenharmony_ci } 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_ci#define CHECK_MARK(file, flag, expect, func) check_mark(file, flag, #flag, expect, func) 81f08c3bdfSopenharmony_ci 82f08c3bdfSopenharmony_cistatic void do_open(char *file, int flag) 83f08c3bdfSopenharmony_ci{ 84f08c3bdfSopenharmony_ci int fd; 85f08c3bdfSopenharmony_ci 86f08c3bdfSopenharmony_ci fd = SAFE_OPEN(file, O_RDONLY | flag); 87f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 88f08c3bdfSopenharmony_ci} 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_cistatic void open_file(char *file) 91f08c3bdfSopenharmony_ci{ 92f08c3bdfSopenharmony_ci do_open(file, 0); 93f08c3bdfSopenharmony_ci} 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_cistatic void open_dir(char *file) 96f08c3bdfSopenharmony_ci{ 97f08c3bdfSopenharmony_ci do_open(file, O_DIRECTORY); 98f08c3bdfSopenharmony_ci} 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_cistatic void verify_event(int mask) 101f08c3bdfSopenharmony_ci{ 102f08c3bdfSopenharmony_ci struct fanotify_event_metadata *event; 103f08c3bdfSopenharmony_ci struct stat st; 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci /* Read the event */ 106f08c3bdfSopenharmony_ci SAFE_READ(0, fd_notify, event_buf, EVENT_SIZE); 107f08c3bdfSopenharmony_ci event = (struct fanotify_event_metadata *)&event_buf; 108f08c3bdfSopenharmony_ci if (event->mask != FAN_OPEN) { 109f08c3bdfSopenharmony_ci tst_res(TFAIL, "got unexpected event %llx", 110f08c3bdfSopenharmony_ci (unsigned long long)event->mask); 111f08c3bdfSopenharmony_ci } else if (fstat(event->fd, &st) < 0) { 112f08c3bdfSopenharmony_ci tst_res(TFAIL, "failed to stat event->fd (%s)", 113f08c3bdfSopenharmony_ci strerror(errno)); 114f08c3bdfSopenharmony_ci } else if ((int)(st.st_mode & S_IFMT) != mask) { 115f08c3bdfSopenharmony_ci tst_res(TFAIL, "event->fd points to object of different type " 116f08c3bdfSopenharmony_ci "(%o != %o)", st.st_mode & S_IFMT, mask); 117f08c3bdfSopenharmony_ci } else { 118f08c3bdfSopenharmony_ci tst_res(TPASS, "event generated properly for type %o", mask); 119f08c3bdfSopenharmony_ci } 120f08c3bdfSopenharmony_ci if (event->fd != FAN_NOFD) 121f08c3bdfSopenharmony_ci SAFE_CLOSE(event->fd); 122f08c3bdfSopenharmony_ci} 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_cistatic void do_open_test(char *file, int flag, int mask) 125f08c3bdfSopenharmony_ci{ 126f08c3bdfSopenharmony_ci do_open(file, flag); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci verify_event(mask); 129f08c3bdfSopenharmony_ci} 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_cistatic void test_open_file(char *file) 132f08c3bdfSopenharmony_ci{ 133f08c3bdfSopenharmony_ci do_open_test(file, 0, S_IFREG); 134f08c3bdfSopenharmony_ci} 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_cistatic void verify_no_event(void) 137f08c3bdfSopenharmony_ci{ 138f08c3bdfSopenharmony_ci int ret; 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci ret = read(fd_notify, event_buf, EVENT_SIZE); 141f08c3bdfSopenharmony_ci if (ret != -1) { 142f08c3bdfSopenharmony_ci struct fanotify_event_metadata *event; 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci event = (struct fanotify_event_metadata *)&event_buf; 145f08c3bdfSopenharmony_ci tst_res(TFAIL, "seen unexpected event (mask %llx)", 146f08c3bdfSopenharmony_ci (unsigned long long)event->mask); 147f08c3bdfSopenharmony_ci /* Cleanup fd from the event */ 148f08c3bdfSopenharmony_ci if (event->fd != FAN_NOFD) 149f08c3bdfSopenharmony_ci SAFE_CLOSE(event->fd); 150f08c3bdfSopenharmony_ci } else if (errno != EAGAIN) { 151f08c3bdfSopenharmony_ci tst_res(TFAIL | TERRNO, "read(%d, buf, %zu) failed", fd_notify, 152f08c3bdfSopenharmony_ci EVENT_SIZE); 153f08c3bdfSopenharmony_ci } else { 154f08c3bdfSopenharmony_ci tst_res(TPASS, "No event as expected"); 155f08c3bdfSopenharmony_ci } 156f08c3bdfSopenharmony_ci} 157f08c3bdfSopenharmony_ci 158f08c3bdfSopenharmony_cistatic void test_open_symlink(char *file) 159f08c3bdfSopenharmony_ci{ 160f08c3bdfSopenharmony_ci /* Since mark is on a symlink, no event should be generated by opening a file */ 161f08c3bdfSopenharmony_ci do_open(file, 0); 162f08c3bdfSopenharmony_ci verify_no_event(); 163f08c3bdfSopenharmony_ci} 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_cistatic void test01(void) 166f08c3bdfSopenharmony_ci{ 167f08c3bdfSopenharmony_ci /* Check ONLYDIR on a directory */ 168f08c3bdfSopenharmony_ci CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL); 169f08c3bdfSopenharmony_ci 170f08c3bdfSopenharmony_ci /* Check ONLYDIR without a directory */ 171f08c3bdfSopenharmony_ci CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL); 172f08c3bdfSopenharmony_ci 173f08c3bdfSopenharmony_ci /* Check DONT_FOLLOW for a symlink */ 174f08c3bdfSopenharmony_ci CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci /* Check without DONT_FOLLOW for a symlink */ 177f08c3bdfSopenharmony_ci CHECK_MARK(sname, 0, 0, test_open_file); 178f08c3bdfSopenharmony_ci 179f08c3bdfSopenharmony_ci /* Verify FAN_MARK_FLUSH destroys all inode marks */ 180f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, fname); 181f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD, FAN_OPEN | FAN_ONDIR, 182f08c3bdfSopenharmony_ci AT_FDCWD, dir); 183f08c3bdfSopenharmony_ci open_file(fname); 184f08c3bdfSopenharmony_ci verify_event(S_IFREG); 185f08c3bdfSopenharmony_ci open_dir(dir); 186f08c3bdfSopenharmony_ci verify_event(S_IFDIR); 187f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_FLUSH, 0, AT_FDCWD, "."); 188f08c3bdfSopenharmony_ci 189f08c3bdfSopenharmony_ci open_dir(dir); 190f08c3bdfSopenharmony_ci verify_no_event(); 191f08c3bdfSopenharmony_ci} 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_cistatic void setup(void) 194f08c3bdfSopenharmony_ci{ 195f08c3bdfSopenharmony_ci int fd; 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_ci sprintf(fname, "fname_%d", getpid()); 198f08c3bdfSopenharmony_ci fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0644); 199f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci sprintf(sname, "symlink_%d", getpid()); 202f08c3bdfSopenharmony_ci SAFE_SYMLINK(fname, sname); 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci sprintf(dir, "dir_%d", getpid()); 205f08c3bdfSopenharmony_ci SAFE_MKDIR(dir, 0755); 206f08c3bdfSopenharmony_ci 207f08c3bdfSopenharmony_ci fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF | FAN_NONBLOCK, 208f08c3bdfSopenharmony_ci O_RDONLY); 209f08c3bdfSopenharmony_ci} 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_cistatic void cleanup(void) 212f08c3bdfSopenharmony_ci{ 213f08c3bdfSopenharmony_ci if (fd_notify > 0) 214f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 215f08c3bdfSopenharmony_ci} 216f08c3bdfSopenharmony_ci 217f08c3bdfSopenharmony_cistatic struct tst_test test = { 218f08c3bdfSopenharmony_ci .test_all = test01, 219f08c3bdfSopenharmony_ci .setup = setup, 220f08c3bdfSopenharmony_ci .cleanup = cleanup, 221f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 222f08c3bdfSopenharmony_ci .needs_root = 1 223f08c3bdfSopenharmony_ci}; 224f08c3bdfSopenharmony_ci 225f08c3bdfSopenharmony_ci#else 226f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required fanotify support"); 227f08c3bdfSopenharmony_ci#endif 228