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