1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2012-2020 Linux Test Project. All Rights Reserved.
4 * Author: Jan Kara, November 2013
5 */
6
7 #ifndef __FANOTIFY_H__
8 #define __FANOTIFY_H__
9
10 #include "config.h"
11 #include <sys/statfs.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 #include <sys/fanotify.h>
16 #include "lapi/fcntl.h"
17
safe_fanotify_init(const char * file,const int lineno,unsigned int flags,unsigned int event_f_flags)18 int safe_fanotify_init(const char *file, const int lineno,
19 unsigned int flags, unsigned int event_f_flags)
20 {
21 int rval;
22
23 rval = fanotify_init(flags, event_f_flags);
24
25 if (rval == -1) {
26 if (errno == ENOSYS) {
27 tst_brk_(file, lineno, TCONF,
28 "fanotify is not configured in this kernel");
29 }
30 tst_brk_(file, lineno, TBROK | TERRNO,
31 "%s:%d: fanotify_init() failed", file, lineno);
32 }
33
34 if (rval < -1) {
35 tst_brk_(file, lineno, TBROK | TERRNO,
36 "invalid fanotify_init() return %d", rval);
37 }
38
39 return rval;
40 }
41
safe_fanotify_mark(const char * file,const int lineno,int fd,unsigned int flags,uint64_t mask,int dfd,const char * pathname)42 static inline int safe_fanotify_mark(const char *file, const int lineno,
43 int fd, unsigned int flags, uint64_t mask,
44 int dfd, const char *pathname)
45 {
46 int rval;
47
48 rval = fanotify_mark(fd, flags, mask, dfd, pathname);
49
50 if (rval == -1) {
51 tst_brk_(file, lineno, TBROK | TERRNO, "fanotify_mark() failed");
52 }
53
54 if (rval < -1) {
55 tst_brk_(file, lineno, TBROK | TERRNO,
56 "invalid fanotify_mark() return %d", rval);
57 }
58
59 return rval;
60 }
61
62 #define SAFE_FANOTIFY_MARK(fd, flags, mask, dfd, pathname) \
63 safe_fanotify_mark(__FILE__, __LINE__, (fd), (flags), (mask), (dfd), (pathname))
64
65 #define SAFE_FANOTIFY_INIT(fan, mode) \
66 safe_fanotify_init(__FILE__, __LINE__, (fan), (mode))
67
68 #ifndef FAN_REPORT_TID
69 #define FAN_REPORT_TID 0x00000100
70 #endif
71 #ifndef FAN_REPORT_FID
72 #define FAN_REPORT_FID 0x00000200
73 #endif
74 #ifndef FAN_REPORT_DIR_FID
75 #define FAN_REPORT_DIR_FID 0x00000400
76 #endif
77 #ifndef FAN_REPORT_NAME
78 #define FAN_REPORT_NAME 0x00000800
79 #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME)
80 #endif
81
82 /* Non-uapi convenience macros */
83 #ifndef FAN_REPORT_DFID_NAME_FID
84 #define FAN_REPORT_DFID_NAME_FID (FAN_REPORT_DFID_NAME | FAN_REPORT_FID)
85 #endif
86 #ifndef FAN_REPORT_DFID_FID
87 #define FAN_REPORT_DFID_FID (FAN_REPORT_DIR_FID | FAN_REPORT_FID)
88 #endif
89
90 #ifndef FAN_MARK_INODE
91 #define FAN_MARK_INODE 0
92 #endif
93 #ifndef FAN_MARK_FILESYSTEM
94 #define FAN_MARK_FILESYSTEM 0x00000100
95 #endif
96 /* New dirent event masks */
97 #ifndef FAN_ATTRIB
98 #define FAN_ATTRIB 0x00000004
99 #endif
100 #ifndef FAN_MOVED_FROM
101 #define FAN_MOVED_FROM 0x00000040
102 #endif
103 #ifndef FAN_MOVED_TO
104 #define FAN_MOVED_TO 0x00000080
105 #endif
106 #ifndef FAN_CREATE
107 #define FAN_CREATE 0x00000100
108 #endif
109 #ifndef FAN_DELETE
110 #define FAN_DELETE 0x00000200
111 #endif
112 #ifndef FAN_DELETE_SELF
113 #define FAN_DELETE_SELF 0x00000400
114 #endif
115 #ifndef FAN_MOVE_SELF
116 #define FAN_MOVE_SELF 0x00000800
117 #endif
118 #ifndef FAN_MOVE
119 #define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO)
120 #endif
121 #ifndef FAN_OPEN_EXEC
122 #define FAN_OPEN_EXEC 0x00001000
123 #endif
124 #ifndef FAN_OPEN_EXEC_PERM
125 #define FAN_OPEN_EXEC_PERM 0x00040000
126 #endif
127
128 /* Flags required for unprivileged user group */
129 #define FANOTIFY_REQUIRED_USER_INIT_FLAGS (FAN_REPORT_FID)
130
131 /*
132 * FAN_ALL_PERM_EVENTS has been deprecated, so any new permission events
133 * are not to be added to it. To cover the instance where a new permission
134 * event is defined, we create a new macro that is to include all
135 * permission events. Any new permission events should be added to this
136 * macro.
137 */
138 #define LTP_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \
139 FAN_ACCESS_PERM)
140
141 struct fanotify_group_type {
142 unsigned int flag;
143 const char * name;
144 };
145
146 struct fanotify_mark_type {
147 unsigned int flag;
148 const char * name;
149 };
150
151 #ifndef __kernel_fsid_t
152 typedef struct {
153 int val[2];
154 } lapi_fsid_t;
155 #define __kernel_fsid_t lapi_fsid_t
156 #endif /* __kernel_fsid_t */
157
158 #ifndef FAN_EVENT_INFO_TYPE_FID
159 #define FAN_EVENT_INFO_TYPE_FID 1
160 #endif
161 #ifndef FAN_EVENT_INFO_TYPE_DFID_NAME
162 #define FAN_EVENT_INFO_TYPE_DFID_NAME 2
163 #endif
164 #ifndef FAN_EVENT_INFO_TYPE_DFID
165 #define FAN_EVENT_INFO_TYPE_DFID 3
166 #endif
167
168 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER
169 struct fanotify_event_info_header {
170 uint8_t info_type;
171 uint8_t pad;
172 uint16_t len;
173 };
174 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER */
175
176 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID
177 struct fanotify_event_info_fid {
178 struct fanotify_event_info_header hdr;
179 __kernel_fsid_t fsid;
180 unsigned char handle[0];
181 };
182 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID */
183
184 /* NOTE: only for struct fanotify_event_info_fid */
185 #ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL
186 # define FSID_VAL_MEMBER(fsid, i) (fsid.__val[i])
187 #else
188 # define FSID_VAL_MEMBER(fsid, i) (fsid.val[i])
189 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */
190
191 #ifdef HAVE_NAME_TO_HANDLE_AT
192
193 #ifndef MAX_HANDLE_SZ
194 #define MAX_HANDLE_SZ 128
195 #endif
196
197 /*
198 * Helper function used to obtain fsid and file_handle for a given path.
199 * Used by test files correlated to FAN_REPORT_FID functionality.
200 */
fanotify_get_fid(const char * path,__kernel_fsid_t * fsid,struct file_handle * handle)201 static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid,
202 struct file_handle *handle)
203 {
204 int mount_id;
205 struct statfs stats;
206
207 if (statfs(path, &stats) == -1)
208 tst_brk(TBROK | TERRNO,
209 "statfs(%s, ...) failed", path);
210 memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid));
211
212 if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) {
213 if (errno == EOPNOTSUPP) {
214 tst_brk(TCONF,
215 "filesystem %s does not support file handles",
216 tst_device->fs_type);
217 }
218 tst_brk(TBROK | TERRNO,
219 "name_to_handle_at(AT_FDCWD, %s, ...) failed", path);
220 }
221 }
222
223 struct fanotify_fid_t {
224 __kernel_fsid_t fsid;
225 struct file_handle handle;
226 char buf[MAX_HANDLE_SZ];
227 };
228
fanotify_save_fid(const char * path,struct fanotify_fid_t * fid)229 static inline void fanotify_save_fid(const char *path,
230 struct fanotify_fid_t *fid)
231 {
232 int *fh = (int *)(fid->handle.f_handle);
233
234 fh[0] = fh[1] = fh[2] = 0;
235 fid->handle.handle_bytes = MAX_HANDLE_SZ;
236 fanotify_get_fid(path, &fid->fsid, &fid->handle);
237
238 tst_res(TINFO,
239 "fid(%s) = %x.%x.%x.%x.%x...", path, fid->fsid.val[0],
240 fid->fsid.val[1], fh[0], fh[1], fh[2]);
241 }
242 #endif /* HAVE_NAME_TO_HANDLE_AT */
243
244 #define INIT_FANOTIFY_GROUP_TYPE(t) \
245 { FAN_ ## t, "FAN_" #t }
246
247 #define INIT_FANOTIFY_MARK_TYPE(t) \
248 { FAN_MARK_ ## t, "FAN_MARK_" #t }
249
require_fanotify_access_permissions_supported_by_kernel(void)250 static inline void require_fanotify_access_permissions_supported_by_kernel(void)
251 {
252 int fd;
253
254 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
255
256 if (fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, ".") < 0) {
257 if (errno == EINVAL) {
258 tst_brk(TCONF | TERRNO,
259 "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not configured in kernel?");
260 } else {
261 tst_brk(TBROK | TERRNO,
262 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, \".\") failed", fd);
263 }
264 }
265
266 SAFE_CLOSE(fd);
267 }
268
fanotify_events_supported_by_kernel(uint64_t mask)269 static inline int fanotify_events_supported_by_kernel(uint64_t mask)
270 {
271 int fd;
272 int rval = 0;
273
274 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
275
276 if (fanotify_mark(fd, FAN_MARK_ADD, mask, AT_FDCWD, ".") < 0) {
277 if (errno == EINVAL) {
278 rval = -1;
279 } else {
280 tst_brk(TBROK | TERRNO,
281 "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, \".\") failed", fd);
282 }
283 }
284
285 SAFE_CLOSE(fd);
286
287 return rval;
288 }
289
290 /*
291 * @return 0: fanotify supported both in kernel and on tested filesystem
292 * @return -1: @flags not supported in kernel
293 * @return -2: @flags not supported on tested filesystem (tested if @fname is not NULL)
294 */
fanotify_init_flags_supported_on_fs(unsigned int flags,const char * fname)295 static inline int fanotify_init_flags_supported_on_fs(unsigned int flags, const char *fname)
296 {
297 int fd;
298 int rval = 0;
299
300 fd = fanotify_init(flags, O_RDONLY);
301
302 if (fd < 0) {
303 if (errno == ENOSYS)
304 tst_brk(TCONF, "fanotify not configured in kernel");
305
306 if (errno == EINVAL)
307 return -1;
308
309 tst_brk(TBROK | TERRNO, "fanotify_init() failed");
310 }
311
312 if (fname && fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS, AT_FDCWD, fname) < 0) {
313 if (errno == ENODEV || errno == EOPNOTSUPP || errno == EXDEV) {
314 rval = -2;
315 } else {
316 tst_brk(TBROK | TERRNO,
317 "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, %s) failed",
318 fd, fname);
319 }
320 }
321
322 SAFE_CLOSE(fd);
323
324 return rval;
325 }
326
fanotify_init_flags_supported_by_kernel(unsigned int flags)327 static inline int fanotify_init_flags_supported_by_kernel(unsigned int flags)
328 {
329 return fanotify_init_flags_supported_on_fs(flags, NULL);
330 }
331
332 typedef void (*tst_res_func_t)(const char *file, const int lineno,
333 int ttype, const char *fmt, ...);
334
fanotify_init_flags_err_msg(const char * flags_str,const char * file,const int lineno,tst_res_func_t res_func,int fail)335 static inline void fanotify_init_flags_err_msg(const char *flags_str,
336 const char *file, const int lineno, tst_res_func_t res_func, int fail)
337 {
338 if (fail == -1)
339 res_func(file, lineno, TCONF,
340 "%s not supported in kernel?", flags_str);
341 if (fail == -2)
342 res_func(file, lineno, TCONF,
343 "%s not supported on %s filesystem",
344 flags_str, tst_device->fs_type);
345 }
346
347 #define FANOTIFY_INIT_FLAGS_ERR_MSG(flags, fail) \
348 fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_res_, (fail))
349
350 #define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(flags, fname) do { \
351 fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \
352 fanotify_init_flags_supported_on_fs(flags, fname)); \
353 } while (0)
354
fanotify_mark_supported_by_kernel(uint64_t flag)355 static inline int fanotify_mark_supported_by_kernel(uint64_t flag)
356 {
357 int fd;
358 int rval = 0;
359
360 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
361
362 if (fanotify_mark(fd, FAN_MARK_ADD | flag, FAN_ACCESS, AT_FDCWD, ".") < 0) {
363 if (errno == EINVAL) {
364 rval = -1;
365 } else {
366 tst_brk(TBROK | TERRNO,
367 "fanotify_mark (%d, FAN_MARK_ADD, ..., FAN_ACCESS, AT_FDCWD, \".\") failed", fd);
368 }
369 }
370
371 SAFE_CLOSE(fd);
372
373 return rval;
374 }
375
376 #endif /* __FANOTIFY_H__ */
377