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 
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 
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 
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 
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 
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 
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 
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