1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Matthew Bobrowski <mbobrowski@mbobrowski.org> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * Validate that the newly introduced FAN_OPEN_EXEC mask functions as expected. 11f08c3bdfSopenharmony_ci * The idea is to generate a sequence of open related actions to ensure that 12f08c3bdfSopenharmony_ci * the correct event flags are being set depending on what event mask was 13f08c3bdfSopenharmony_ci * requested when the object was marked. 14f08c3bdfSopenharmony_ci */ 15f08c3bdfSopenharmony_ci 16f08c3bdfSopenharmony_ci#define _GNU_SOURCE 17f08c3bdfSopenharmony_ci#include "config.h" 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#include <stdio.h> 20f08c3bdfSopenharmony_ci#include <errno.h> 21f08c3bdfSopenharmony_ci#include <stdlib.h> 22f08c3bdfSopenharmony_ci#include <sys/stat.h> 23f08c3bdfSopenharmony_ci#include <sys/types.h> 24f08c3bdfSopenharmony_ci#include <sys/wait.h> 25f08c3bdfSopenharmony_ci#include "tst_test.h" 26f08c3bdfSopenharmony_ci 27f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 28f08c3bdfSopenharmony_ci#include "fanotify.h" 29f08c3bdfSopenharmony_ci 30f08c3bdfSopenharmony_ci#define EVENT_MAX 1024 31f08c3bdfSopenharmony_ci#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) 32f08c3bdfSopenharmony_ci#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) 33f08c3bdfSopenharmony_ci#define EVENT_SET_BUF 32 34f08c3bdfSopenharmony_ci 35f08c3bdfSopenharmony_ci#define BUF_SIZE 256 36f08c3bdfSopenharmony_ci#define TEST_APP "fanotify_child" 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_cistatic pid_t child_pid; 39f08c3bdfSopenharmony_cistatic char fname[BUF_SIZE]; 40f08c3bdfSopenharmony_cistatic volatile int fd_notify; 41f08c3bdfSopenharmony_cistatic volatile int complete; 42f08c3bdfSopenharmony_cistatic char event_buf[EVENT_BUF_LEN]; 43f08c3bdfSopenharmony_cistatic int exec_events_unsupported; 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_cistatic struct test_case_t { 46f08c3bdfSopenharmony_ci const char *tname; 47f08c3bdfSopenharmony_ci struct fanotify_mark_type mark; 48f08c3bdfSopenharmony_ci unsigned long long mask; 49f08c3bdfSopenharmony_ci unsigned long long ignore_mask; 50f08c3bdfSopenharmony_ci int event_count; 51f08c3bdfSopenharmony_ci unsigned long long event_set[EVENT_SET_BUF]; 52f08c3bdfSopenharmony_ci} test_cases[] = { 53f08c3bdfSopenharmony_ci { 54f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN events", 55f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 56f08c3bdfSopenharmony_ci FAN_OPEN, 57f08c3bdfSopenharmony_ci 0, 58f08c3bdfSopenharmony_ci 2, 59f08c3bdfSopenharmony_ci {FAN_OPEN, FAN_OPEN} 60f08c3bdfSopenharmony_ci }, 61f08c3bdfSopenharmony_ci { 62f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN_EXEC events", 63f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 64f08c3bdfSopenharmony_ci FAN_OPEN_EXEC, 65f08c3bdfSopenharmony_ci 0, 66f08c3bdfSopenharmony_ci 1, 67f08c3bdfSopenharmony_ci {FAN_OPEN_EXEC} 68f08c3bdfSopenharmony_ci }, 69f08c3bdfSopenharmony_ci { 70f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN | FAN_OPEN_EXEC events", 71f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 72f08c3bdfSopenharmony_ci FAN_OPEN | FAN_OPEN_EXEC, 73f08c3bdfSopenharmony_ci 0, 74f08c3bdfSopenharmony_ci 2, 75f08c3bdfSopenharmony_ci {FAN_OPEN, FAN_OPEN | FAN_OPEN_EXEC} 76f08c3bdfSopenharmony_ci }, 77f08c3bdfSopenharmony_ci { 78f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN events, ignore FAN_OPEN_EXEC", 79f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 80f08c3bdfSopenharmony_ci FAN_OPEN, 81f08c3bdfSopenharmony_ci FAN_OPEN_EXEC, 82f08c3bdfSopenharmony_ci 2, 83f08c3bdfSopenharmony_ci {FAN_OPEN, FAN_OPEN} 84f08c3bdfSopenharmony_ci }, 85f08c3bdfSopenharmony_ci { 86f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN_EXEC events, ignore FAN_OPEN", 87f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 88f08c3bdfSopenharmony_ci FAN_OPEN_EXEC, 89f08c3bdfSopenharmony_ci FAN_OPEN, 90f08c3bdfSopenharmony_ci 1, 91f08c3bdfSopenharmony_ci {FAN_OPEN_EXEC} 92f08c3bdfSopenharmony_ci }, 93f08c3bdfSopenharmony_ci { 94f08c3bdfSopenharmony_ci "inode mark, FAN_OPEN | FAN_OPEN_EXEC events, ignore " 95f08c3bdfSopenharmony_ci "FAN_OPEN_EXEC", 96f08c3bdfSopenharmony_ci INIT_FANOTIFY_MARK_TYPE(INODE), 97f08c3bdfSopenharmony_ci FAN_OPEN | FAN_OPEN_EXEC, 98f08c3bdfSopenharmony_ci FAN_OPEN_EXEC, 99f08c3bdfSopenharmony_ci 2, 100f08c3bdfSopenharmony_ci {FAN_OPEN, FAN_OPEN} 101f08c3bdfSopenharmony_ci } 102f08c3bdfSopenharmony_ci}; 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_cistatic int generate_events(void) 105f08c3bdfSopenharmony_ci{ 106f08c3bdfSopenharmony_ci int fd, status; 107f08c3bdfSopenharmony_ci 108f08c3bdfSopenharmony_ci child_pid = SAFE_FORK(); 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_ci /* 111f08c3bdfSopenharmony_ci * Generate a sequence of events 112f08c3bdfSopenharmony_ci */ 113f08c3bdfSopenharmony_ci if (child_pid == 0) { 114f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci fd = SAFE_OPEN(fname, O_RDONLY); 117f08c3bdfSopenharmony_ci 118f08c3bdfSopenharmony_ci if (fd > 0) 119f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci SAFE_EXECL(TEST_APP, TEST_APP, NULL); 122f08c3bdfSopenharmony_ci exit(1); 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci SAFE_WAITPID(child_pid, &status, 0); 126f08c3bdfSopenharmony_ci 127f08c3bdfSopenharmony_ci if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 128f08c3bdfSopenharmony_ci return 1; 129f08c3bdfSopenharmony_ci return 0; 130f08c3bdfSopenharmony_ci} 131f08c3bdfSopenharmony_ci 132f08c3bdfSopenharmony_cistatic int setup_mark(unsigned int n) 133f08c3bdfSopenharmony_ci{ 134f08c3bdfSopenharmony_ci unsigned int i = 0; 135f08c3bdfSopenharmony_ci struct test_case_t *tc = &test_cases[n]; 136f08c3bdfSopenharmony_ci struct fanotify_mark_type *mark = &tc->mark; 137f08c3bdfSopenharmony_ci const char *const files[] = {fname, TEST_APP}; 138f08c3bdfSopenharmony_ci 139f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", n, tc->tname); 140f08c3bdfSopenharmony_ci 141f08c3bdfSopenharmony_ci if (exec_events_unsupported && ((tc->mask & FAN_OPEN_EXEC) || 142f08c3bdfSopenharmony_ci tc->ignore_mask & FAN_OPEN_EXEC)) { 143f08c3bdfSopenharmony_ci tst_res(TCONF, "FAN_OPEN_EXEC not supported in kernel?"); 144f08c3bdfSopenharmony_ci return -1; 145f08c3bdfSopenharmony_ci } 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); 148f08c3bdfSopenharmony_ci 149f08c3bdfSopenharmony_ci for (; i < ARRAY_SIZE(files); i++) { 150f08c3bdfSopenharmony_ci /* Setup normal mark on object */ 151f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, 152f08c3bdfSopenharmony_ci tc->mask, AT_FDCWD, files[i]); 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci /* Setup ignore mark on object */ 155f08c3bdfSopenharmony_ci if (tc->ignore_mask) { 156f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag 157f08c3bdfSopenharmony_ci | FAN_MARK_IGNORED_MASK, 158f08c3bdfSopenharmony_ci tc->ignore_mask, AT_FDCWD, 159f08c3bdfSopenharmony_ci files[i]); 160f08c3bdfSopenharmony_ci } 161f08c3bdfSopenharmony_ci } 162f08c3bdfSopenharmony_ci 163f08c3bdfSopenharmony_ci return 0; 164f08c3bdfSopenharmony_ci} 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_cistatic void do_test(unsigned int n) 167f08c3bdfSopenharmony_ci{ 168f08c3bdfSopenharmony_ci int len = 0, event_num = 0; 169f08c3bdfSopenharmony_ci struct test_case_t *tc = &test_cases[n]; 170f08c3bdfSopenharmony_ci struct fanotify_event_metadata *event; 171f08c3bdfSopenharmony_ci 172f08c3bdfSopenharmony_ci /* Place a mark on the object */ 173f08c3bdfSopenharmony_ci if (setup_mark(n) != 0) 174f08c3bdfSopenharmony_ci goto cleanup; 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci /* Generate events in child process */ 177f08c3bdfSopenharmony_ci if (!generate_events()) 178f08c3bdfSopenharmony_ci goto cleanup; 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci /* Read available events into buffer */ 181f08c3bdfSopenharmony_ci len = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN); 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci event = (struct fanotify_event_metadata *) event_buf; 184f08c3bdfSopenharmony_ci 185f08c3bdfSopenharmony_ci /* Process events */ 186f08c3bdfSopenharmony_ci while (FAN_EVENT_OK(event, len) && event_num < tc->event_count) { 187f08c3bdfSopenharmony_ci if (event->mask != *(tc->event_set + event_num)) { 188f08c3bdfSopenharmony_ci tst_res(TFAIL, 189f08c3bdfSopenharmony_ci "Received event: mask=%llx (expected %llx, " 190f08c3bdfSopenharmony_ci "pid=%u, fd=%d", 191f08c3bdfSopenharmony_ci (unsigned long long) event->mask, 192f08c3bdfSopenharmony_ci *(tc->event_set + event_num), 193f08c3bdfSopenharmony_ci (unsigned int) event->pid, 194f08c3bdfSopenharmony_ci event->fd); 195f08c3bdfSopenharmony_ci } else if (event->pid != child_pid) { 196f08c3bdfSopenharmony_ci tst_res(TFAIL, 197f08c3bdfSopenharmony_ci "Received event: mask=%llx, pid=%u (expected " 198f08c3bdfSopenharmony_ci "%u), fd=%d", 199f08c3bdfSopenharmony_ci (unsigned long long) event->mask, 200f08c3bdfSopenharmony_ci (unsigned int) event->pid, 201f08c3bdfSopenharmony_ci (unsigned int) child_pid, 202f08c3bdfSopenharmony_ci event->fd); 203f08c3bdfSopenharmony_ci } else { 204f08c3bdfSopenharmony_ci tst_res(TPASS, 205f08c3bdfSopenharmony_ci "Received event: mask=%llx, pid=%u, fd=%d", 206f08c3bdfSopenharmony_ci (unsigned long long) event->mask, 207f08c3bdfSopenharmony_ci (unsigned int) event->pid, 208f08c3bdfSopenharmony_ci event->fd); 209f08c3bdfSopenharmony_ci } 210f08c3bdfSopenharmony_ci 211f08c3bdfSopenharmony_ci if (event->fd != FAN_NOFD) 212f08c3bdfSopenharmony_ci SAFE_CLOSE(event->fd); 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci event_num++; 215f08c3bdfSopenharmony_ci event = FAN_EVENT_NEXT(event, len); 216f08c3bdfSopenharmony_ci } 217f08c3bdfSopenharmony_ci 218f08c3bdfSopenharmony_cicleanup: 219f08c3bdfSopenharmony_ci if (fd_notify > 0) 220f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 221f08c3bdfSopenharmony_ci} 222f08c3bdfSopenharmony_ci 223f08c3bdfSopenharmony_cistatic void do_setup(void) 224f08c3bdfSopenharmony_ci{ 225f08c3bdfSopenharmony_ci exec_events_unsupported = fanotify_events_supported_by_kernel(FAN_OPEN_EXEC, 226f08c3bdfSopenharmony_ci FAN_CLASS_NOTIF, 0); 227f08c3bdfSopenharmony_ci 228f08c3bdfSopenharmony_ci sprintf(fname, "fname_%d", getpid()); 229f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(fname, "1"); 230f08c3bdfSopenharmony_ci} 231f08c3bdfSopenharmony_ci 232f08c3bdfSopenharmony_cistatic void do_cleanup(void) 233f08c3bdfSopenharmony_ci{ 234f08c3bdfSopenharmony_ci if (fd_notify > 0) 235f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 236f08c3bdfSopenharmony_ci} 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_cistatic struct tst_test test = { 239f08c3bdfSopenharmony_ci .setup = do_setup, 240f08c3bdfSopenharmony_ci .test = do_test, 241f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(test_cases), 242f08c3bdfSopenharmony_ci .cleanup = do_cleanup, 243f08c3bdfSopenharmony_ci .forks_child = 1, 244f08c3bdfSopenharmony_ci .needs_root = 1, 245f08c3bdfSopenharmony_ci .resource_files = (const char *const []) { 246f08c3bdfSopenharmony_ci TEST_APP, 247f08c3bdfSopenharmony_ci NULL 248f08c3bdfSopenharmony_ci } 249f08c3bdfSopenharmony_ci}; 250f08c3bdfSopenharmony_ci#else 251f08c3bdfSopenharmony_ci TST_TEST_TCONF("System does not contain required fanotify support"); 252f08c3bdfSopenharmony_ci#endif 253