1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (c) 2017 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 that fanotify permission events are handled properly on instance destruction. 11f08c3bdfSopenharmony_ci */ 12f08c3bdfSopenharmony_ci 13f08c3bdfSopenharmony_ci/* 14f08c3bdfSopenharmony_ci * Kernel crashes should be fixed by: 15f08c3bdfSopenharmony_ci * 96d41019e3ac "fanotify: fix list corruption in fanotify_get_response()" 16f08c3bdfSopenharmony_ci * 17f08c3bdfSopenharmony_ci * Kernel hangs should be fixed by: 18f08c3bdfSopenharmony_ci * 05f0e38724e8 "fanotify: Release SRCU lock when waiting for userspace response" 19f08c3bdfSopenharmony_ci */ 20f08c3bdfSopenharmony_ci 21f08c3bdfSopenharmony_ci#define _GNU_SOURCE 22f08c3bdfSopenharmony_ci#include "config.h" 23f08c3bdfSopenharmony_ci 24f08c3bdfSopenharmony_ci#include <stdio.h> 25f08c3bdfSopenharmony_ci#include <unistd.h> 26f08c3bdfSopenharmony_ci#include <stdlib.h> 27f08c3bdfSopenharmony_ci#include <sys/stat.h> 28f08c3bdfSopenharmony_ci#include <sys/types.h> 29f08c3bdfSopenharmony_ci#include <sys/wait.h> 30f08c3bdfSopenharmony_ci#include <errno.h> 31f08c3bdfSopenharmony_ci#include <string.h> 32f08c3bdfSopenharmony_ci#include <signal.h> 33f08c3bdfSopenharmony_ci#include <sys/syscall.h> 34f08c3bdfSopenharmony_ci#include "tst_test.h" 35f08c3bdfSopenharmony_ci#include "lapi/syscalls.h" 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H 38f08c3bdfSopenharmony_ci#include "fanotify.h" 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci#define BUF_SIZE 256 41f08c3bdfSopenharmony_cistatic char fname[BUF_SIZE]; 42f08c3bdfSopenharmony_cistatic char buf[BUF_SIZE]; 43f08c3bdfSopenharmony_cistatic volatile int fd_notify; 44f08c3bdfSopenharmony_ci 45f08c3bdfSopenharmony_ci/* Number of children we start */ 46f08c3bdfSopenharmony_ci#define MAX_CHILDREN 16 47f08c3bdfSopenharmony_cistatic pid_t child_pid[MAX_CHILDREN]; 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci/* Number of children we don't respond to before stopping */ 50f08c3bdfSopenharmony_ci#define MAX_NOT_RESPONDED 4 51f08c3bdfSopenharmony_ci 52f08c3bdfSopenharmony_cistatic void generate_events(void) 53f08c3bdfSopenharmony_ci{ 54f08c3bdfSopenharmony_ci int fd; 55f08c3bdfSopenharmony_ci 56f08c3bdfSopenharmony_ci /* 57f08c3bdfSopenharmony_ci * generate sequence of events 58f08c3bdfSopenharmony_ci */ 59f08c3bdfSopenharmony_ci fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700); 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_ci /* Run until killed... */ 62f08c3bdfSopenharmony_ci while (1) { 63f08c3bdfSopenharmony_ci SAFE_LSEEK(fd, 0, SEEK_SET); 64f08c3bdfSopenharmony_ci SAFE_READ(0, fd, buf, BUF_SIZE); 65f08c3bdfSopenharmony_ci } 66f08c3bdfSopenharmony_ci} 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic void run_children(void) 69f08c3bdfSopenharmony_ci{ 70f08c3bdfSopenharmony_ci int i; 71f08c3bdfSopenharmony_ci 72f08c3bdfSopenharmony_ci for (i = 0; i < MAX_CHILDREN; i++) { 73f08c3bdfSopenharmony_ci child_pid[i] = SAFE_FORK(); 74f08c3bdfSopenharmony_ci if (!child_pid[i]) { 75f08c3bdfSopenharmony_ci /* Child will generate events now */ 76f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 77f08c3bdfSopenharmony_ci generate_events(); 78f08c3bdfSopenharmony_ci exit(0); 79f08c3bdfSopenharmony_ci } 80f08c3bdfSopenharmony_ci } 81f08c3bdfSopenharmony_ci} 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_cistatic int stop_children(void) 84f08c3bdfSopenharmony_ci{ 85f08c3bdfSopenharmony_ci int child_ret; 86f08c3bdfSopenharmony_ci int i, ret = 0; 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci for (i = 0; i < MAX_CHILDREN; i++) { 89f08c3bdfSopenharmony_ci if (!child_pid[i]) 90f08c3bdfSopenharmony_ci continue; 91f08c3bdfSopenharmony_ci 92f08c3bdfSopenharmony_ci SAFE_KILL(child_pid[i], SIGKILL); 93f08c3bdfSopenharmony_ci } 94f08c3bdfSopenharmony_ci 95f08c3bdfSopenharmony_ci for (i = 0; i < MAX_CHILDREN; i++) { 96f08c3bdfSopenharmony_ci if (!child_pid[i]) 97f08c3bdfSopenharmony_ci continue; 98f08c3bdfSopenharmony_ci 99f08c3bdfSopenharmony_ci SAFE_WAITPID(child_pid[i], &child_ret, 0); 100f08c3bdfSopenharmony_ci 101f08c3bdfSopenharmony_ci if (!WIFSIGNALED(child_ret)) 102f08c3bdfSopenharmony_ci ret = 1; 103f08c3bdfSopenharmony_ci 104f08c3bdfSopenharmony_ci child_pid[i] = 0; 105f08c3bdfSopenharmony_ci } 106f08c3bdfSopenharmony_ci 107f08c3bdfSopenharmony_ci return ret; 108f08c3bdfSopenharmony_ci} 109f08c3bdfSopenharmony_ci 110f08c3bdfSopenharmony_cistatic int setup_instance(void) 111f08c3bdfSopenharmony_ci{ 112f08c3bdfSopenharmony_ci int fd; 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY); 115f08c3bdfSopenharmony_ci SAFE_FANOTIFY_MARK(fd, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, fname); 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_ci return fd; 118f08c3bdfSopenharmony_ci} 119f08c3bdfSopenharmony_ci 120f08c3bdfSopenharmony_cistatic void loose_fanotify_events(void) 121f08c3bdfSopenharmony_ci{ 122f08c3bdfSopenharmony_ci int not_responded = 0; 123f08c3bdfSopenharmony_ci 124f08c3bdfSopenharmony_ci /* 125f08c3bdfSopenharmony_ci * check events 126f08c3bdfSopenharmony_ci */ 127f08c3bdfSopenharmony_ci while (not_responded < MAX_NOT_RESPONDED) { 128f08c3bdfSopenharmony_ci struct fanotify_event_metadata event; 129f08c3bdfSopenharmony_ci struct fanotify_response resp; 130f08c3bdfSopenharmony_ci 131f08c3bdfSopenharmony_ci /* Get more events */ 132f08c3bdfSopenharmony_ci SAFE_READ(1, fd_notify, &event, sizeof(event)); 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci if (event.mask != FAN_ACCESS_PERM) { 135f08c3bdfSopenharmony_ci tst_res(TFAIL, 136f08c3bdfSopenharmony_ci "got event: mask=%llx (expected %llx) " 137f08c3bdfSopenharmony_ci "pid=%u fd=%d", 138f08c3bdfSopenharmony_ci (unsigned long long)event.mask, 139f08c3bdfSopenharmony_ci (unsigned long long)FAN_ACCESS_PERM, 140f08c3bdfSopenharmony_ci (unsigned int)event.pid, event.fd); 141f08c3bdfSopenharmony_ci break; 142f08c3bdfSopenharmony_ci } 143f08c3bdfSopenharmony_ci 144f08c3bdfSopenharmony_ci /* We respond to permission event with 95% percent probability. */ 145f08c3bdfSopenharmony_ci if (random() % 100 > 5) { 146f08c3bdfSopenharmony_ci /* Write response to permission event */ 147f08c3bdfSopenharmony_ci resp.fd = event.fd; 148f08c3bdfSopenharmony_ci resp.response = FAN_ALLOW; 149f08c3bdfSopenharmony_ci SAFE_WRITE(SAFE_WRITE_ALL, fd_notify, &resp, sizeof(resp)); 150f08c3bdfSopenharmony_ci } else { 151f08c3bdfSopenharmony_ci not_responded++; 152f08c3bdfSopenharmony_ci } 153f08c3bdfSopenharmony_ci SAFE_CLOSE(event.fd); 154f08c3bdfSopenharmony_ci } 155f08c3bdfSopenharmony_ci} 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_cistatic void test_fanotify(void) 158f08c3bdfSopenharmony_ci{ 159f08c3bdfSopenharmony_ci int newfd; 160f08c3bdfSopenharmony_ci int ret; 161f08c3bdfSopenharmony_ci 162f08c3bdfSopenharmony_ci fd_notify = setup_instance(); 163f08c3bdfSopenharmony_ci run_children(); 164f08c3bdfSopenharmony_ci loose_fanotify_events(); 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci /* 167f08c3bdfSopenharmony_ci * Create and destroy another instance. This may hang if 168f08c3bdfSopenharmony_ci * unanswered fanotify events block notification subsystem. 169f08c3bdfSopenharmony_ci */ 170f08c3bdfSopenharmony_ci newfd = setup_instance(); 171f08c3bdfSopenharmony_ci 172f08c3bdfSopenharmony_ci SAFE_CLOSE(newfd); 173f08c3bdfSopenharmony_ci 174f08c3bdfSopenharmony_ci tst_res(TPASS, "second instance destroyed successfully"); 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci /* 177f08c3bdfSopenharmony_ci * Now destroy the fanotify instance while there are permission 178f08c3bdfSopenharmony_ci * events at various stages of processing. This may provoke 179f08c3bdfSopenharmony_ci * kernel hangs or crashes. 180f08c3bdfSopenharmony_ci */ 181f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 182f08c3bdfSopenharmony_ci 183f08c3bdfSopenharmony_ci ret = stop_children(); 184f08c3bdfSopenharmony_ci if (ret) 185f08c3bdfSopenharmony_ci tst_res(TFAIL, "child exited for unexpected reason"); 186f08c3bdfSopenharmony_ci else 187f08c3bdfSopenharmony_ci tst_res(TPASS, "all children exited successfully"); 188f08c3bdfSopenharmony_ci} 189f08c3bdfSopenharmony_ci 190f08c3bdfSopenharmony_cistatic void setup(void) 191f08c3bdfSopenharmony_ci{ 192f08c3bdfSopenharmony_ci require_fanotify_access_permissions_supported_by_kernel(); 193f08c3bdfSopenharmony_ci 194f08c3bdfSopenharmony_ci sprintf(fname, "fname_%d", getpid()); 195f08c3bdfSopenharmony_ci SAFE_FILE_PRINTF(fname, "%s", fname); 196f08c3bdfSopenharmony_ci} 197f08c3bdfSopenharmony_ci 198f08c3bdfSopenharmony_cistatic void cleanup(void) 199f08c3bdfSopenharmony_ci{ 200f08c3bdfSopenharmony_ci stop_children(); 201f08c3bdfSopenharmony_ci 202f08c3bdfSopenharmony_ci if (fd_notify > 0) 203f08c3bdfSopenharmony_ci SAFE_CLOSE(fd_notify); 204f08c3bdfSopenharmony_ci} 205f08c3bdfSopenharmony_ci 206f08c3bdfSopenharmony_cistatic struct tst_test test = { 207f08c3bdfSopenharmony_ci .test_all = test_fanotify, 208f08c3bdfSopenharmony_ci .setup = setup, 209f08c3bdfSopenharmony_ci .cleanup = cleanup, 210f08c3bdfSopenharmony_ci .needs_tmpdir = 1, 211f08c3bdfSopenharmony_ci .forks_child = 1, 212f08c3bdfSopenharmony_ci .needs_root = 1, 213f08c3bdfSopenharmony_ci}; 214f08c3bdfSopenharmony_ci 215f08c3bdfSopenharmony_ci#else 216f08c3bdfSopenharmony_ci TST_TEST_TCONF("system doesn't have required fanotify support"); 217f08c3bdfSopenharmony_ci#endif 218