1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2021 Google. All Rights Reserved. 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * Started by Matthew Bobrowski <repnop@google.com> 6f08c3bdfSopenharmony_ci */ 7f08c3bdfSopenharmony_ci 8f08c3bdfSopenharmony_ci/*\ 9f08c3bdfSopenharmony_ci * [Description] 10f08c3bdfSopenharmony_ci * 11f08c3bdfSopenharmony_ci * A test which verifies whether the returned struct 12f08c3bdfSopenharmony_ci * fanotify_event_info_pidfd in FAN_REPORT_PIDFD mode contains the 13f08c3bdfSopenharmony_ci * expected set of information. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * NOTE: FAN_REPORT_PIDFD support was added in v5.15-rc1 in af579beb666a 16f08c3bdfSopenharmony_ci * ("fanotify: add pidfd support to the fanotify API"). 17f08c3bdfSopenharmony_ci */ 18f08c3bdfSopenharmony_ci 19f08c3bdfSopenharmony_ci#define _GNU_SOURCE 20f08c3bdfSopenharmony_ci#include <stdio.h> 21f08c3bdfSopenharmony_ci#include <ctype.h> 22f08c3bdfSopenharmony_ci#include <stdlib.h> 23f08c3bdfSopenharmony_ci#include <string.h> 24f08c3bdfSopenharmony_ci#include "tst_test.h" 25f08c3bdfSopenharmony_ci#include "tst_safe_stdio.h" 26f08c3bdfSopenharmony_ci#include "tst_safe_macros.h" 27f08c3bdfSopenharmony_ci#include "lapi/pidfd.h" 28f08c3bdfSopenharmony_ci 29f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 30f08c3bdfSopenharmony_ci#include "fanotify.h" 31f08c3bdfSopenharmony_ci 32f08c3bdfSopenharmony_ci#define BUF_SZ 4096 33f08c3bdfSopenharmony_ci#define MOUNT_PATH "fs_mnt" 34f08c3bdfSopenharmony_ci#define TEST_FILE MOUNT_PATH "/testfile" 35f08c3bdfSopenharmony_ci 36f08c3bdfSopenharmony_cistruct pidfd_fdinfo_t { 37f08c3bdfSopenharmony_ci int pos; 38f08c3bdfSopenharmony_ci int flags; 39f08c3bdfSopenharmony_ci int mnt_id; 40f08c3bdfSopenharmony_ci int pid; 41f08c3bdfSopenharmony_ci int ns_pid; 42f08c3bdfSopenharmony_ci}; 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_cistatic struct test_case_t { 45f08c3bdfSopenharmony_ci char *name; 46f08c3bdfSopenharmony_ci int fork; 47f08c3bdfSopenharmony_ci int want_pidfd_err; 48f08c3bdfSopenharmony_ci} test_cases[] = { 49f08c3bdfSopenharmony_ci { 50f08c3bdfSopenharmony_ci "return a valid pidfd for event created by self", 51f08c3bdfSopenharmony_ci 0, 52f08c3bdfSopenharmony_ci 0, 53f08c3bdfSopenharmony_ci }, 54f08c3bdfSopenharmony_ci { 55f08c3bdfSopenharmony_ci "return invalid pidfd for event created by terminated child", 56f08c3bdfSopenharmony_ci 1, 57f08c3bdfSopenharmony_ci FAN_NOPIDFD, 58f08c3bdfSopenharmony_ci }, 59f08c3bdfSopenharmony_ci}; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_cistatic int fanotify_fd; 62f08c3bdfSopenharmony_cistatic char event_buf[BUF_SZ]; 63f08c3bdfSopenharmony_cistatic struct pidfd_fdinfo_t *self_pidfd_fdinfo; 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cistatic struct pidfd_fdinfo_t *read_pidfd_fdinfo(int pidfd) 66f08c3bdfSopenharmony_ci{ 67f08c3bdfSopenharmony_ci char *fdinfo_path; 68f08c3bdfSopenharmony_ci struct pidfd_fdinfo_t *pidfd_fdinfo; 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci pidfd_fdinfo = SAFE_MALLOC(sizeof(struct pidfd_fdinfo_t)); 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci SAFE_ASPRINTF(&fdinfo_path, "/proc/self/fdinfo/%d", pidfd); 73f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(fdinfo_path, "pos: %d", &pidfd_fdinfo->pos); 74f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(fdinfo_path, "flags: %d", &pidfd_fdinfo->flags); 75f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(fdinfo_path, "mnt_id: %d", &pidfd_fdinfo->mnt_id); 76f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(fdinfo_path, "Pid: %d", &pidfd_fdinfo->pid); 77f08c3bdfSopenharmony_ci SAFE_FILE_LINES_SCANF(fdinfo_path, "NSpid: %d", &pidfd_fdinfo->ns_pid); 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_ci free(fdinfo_path); 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ci return pidfd_fdinfo; 82f08c3bdfSopenharmony_ci} 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_cistatic void generate_event(void) 85f08c3bdfSopenharmony_ci{ 86f08c3bdfSopenharmony_ci int fd; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci /* Generate a single FAN_OPEN event on the watched object. */ 89f08c3bdfSopenharmony_ci fd = SAFE_OPEN(TEST_FILE, O_RDONLY); 90f08c3bdfSopenharmony_ci SAFE_CLOSE(fd); 91f08c3bdfSopenharmony_ci} 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_cistatic void do_fork(void) 94f08c3bdfSopenharmony_ci{ 95f08c3bdfSopenharmony_ci int status; 96f08c3bdfSopenharmony_ci pid_t child; 97f08c3bdfSopenharmony_ci 98f08c3bdfSopenharmony_ci child = SAFE_FORK(); 99f08c3bdfSopenharmony_ci if (child == 0) { 100f08c3bdfSopenharmony_ci SAFE_CLOSE(fanotify_fd); 101f08c3bdfSopenharmony_ci generate_event(); 102f08c3bdfSopenharmony_ci exit(EXIT_SUCCESS); 103f08c3bdfSopenharmony_ci } 104f08c3bdfSopenharmony_ci 105f08c3bdfSopenharmony_ci SAFE_WAITPID(child, &status, 0); 106f08c3bdfSopenharmony_ci if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 107f08c3bdfSopenharmony_ci tst_brk(TBROK, 108f08c3bdfSopenharmony_ci "child process terminated incorrectly"); 109f08c3bdfSopenharmony_ci} 110f08c3bdfSopenharmony_ci 111f08c3bdfSopenharmony_cistatic void do_setup(void) 112f08c3bdfSopenharmony_ci{ 113f08c3bdfSopenharmony_ci int pidfd; 114f08c3bdfSopenharmony_ci 115f08c3bdfSopenharmony_ci SAFE_TOUCH(TEST_FILE, 0666, NULL); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci /* 118f08c3bdfSopenharmony_ci * An explicit check for FAN_REPORT_PIDFD is performed early 119f08c3bdfSopenharmony_ci * on in the test initialization as it's a prerequisite for 120f08c3bdfSopenharmony_ci * all test cases. 121f08c3bdfSopenharmony_ci */ 122f08c3bdfSopenharmony_ci REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(FAN_REPORT_PIDFD); 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci fanotify_fd = SAFE_FANOTIFY_INIT(FAN_REPORT_PIDFD, O_RDONLY); 125f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, 126f08c3bdfSopenharmony_ci TEST_FILE); 127f08c3bdfSopenharmony_ci 128f08c3bdfSopenharmony_ci pidfd = SAFE_PIDFD_OPEN(getpid(), 0); 129f08c3bdfSopenharmony_ci 130f08c3bdfSopenharmony_ci self_pidfd_fdinfo = read_pidfd_fdinfo(pidfd); 131f08c3bdfSopenharmony_ci if (self_pidfd_fdinfo == NULL) { 132f08c3bdfSopenharmony_ci tst_brk(TBROK, 133f08c3bdfSopenharmony_ci "pidfd=%d, failed to read pidfd fdinfo", 134f08c3bdfSopenharmony_ci pidfd); 135f08c3bdfSopenharmony_ci } 136f08c3bdfSopenharmony_ci} 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_cistatic void do_test(unsigned int num) 139f08c3bdfSopenharmony_ci{ 140f08c3bdfSopenharmony_ci int i = 0, len; 141f08c3bdfSopenharmony_ci struct test_case_t *tc = &test_cases[num]; 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci tst_res(TINFO, "Test #%d: %s", num, tc->name); 144f08c3bdfSopenharmony_ci 145f08c3bdfSopenharmony_ci /* 146f08c3bdfSopenharmony_ci * Generate the event in either self or a child process. Event 147f08c3bdfSopenharmony_ci * generation in a child process is done so that the FAN_NOPIDFD case 148f08c3bdfSopenharmony_ci * can be verified. 149f08c3bdfSopenharmony_ci */ 150f08c3bdfSopenharmony_ci if (tc->fork) 151f08c3bdfSopenharmony_ci do_fork(); 152f08c3bdfSopenharmony_ci else 153f08c3bdfSopenharmony_ci generate_event(); 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci /* 156f08c3bdfSopenharmony_ci * Read all of the queued events into the provided event 157f08c3bdfSopenharmony_ci * buffer. 158f08c3bdfSopenharmony_ci */ 159f08c3bdfSopenharmony_ci len = SAFE_READ(0, fanotify_fd, event_buf, sizeof(event_buf)); 160f08c3bdfSopenharmony_ci while (i < len) { 161f08c3bdfSopenharmony_ci struct fanotify_event_metadata *event; 162f08c3bdfSopenharmony_ci struct fanotify_event_info_pidfd *info; 163f08c3bdfSopenharmony_ci struct pidfd_fdinfo_t *event_pidfd_fdinfo = NULL; 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci event = (struct fanotify_event_metadata *)&event_buf[i]; 166f08c3bdfSopenharmony_ci info = (struct fanotify_event_info_pidfd *)(event + 1); 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci /* 169f08c3bdfSopenharmony_ci * Checks ensuring that pidfd information record object header 170f08c3bdfSopenharmony_ci * fields are set correctly. 171f08c3bdfSopenharmony_ci */ 172f08c3bdfSopenharmony_ci if (info->hdr.info_type != FAN_EVENT_INFO_TYPE_PIDFD) { 173f08c3bdfSopenharmony_ci tst_res(TFAIL, 174f08c3bdfSopenharmony_ci "unexpected info_type received in info " 175f08c3bdfSopenharmony_ci "header (expected: %d, got: %d", 176f08c3bdfSopenharmony_ci FAN_EVENT_INFO_TYPE_PIDFD, 177f08c3bdfSopenharmony_ci info->hdr.info_type); 178f08c3bdfSopenharmony_ci info = NULL; 179f08c3bdfSopenharmony_ci goto next_event; 180f08c3bdfSopenharmony_ci } else if (info->hdr.len != 181f08c3bdfSopenharmony_ci sizeof(struct fanotify_event_info_pidfd)) { 182f08c3bdfSopenharmony_ci tst_res(TFAIL, 183f08c3bdfSopenharmony_ci "unexpected info object length " 184f08c3bdfSopenharmony_ci "(expected: %lu, got: %d", 185f08c3bdfSopenharmony_ci sizeof(struct fanotify_event_info_pidfd), 186f08c3bdfSopenharmony_ci info->hdr.len); 187f08c3bdfSopenharmony_ci info = NULL; 188f08c3bdfSopenharmony_ci goto next_event; 189f08c3bdfSopenharmony_ci } 190f08c3bdfSopenharmony_ci 191f08c3bdfSopenharmony_ci /* 192f08c3bdfSopenharmony_ci * Check if pidfd information object reported any errors during 193f08c3bdfSopenharmony_ci * creation and whether they're expected. 194f08c3bdfSopenharmony_ci */ 195f08c3bdfSopenharmony_ci if (info->pidfd < 0 && !tc->want_pidfd_err) { 196f08c3bdfSopenharmony_ci tst_res(TFAIL, 197f08c3bdfSopenharmony_ci "pidfd creation failed for pid: %u with pidfd error value " 198f08c3bdfSopenharmony_ci "set to: %d", 199f08c3bdfSopenharmony_ci (unsigned int)event->pid, 200f08c3bdfSopenharmony_ci info->pidfd); 201f08c3bdfSopenharmony_ci goto next_event; 202f08c3bdfSopenharmony_ci } else if (tc->want_pidfd_err && 203f08c3bdfSopenharmony_ci info->pidfd != tc->want_pidfd_err) { 204f08c3bdfSopenharmony_ci tst_res(TFAIL, 205f08c3bdfSopenharmony_ci "pidfd set to an unexpected error: %d for pid: %u", 206f08c3bdfSopenharmony_ci info->pidfd, 207f08c3bdfSopenharmony_ci (unsigned int)event->pid); 208f08c3bdfSopenharmony_ci goto next_event; 209f08c3bdfSopenharmony_ci } else if (tc->want_pidfd_err && 210f08c3bdfSopenharmony_ci info->pidfd == tc->want_pidfd_err) { 211f08c3bdfSopenharmony_ci tst_res(TPASS, 212f08c3bdfSopenharmony_ci "pid: %u terminated before pidfd was created, " 213f08c3bdfSopenharmony_ci "pidfd set to the value of: %d, as expected", 214f08c3bdfSopenharmony_ci (unsigned int)event->pid, 215f08c3bdfSopenharmony_ci FAN_NOPIDFD); 216f08c3bdfSopenharmony_ci goto next_event; 217f08c3bdfSopenharmony_ci } 218f08c3bdfSopenharmony_ci 219f08c3bdfSopenharmony_ci /* 220f08c3bdfSopenharmony_ci * No pidfd errors occurred, continue with verifying pidfd 221f08c3bdfSopenharmony_ci * fdinfo validity. 222f08c3bdfSopenharmony_ci */ 223f08c3bdfSopenharmony_ci event_pidfd_fdinfo = read_pidfd_fdinfo(info->pidfd); 224f08c3bdfSopenharmony_ci if (event_pidfd_fdinfo == NULL) { 225f08c3bdfSopenharmony_ci tst_brk(TBROK, 226f08c3bdfSopenharmony_ci "reading fdinfo for pidfd: %d " 227f08c3bdfSopenharmony_ci "describing pid: %u failed", 228f08c3bdfSopenharmony_ci info->pidfd, 229f08c3bdfSopenharmony_ci (unsigned int)event->pid); 230f08c3bdfSopenharmony_ci goto next_event; 231f08c3bdfSopenharmony_ci } else if (event_pidfd_fdinfo->pid != event->pid) { 232f08c3bdfSopenharmony_ci tst_res(TFAIL, 233f08c3bdfSopenharmony_ci "pidfd provided for incorrect pid " 234f08c3bdfSopenharmony_ci "(expected pidfd for pid: %u, got pidfd for " 235f08c3bdfSopenharmony_ci "pid: %u)", 236f08c3bdfSopenharmony_ci (unsigned int)event->pid, 237f08c3bdfSopenharmony_ci (unsigned int)event_pidfd_fdinfo->pid); 238f08c3bdfSopenharmony_ci goto next_event; 239f08c3bdfSopenharmony_ci } else if (memcmp(event_pidfd_fdinfo, self_pidfd_fdinfo, 240f08c3bdfSopenharmony_ci sizeof(struct pidfd_fdinfo_t))) { 241f08c3bdfSopenharmony_ci tst_res(TFAIL, 242f08c3bdfSopenharmony_ci "pidfd fdinfo values for self and event differ " 243f08c3bdfSopenharmony_ci "(expected pos: %d, flags: %x, mnt_id: %d, " 244f08c3bdfSopenharmony_ci "pid: %d, ns_pid: %d, got pos: %d, " 245f08c3bdfSopenharmony_ci "flags: %x, mnt_id: %d, pid: %d, ns_pid: %d", 246f08c3bdfSopenharmony_ci self_pidfd_fdinfo->pos, 247f08c3bdfSopenharmony_ci self_pidfd_fdinfo->flags, 248f08c3bdfSopenharmony_ci self_pidfd_fdinfo->mnt_id, 249f08c3bdfSopenharmony_ci self_pidfd_fdinfo->pid, 250f08c3bdfSopenharmony_ci self_pidfd_fdinfo->ns_pid, 251f08c3bdfSopenharmony_ci event_pidfd_fdinfo->pos, 252f08c3bdfSopenharmony_ci event_pidfd_fdinfo->flags, 253f08c3bdfSopenharmony_ci event_pidfd_fdinfo->mnt_id, 254f08c3bdfSopenharmony_ci event_pidfd_fdinfo->pid, 255f08c3bdfSopenharmony_ci event_pidfd_fdinfo->ns_pid); 256f08c3bdfSopenharmony_ci goto next_event; 257f08c3bdfSopenharmony_ci } else { 258f08c3bdfSopenharmony_ci tst_res(TPASS, 259f08c3bdfSopenharmony_ci "got an event with a valid pidfd info record, " 260f08c3bdfSopenharmony_ci "mask: %lld, pid: %u, fd: %d, " 261f08c3bdfSopenharmony_ci "pidfd: %d, info_type: %d, info_len: %d", 262f08c3bdfSopenharmony_ci (unsigned long long)event->mask, 263f08c3bdfSopenharmony_ci (unsigned int)event->pid, 264f08c3bdfSopenharmony_ci event->fd, 265f08c3bdfSopenharmony_ci info->pidfd, 266f08c3bdfSopenharmony_ci info->hdr.info_type, 267f08c3bdfSopenharmony_ci info->hdr.len); 268f08c3bdfSopenharmony_ci } 269f08c3bdfSopenharmony_ci 270f08c3bdfSopenharmony_cinext_event: 271f08c3bdfSopenharmony_ci i += event->event_len; 272f08c3bdfSopenharmony_ci if (event->fd >= 0) 273f08c3bdfSopenharmony_ci SAFE_CLOSE(event->fd); 274f08c3bdfSopenharmony_ci 275f08c3bdfSopenharmony_ci if (info && info->pidfd >= 0) 276f08c3bdfSopenharmony_ci SAFE_CLOSE(info->pidfd); 277f08c3bdfSopenharmony_ci 278f08c3bdfSopenharmony_ci if (event_pidfd_fdinfo) 279f08c3bdfSopenharmony_ci free(event_pidfd_fdinfo); 280f08c3bdfSopenharmony_ci } 281f08c3bdfSopenharmony_ci} 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_cistatic void do_cleanup(void) 284f08c3bdfSopenharmony_ci{ 285f08c3bdfSopenharmony_ci if (fanotify_fd >= 0) 286f08c3bdfSopenharmony_ci SAFE_CLOSE(fanotify_fd); 287f08c3bdfSopenharmony_ci 288f08c3bdfSopenharmony_ci if (self_pidfd_fdinfo) 289f08c3bdfSopenharmony_ci free(self_pidfd_fdinfo); 290f08c3bdfSopenharmony_ci} 291f08c3bdfSopenharmony_ci 292f08c3bdfSopenharmony_cistatic struct tst_test test = { 293f08c3bdfSopenharmony_ci .setup = do_setup, 294f08c3bdfSopenharmony_ci .test = do_test, 295f08c3bdfSopenharmony_ci .tcnt = ARRAY_SIZE(test_cases), 296f08c3bdfSopenharmony_ci .cleanup = do_cleanup, 297f08c3bdfSopenharmony_ci .all_filesystems = 1, 298f08c3bdfSopenharmony_ci .needs_root = 1, 299f08c3bdfSopenharmony_ci .mntpoint = MOUNT_PATH, 300f08c3bdfSopenharmony_ci .forks_child = 1, 301f08c3bdfSopenharmony_ci}; 302f08c3bdfSopenharmony_ci 303f08c3bdfSopenharmony_ci#else 304f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required fanotify support"); 305f08c3bdfSopenharmony_ci#endif /* HAVE_SYS_FANOTIFY_H */ 306