blob: 1ab8798438d6ee386665ed7270d7a89248456b6a [file] [log] [blame]
Jan Karaf057c1c2013-11-20 23:43:13 +01001/*
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 */
Waldemar Brodkorbdd9240e2016-03-05 09:54:10 +010028#define _GNU_SOURCE
Jan Karaf057c1c2013-11-20 23:43:13 +010029#include "config.h"
30
31#include <stdio.h>
32#include <unistd.h>
33#include <sys/stat.h>
34#include <sys/types.h>
Steven Jacksona7fa85612016-12-13 15:10:28 +000035#include <fcntl.h>
Jan Karaf057c1c2013-11-20 23:43:13 +010036#include <sys/wait.h>
37#include <errno.h>
38#include <string.h>
39#include <signal.h>
40#include <sys/syscall.h>
Xiong Zhou9964e882017-08-16 15:15:36 +080041#include <stdlib.h>
42#include "tst_test.h"
Jan Karaf057c1c2013-11-20 23:43:13 +010043#include "fanotify.h"
Jan Karaf057c1c2013-11-20 23:43:13 +010044
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
Jan Karaf057c1c2013-11-20 23:43:13 +010054#define BUF_SIZE 256
Xiong Zhou9964e882017-08-16 15:15:36 +080055#define TST_TOTAL 3
56
Jan Karaf057c1c2013-11-20 23:43:13 +010057static char fname[BUF_SIZE];
58static char buf[BUF_SIZE];
59static volatile int fd_notify;
60
61static pid_t child_pid;
62
63static unsigned long long event_set[EVENT_MAX];
64static unsigned int event_resp[EVENT_MAX];
65
66static char event_buf[EVENT_BUF_LEN];
67
68static 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
88static void child_handler(int tmp)
89{
Xiong Zhou9964e882017-08-16 15:15:36 +080090 (void)tmp;
Jan Karaf057c1c2013-11-20 23:43:13 +010091 /*
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
99static 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) {
Xiong Zhou9964e882017-08-16 15:15:36 +0800108 tst_brk(TBROK | TERRNO,
Jan Karaf057c1c2013-11-20 23:43:13 +0100109 "sigaction(SIGCHLD, &child_action, NULL) failed");
110 }
111
Xiong Zhou9964e882017-08-16 15:15:36 +0800112 child_pid = SAFE_FORK();
113 if (child_pid == 0) {
Jan Karaf057c1c2013-11-20 23:43:13 +0100114 /* Child will generate events now */
115 close(fd_notify);
116 generate_events();
117 exit(0);
Jan Karaf057c1c2013-11-20 23:43:13 +0100118 }
119}
120
121static 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) {
Xiong Zhou9964e882017-08-16 15:15:36 +0800130 tst_brk(TBROK | TERRNO,
Jan Karaf057c1c2013-11-20 23:43:13 +0100131 "sigaction(SIGCHLD, &child_action, NULL) failed");
132 }
Cyril Hrubis66374d52017-10-03 13:46:52 +0200133 SAFE_WAITPID(-1, &child_ret, 0);
Jan Karaf057c1c2013-11-20 23:43:13 +0100134
135 if (WIFSIGNALED(child_ret)) {
Xiong Zhou9964e882017-08-16 15:15:36 +0800136 tst_res(TFAIL, "child exited due to signal %d",
Jan Karaf057c1c2013-11-20 23:43:13 +0100137 WTERMSIG(child_ret));
138 } else if (WIFEXITED(child_ret)) {
139 if (WEXITSTATUS(child_ret) == 0)
Xiong Zhou9964e882017-08-16 15:15:36 +0800140 tst_res(TPASS, "child exited correctly");
Jan Karaf057c1c2013-11-20 23:43:13 +0100141 else
Xiong Zhou9964e882017-08-16 15:15:36 +0800142 tst_res(TFAIL, "child exited with status %d",
Jan Karaf057c1c2013-11-20 23:43:13 +0100143 WEXITSTATUS(child_ret));
144 } else {
Xiong Zhou9964e882017-08-16 15:15:36 +0800145 tst_res(TFAIL, "child exited for unknown reason (status %d)",
Jan Karaf057c1c2013-11-20 23:43:13 +0100146 child_ret);
147 }
148}
149
Xiong Zhou9964e882017-08-16 15:15:36 +0800150void test01(void)
Jan Karaf057c1c2013-11-20 23:43:13 +0100151{
Xiong Zhou9964e882017-08-16 15:15:36 +0800152 int tst_count, fd_notify_backup = -1;
Jan Karaf057c1c2013-11-20 23:43:13 +0100153
Xiong Zhou9964e882017-08-16 15:15:36 +0800154 int ret, len = 0, i = 0, test_num = 0;
Jan Karaf057c1c2013-11-20 23:43:13 +0100155
Xiong Zhou9964e882017-08-16 15:15:36 +0800156 if (fd_notify_backup == -1) {
157 fd_notify_backup = dup(fd_notify);
158 if (fd_notify_backup < 0)
159 tst_brk(TBROK | TERRNO,
160 "dup(%d) failed", fd_notify);
Jan Karaf057c1c2013-11-20 23:43:13 +0100161 }
Xiong Zhou9964e882017-08-16 15:15:36 +0800162 run_child();
Jan Karaf057c1c2013-11-20 23:43:13 +0100163
Xiong Zhou9964e882017-08-16 15:15:36 +0800164 tst_count = 0;
165
166 event_set[tst_count] = FAN_OPEN_PERM;
167 event_resp[tst_count++] = FAN_ALLOW;
168 event_set[tst_count] = FAN_ACCESS_PERM;
169 event_resp[tst_count++] = FAN_DENY;
170
171 /* tst_count + 1 is for checking child return value */
172 if (TST_TOTAL != tst_count + 1) {
173 tst_brk(TBROK,
174 "TST_TOTAL and tst_count do not match");
175 }
176 tst_count = 0;
177
178 /*
179 * check events
180 */
181 while (test_num < TST_TOTAL && fd_notify != -1) {
182 struct fanotify_event_metadata *event;
183
184 if (i == len) {
185 /* Get more events */
186 ret = read(fd_notify, event_buf + len,
187 EVENT_BUF_LEN - len);
188 if (fd_notify == -1)
189 break;
190 if (ret < 0) {
191 tst_brk(TBROK,
192 "read(%d, buf, %zu) failed",
193 fd_notify, EVENT_BUF_LEN);
194 }
195 len += ret;
196 }
197
198 event = (struct fanotify_event_metadata *)&event_buf[i];
199 if (!(event->mask & event_set[test_num])) {
200 tst_res(TFAIL,
201 "get event: mask=%llx (expected %llx) "
202 "pid=%u fd=%u",
203 (unsigned long long)event->mask,
204 event_set[test_num],
205 (unsigned)event->pid, event->fd);
206 } else if (event->pid != child_pid) {
207 tst_res(TFAIL,
208 "get event: mask=%llx pid=%u "
209 "(expected %u) fd=%u",
210 (unsigned long long)event->mask,
211 (unsigned)event->pid,
212 (unsigned)child_pid,
213 event->fd);
214 } else {
215 tst_res(TPASS,
216 "get event: mask=%llx pid=%u fd=%u",
217 (unsigned long long)event->mask,
218 (unsigned)event->pid, event->fd);
219 }
220 /* Write response to permission event */
221 if (event_set[test_num] & FAN_ALL_PERM_EVENTS) {
222 struct fanotify_response resp;
223
224 resp.fd = event->fd;
225 resp.response = event_resp[test_num];
226 SAFE_WRITE(1, fd_notify, &resp,
227 sizeof(resp));
228 }
229 event->mask &= ~event_set[test_num];
230 /* No events left in current mask? Go for next event */
231 if (event->mask == 0) {
232 i += event->event_len;
233 close(event->fd);
234 }
235 test_num++;
236 }
237 for (; test_num < TST_TOTAL - 1; test_num++) {
238 tst_res(TFAIL, "didn't get event: mask=%llx",
239 event_set[test_num]);
240
241 }
242 check_child();
243 /* We got SIGCHLD while running, resetup fd_notify */
244 if (fd_notify == -1) {
245 fd_notify = fd_notify_backup;
246 fd_notify_backup = -1;
247 }
Jan Karaf057c1c2013-11-20 23:43:13 +0100248}
249
250static void setup(void)
251{
252 int fd;
253
Jan Karaf057c1c2013-11-20 23:43:13 +0100254 sprintf(fname, "fname_%d", getpid());
Xiong Zhou9964e882017-08-16 15:15:36 +0800255 fd = SAFE_OPEN(fname, O_CREAT | O_RDWR, 0644);
256 SAFE_WRITE(1, fd, fname, 1);
257 SAFE_CLOSE(fd);
Jan Karaf057c1c2013-11-20 23:43:13 +0100258
Xiong Zhou9964e882017-08-16 15:15:36 +0800259 fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
Jan Karaf057c1c2013-11-20 23:43:13 +0100260
Helge Dellerff964762014-07-29 18:10:40 +0200261 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM |
Jan Karaf057c1c2013-11-20 23:43:13 +0100262 FAN_OPEN_PERM, AT_FDCWD, fname) < 0) {
Helge Dellerff964762014-07-29 18:10:40 +0200263 if (errno == EINVAL) {
Xiong Zhou9964e882017-08-16 15:15:36 +0800264 tst_brk(TCONF | TERRNO,
Helge Dellerff964762014-07-29 18:10:40 +0200265 "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not "
266 "configured in kernel?");
267 } else {
Xiong Zhou9964e882017-08-16 15:15:36 +0800268 tst_brk(TBROK | TERRNO,
Helge Dellerff964762014-07-29 18:10:40 +0200269 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | "
270 "FAN_OPEN_PERM, AT_FDCWD, %s) failed.", fd_notify, fname);
271 }
Jan Karaf057c1c2013-11-20 23:43:13 +0100272 }
273
274}
275
276static void cleanup(void)
277{
Xiong Zhou9964e882017-08-16 15:15:36 +0800278 if (fd_notify > 0)
279 SAFE_CLOSE(fd_notify);
Jan Karaf057c1c2013-11-20 23:43:13 +0100280}
281
Xiong Zhou9964e882017-08-16 15:15:36 +0800282static struct tst_test test = {
283 .test_all = test01,
284 .setup = setup,
285 .cleanup = cleanup,
286 .needs_tmpdir = 1,
Xiao Liang761577a2017-08-21 13:07:19 +0800287 .forks_child = 1,
Xiong Zhou9964e882017-08-16 15:15:36 +0800288 .needs_root = 1
289};
290
Jan Karaf057c1c2013-11-20 23:43:13 +0100291#else
Xiong Zhou9964e882017-08-16 15:15:36 +0800292 TST_TEST_TCONF("system doesn't have required fanotify support");
Jan Karaf057c1c2013-11-20 23:43:13 +0100293#endif