1 /*
2 * Copyright (c) 2013 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 of the GNU General Public License as
6 * 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 work
27 */
28 #define _GNU_SOURCE
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/wait.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <signal.h>
40 #include <sys/syscall.h>
41 #include <stdlib.h>
42 #include "tst_test.h"
43 #include "fanotify.h"
44
45 #if defined(HAVE_SYS_FANOTIFY_H)
46 #include <sys/fanotify.h>
47
48 #define EVENT_MAX 1024
49 /* size of the event structure, not counting name */
50 #define EVENT_SIZE (sizeof (struct fanotify_event_metadata))
51 /* reasonable guess as to size of 1024 events */
52 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
53
54 #define BUF_SIZE 256
55 #define TST_TOTAL 3
56
57 static char fname[BUF_SIZE];
58 static char buf[BUF_SIZE];
59 static volatile int fd_notify;
60
61 static pid_t child_pid;
62
63 static unsigned long long event_set[EVENT_MAX];
64 static unsigned int event_resp[EVENT_MAX];
65
66 static char event_buf[EVENT_BUF_LEN];
67
generate_events(void)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 if (write(fd, fname, 1) == -1)
78 exit(2);
79
80 lseek(fd, 0, SEEK_SET);
81 if (read(fd, buf, BUF_SIZE) != -1)
82 exit(3);
83
84 if (close(fd) == -1)
85 exit(4);
86 }
87
child_handler(int tmp)88 static void child_handler(int tmp)
89 {
90 (void)tmp;
91 /*
92 * Close notification fd so that we cannot block while reading
93 * from it
94 */
95 close(fd_notify);
96 fd_notify = -1;
97 }
98
run_child(void)99 static void run_child(void)
100 {
101 struct sigaction child_action;
102
103 child_action.sa_handler = child_handler;
104 sigemptyset(&child_action.sa_mask);
105 child_action.sa_flags = SA_NOCLDSTOP;
106
107 if (sigaction(SIGCHLD, &child_action, NULL) < 0) {
108 tst_brk(TBROK | TERRNO,
109 "sigaction(SIGCHLD, &child_action, NULL) failed");
110 }
111
112 child_pid = SAFE_FORK();
113 if (child_pid == 0) {
114 /* Child will generate events now */
115 close(fd_notify);
116 generate_events();
117 exit(0);
118 }
119 }
120
check_child(void)121 static void check_child(void)
122 {
123 struct sigaction child_action;
124 int child_ret;
125
126 child_action.sa_handler = SIG_IGN;
127 sigemptyset(&child_action.sa_mask);
128 child_action.sa_flags = SA_NOCLDSTOP;
129 if (sigaction(SIGCHLD, &child_action, NULL) < 0) {
130 tst_brk(TBROK | TERRNO,
131 "sigaction(SIGCHLD, &child_action, NULL) failed");
132 }
133 SAFE_WAITPID(-1, &child_ret, 0);
134
135 if (WIFEXITED(child_ret) && WEXITSTATUS(child_ret) == 0)
136 tst_res(TPASS, "child exited correctly");
137 else
138 tst_res(TFAIL, "child %s", tst_strstatus(child_ret));
139 }
140
test01(void)141 void test01(void)
142 {
143 int tst_count, fd_notify_backup = -1;
144
145 int ret, len = 0, i = 0, test_num = 0;
146
147 if (fd_notify_backup == -1) {
148 fd_notify_backup = SAFE_DUP(fd_notify);
149 }
150 run_child();
151
152 tst_count = 0;
153
154 event_set[tst_count] = FAN_OPEN_PERM;
155 event_resp[tst_count++] = FAN_ALLOW;
156 event_set[tst_count] = FAN_ACCESS_PERM;
157 event_resp[tst_count++] = FAN_DENY;
158
159 /* tst_count + 1 is for checking child return value */
160 if (TST_TOTAL != tst_count + 1) {
161 tst_brk(TBROK,
162 "TST_TOTAL and tst_count do not match");
163 }
164 tst_count = 0;
165
166 /*
167 * check events
168 */
169 while (test_num < TST_TOTAL && fd_notify != -1) {
170 struct fanotify_event_metadata *event;
171
172 if (i == len) {
173 /* Get more events */
174 ret = read(fd_notify, event_buf + len,
175 EVENT_BUF_LEN - len);
176 if (fd_notify == -1)
177 break;
178 if (ret < 0) {
179 tst_brk(TBROK,
180 "read(%d, buf, %zu) failed",
181 fd_notify, EVENT_BUF_LEN);
182 }
183 len += ret;
184 }
185
186 event = (struct fanotify_event_metadata *)&event_buf[i];
187 if (!(event->mask & event_set[test_num])) {
188 tst_res(TFAIL,
189 "get event: mask=%llx (expected %llx) "
190 "pid=%u fd=%u",
191 (unsigned long long)event->mask,
192 event_set[test_num],
193 (unsigned)event->pid, event->fd);
194 } else if (event->pid != child_pid) {
195 tst_res(TFAIL,
196 "get event: mask=%llx pid=%u "
197 "(expected %u) fd=%u",
198 (unsigned long long)event->mask,
199 (unsigned)event->pid,
200 (unsigned)child_pid,
201 event->fd);
202 } else {
203 tst_res(TPASS,
204 "get event: mask=%llx pid=%u fd=%u",
205 (unsigned long long)event->mask,
206 (unsigned)event->pid, event->fd);
207 }
208 /* Write response to permission event */
209 if (event_set[test_num] & FAN_ALL_PERM_EVENTS) {
210 struct fanotify_response resp;
211
212 resp.fd = event->fd;
213 resp.response = event_resp[test_num];
214 SAFE_WRITE(1, fd_notify, &resp,
215 sizeof(resp));
216 }
217 event->mask &= ~event_set[test_num];
218 /* No events left in current mask? Go for next event */
219 if (event->mask == 0) {
220 i += event->event_len;
221 close(event->fd);
222 }
223 test_num++;
224 }
225 for (; test_num < TST_TOTAL - 1; test_num++) {
226 tst_res(TFAIL, "didn't get event: mask=%llx",
227 event_set[test_num]);
228
229 }
230 check_child();
231 /* We got SIGCHLD while running, resetup fd_notify */
232 if (fd_notify == -1) {
233 fd_notify = fd_notify_backup;
234 fd_notify_backup = -1;
235 }
236 }
237
setup(void)238 static void setup(void)
239 {
240 int fd;
241
242 sprintf(fname, "fname_%d", getpid());
243 fd = SAFE_OPEN(fname, O_CREAT | O_RDWR, 0644);
244 SAFE_WRITE(1, fd, fname, 1);
245 SAFE_CLOSE(fd);
246
247 fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
248
249 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM |
250 FAN_OPEN_PERM, AT_FDCWD, fname) < 0) {
251 if (errno == EINVAL) {
252 tst_brk(TCONF | TERRNO,
253 "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not "
254 "configured in kernel?");
255 } else {
256 tst_brk(TBROK | TERRNO,
257 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | "
258 "FAN_OPEN_PERM, AT_FDCWD, %s) failed.", fd_notify, fname);
259 }
260 }
261
262 }
263
cleanup(void)264 static void cleanup(void)
265 {
266 if (fd_notify > 0)
267 SAFE_CLOSE(fd_notify);
268 }
269
270 static struct tst_test test = {
271 .test_all = test01,
272 .setup = setup,
273 .cleanup = cleanup,
274 .needs_tmpdir = 1,
275 .forks_child = 1,
276 .needs_root = 1
277 };
278
279 #else
280 TST_TEST_TCONF("system doesn't have required fanotify support");
281 #endif
282