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 #ifndef FAN_REPORT_PIDFD
82 #define FAN_REPORT_PIDFD 0x00000080
83 #endif
84
85 /* Non-uapi convenience macros */
86 #ifndef FAN_REPORT_DFID_NAME_FID
87 #define FAN_REPORT_DFID_NAME_FID (FAN_REPORT_DFID_NAME | FAN_REPORT_FID)
88 #endif
89 #ifndef FAN_REPORT_DFID_FID
90 #define FAN_REPORT_DFID_FID (FAN_REPORT_DIR_FID | FAN_REPORT_FID)
91 #endif
92
93 #ifndef FAN_MARK_INODE
94 #define FAN_MARK_INODE 0
95 #endif
96 #ifndef FAN_MARK_FILESYSTEM
97 #define FAN_MARK_FILESYSTEM 0x00000100
98 #endif
99 /* New dirent event masks */
100 #ifndef FAN_ATTRIB
101 #define FAN_ATTRIB 0x00000004
102 #endif
103 #ifndef FAN_MOVED_FROM
104 #define FAN_MOVED_FROM 0x00000040
105 #endif
106 #ifndef FAN_MOVED_TO
107 #define FAN_MOVED_TO 0x00000080
108 #endif
109 #ifndef FAN_CREATE
110 #define FAN_CREATE 0x00000100
111 #endif
112 #ifndef FAN_DELETE
113 #define FAN_DELETE 0x00000200
114 #endif
115 #ifndef FAN_DELETE_SELF
116 #define FAN_DELETE_SELF 0x00000400
117 #endif
118 #ifndef FAN_MOVE_SELF
119 #define FAN_MOVE_SELF 0x00000800
120 #endif
121 #ifndef FAN_MOVE
122 #define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO)
123 #endif
124 #ifndef FAN_OPEN_EXEC
125 #define FAN_OPEN_EXEC 0x00001000
126 #endif
127 #ifndef FAN_OPEN_EXEC_PERM
128 #define FAN_OPEN_EXEC_PERM 0x00040000
129 #endif
130 #ifndef FAN_FS_ERROR
131 #define FAN_FS_ERROR 0x00008000
132 #endif
133
134 /* Additional error status codes that can be returned to userspace */
135 #ifndef FAN_NOPIDFD
136 #define FAN_NOPIDFD -1
137 #endif
138 #ifndef FAN_EPIDFD
139 #define FAN_EPIDFD -2
140 #endif
141
142 /* Flags required for unprivileged user group */
143 #define FANOTIFY_REQUIRED_USER_INIT_FLAGS (FAN_REPORT_FID)
144
145 /*
146 * FAN_ALL_PERM_EVENTS has been deprecated, so any new permission events
147 * are not to be added to it. To cover the instance where a new permission
148 * event is defined, we create a new macro that is to include all
149 * permission events. Any new permission events should be added to this
150 * macro.
151 */
152 #define LTP_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \
153 FAN_ACCESS_PERM)
154
155 struct fanotify_group_type {
156 unsigned int flag;
157 const char * name;
158 };
159
160 struct fanotify_mark_type {
161 unsigned int flag;
162 const char * name;
163 };
164
165 #ifndef __kernel_fsid_t
166 typedef struct {
167 int val[2];
168 } lapi_fsid_t;
169 #define __kernel_fsid_t lapi_fsid_t
170 #endif /* __kernel_fsid_t */
171
172 #ifndef FAN_EVENT_INFO_TYPE_FID
173 #define FAN_EVENT_INFO_TYPE_FID 1
174 #endif
175 #ifndef FAN_EVENT_INFO_TYPE_DFID_NAME
176 #define FAN_EVENT_INFO_TYPE_DFID_NAME 2
177 #endif
178 #ifndef FAN_EVENT_INFO_TYPE_DFID
179 #define FAN_EVENT_INFO_TYPE_DFID 3
180 #endif
181 #ifndef FAN_EVENT_INFO_TYPE_PIDFD
182 #define FAN_EVENT_INFO_TYPE_PIDFD 4
183 #endif
184 #ifndef FAN_EVENT_INFO_TYPE_ERROR
185 #define FAN_EVENT_INFO_TYPE_ERROR 5
186 #endif
187
188 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER
189 struct fanotify_event_info_header {
190 uint8_t info_type;
191 uint8_t pad;
192 uint16_t len;
193 };
194 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER */
195
196 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID
197 struct fanotify_event_info_fid {
198 struct fanotify_event_info_header hdr;
199 __kernel_fsid_t fsid;
200 unsigned char handle[0];
201 };
202 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID */
203
204 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD
205 struct fanotify_event_info_pidfd {
206 struct fanotify_event_info_header hdr;
207 int32_t pidfd;
208 };
209 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD */
210
211 #ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR
212 struct fanotify_event_info_error {
213 struct fanotify_event_info_header hdr;
214 __s32 error;
215 __u32 error_count;
216 };
217 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR */
218
219 /* NOTE: only for struct fanotify_event_info_fid */
220 #ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL
221 # define FSID_VAL_MEMBER(fsid, i) (fsid.__val[i])
222 #else
223 # define FSID_VAL_MEMBER(fsid, i) (fsid.val[i])
224 #endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */
225
226 #ifdef HAVE_NAME_TO_HANDLE_AT
227
228 #ifndef MAX_HANDLE_SZ
229 #define MAX_HANDLE_SZ 128
230 #endif
231
232 /*
233 * Helper function used to obtain fsid and file_handle for a given path.
234 * Used by test files correlated to FAN_REPORT_FID functionality.
235 */
fanotify_get_fid(const char * path,__kernel_fsid_t * fsid,struct file_handle * handle)236 static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid,
237 struct file_handle *handle)
238 {
239 int mount_id;
240 struct statfs stats;
241
242 if (statfs(path, &stats) == -1)
243 tst_brk(TBROK | TERRNO,
244 "statfs(%s, ...) failed", path);
245 memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid));
246
247 if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) {
248 if (errno == EOPNOTSUPP) {
249 tst_brk(TCONF,
250 "filesystem %s does not support file handles",
251 tst_device->fs_type);
252 }
253 tst_brk(TBROK | TERRNO,
254 "name_to_handle_at(AT_FDCWD, %s, ...) failed", path);
255 }
256 }
257
258 #ifndef FILEID_INVALID
259 #define FILEID_INVALID 0xff
260 #endif
261
262 struct fanotify_fid_t {
263 __kernel_fsid_t fsid;
264 struct file_handle handle;
265 char buf[MAX_HANDLE_SZ];
266 };
267
fanotify_save_fid(const char * path,struct fanotify_fid_t * fid)268 static inline void fanotify_save_fid(const char *path,
269 struct fanotify_fid_t *fid)
270 {
271 int *fh = (int *)(fid->handle.f_handle);
272
273 fh[0] = fh[1] = fh[2] = 0;
274 fid->handle.handle_bytes = MAX_HANDLE_SZ;
275 fanotify_get_fid(path, &fid->fsid, &fid->handle);
276
277 tst_res(TINFO,
278 "fid(%s) = %x.%x.%x.%x.%x...", path, fid->fsid.val[0],
279 fid->fsid.val[1], fh[0], fh[1], fh[2]);
280 }
281 #endif /* HAVE_NAME_TO_HANDLE_AT */
282
283 #define INIT_FANOTIFY_GROUP_TYPE(t) \
284 { FAN_ ## t, "FAN_" #t }
285
286 #define INIT_FANOTIFY_MARK_TYPE(t) \
287 { FAN_MARK_ ## t, "FAN_MARK_" #t }
288
require_fanotify_access_permissions_supported_by_kernel(void)289 static inline void require_fanotify_access_permissions_supported_by_kernel(void)
290 {
291 int fd;
292
293 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
294
295 if (fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, ".") < 0) {
296 if (errno == EINVAL) {
297 tst_brk(TCONF | TERRNO,
298 "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not configured in kernel?");
299 } else {
300 tst_brk(TBROK | TERRNO,
301 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM, AT_FDCWD, \".\") failed", fd);
302 }
303 }
304
305 SAFE_CLOSE(fd);
306 }
307
fanotify_events_supported_by_kernel(uint64_t mask,unsigned int init_flags,unsigned int mark_flags)308 static inline int fanotify_events_supported_by_kernel(uint64_t mask,
309 unsigned int init_flags,
310 unsigned int mark_flags)
311 {
312 int fd;
313 int rval = 0;
314
315 fd = SAFE_FANOTIFY_INIT(init_flags, O_RDONLY);
316
317 if (fanotify_mark(fd, FAN_MARK_ADD | mark_flags, mask, AT_FDCWD, ".") < 0) {
318 if (errno == EINVAL) {
319 rval = -1;
320 } else {
321 tst_brk(TBROK | TERRNO,
322 "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, \".\") failed", fd);
323 }
324 }
325
326 SAFE_CLOSE(fd);
327
328 return rval;
329 }
330
331 /*
332 * @return 0: fanotify supported both in kernel and on tested filesystem
333 * @return -1: @flags not supported in kernel
334 * @return -2: @flags not supported on tested filesystem (tested if @fname is not NULL)
335 */
fanotify_init_flags_supported_on_fs(unsigned int flags,const char * fname)336 static inline int fanotify_init_flags_supported_on_fs(unsigned int flags, const char *fname)
337 {
338 int fd;
339 int rval = 0;
340
341 fd = fanotify_init(flags, O_RDONLY);
342
343 if (fd < 0) {
344 if (errno == ENOSYS)
345 tst_brk(TCONF, "fanotify not configured in kernel");
346
347 if (errno == EINVAL)
348 return -1;
349
350 tst_brk(TBROK | TERRNO, "fanotify_init() failed");
351 }
352
353 if (fname && fanotify_mark(fd, FAN_MARK_ADD, FAN_ACCESS, AT_FDCWD, fname) < 0) {
354 if (errno == ENODEV || errno == EOPNOTSUPP || errno == EXDEV) {
355 rval = -2;
356 } else {
357 tst_brk(TBROK | TERRNO,
358 "fanotify_mark (%d, FAN_MARK_ADD, ..., AT_FDCWD, %s) failed",
359 fd, fname);
360 }
361 }
362
363 SAFE_CLOSE(fd);
364
365 return rval;
366 }
367
fanotify_init_flags_supported_by_kernel(unsigned int flags)368 static inline int fanotify_init_flags_supported_by_kernel(unsigned int flags)
369 {
370 return fanotify_init_flags_supported_on_fs(flags, NULL);
371 }
372
373 typedef void (*tst_res_func_t)(const char *file, const int lineno,
374 int ttype, const char *fmt, ...);
375
fanotify_init_flags_err_msg(const char * flags_str,const char * file,const int lineno,tst_res_func_t res_func,int fail)376 static inline void fanotify_init_flags_err_msg(const char *flags_str,
377 const char *file, const int lineno, tst_res_func_t res_func, int fail)
378 {
379 if (fail == -1)
380 res_func(file, lineno, TCONF,
381 "%s not supported in kernel?", flags_str);
382 if (fail == -2)
383 res_func(file, lineno, TCONF,
384 "%s not supported on %s filesystem",
385 flags_str, tst_device->fs_type);
386 }
387
388 #define FANOTIFY_INIT_FLAGS_ERR_MSG(flags, fail) \
389 fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_res_, (fail))
390
391 #define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(flags, fname) do { \
392 fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \
393 fanotify_init_flags_supported_on_fs(flags, fname)); \
394 } while (0)
395
396 #define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(flags) do { \
397 fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \
398 fanotify_init_flags_supported_by_kernel(flags)); \
399 } while (0)
400
fanotify_mark_supported_by_kernel(uint64_t flag)401 static inline int fanotify_mark_supported_by_kernel(uint64_t flag)
402 {
403 int fd;
404 int rval = 0;
405
406 fd = SAFE_FANOTIFY_INIT(FAN_CLASS_CONTENT, O_RDONLY);
407
408 if (fanotify_mark(fd, FAN_MARK_ADD | flag, FAN_ACCESS, AT_FDCWD, ".") < 0) {
409 if (errno == EINVAL) {
410 rval = -1;
411 } else {
412 tst_brk(TBROK | TERRNO,
413 "fanotify_mark (%d, FAN_MARK_ADD, ..., FAN_ACCESS, AT_FDCWD, \".\") failed", fd);
414 }
415 }
416
417 SAFE_CLOSE(fd);
418
419 return rval;
420 }
421
422 #define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) do { \
423 fanotify_init_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \
424 fanotify_mark_supported_by_kernel(mark_type)); \
425 } while (0)
426
427 #define REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(init_flags, mark_type, mask, fname) do { \
428 if (mark_type) \
429 REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type); \
430 if (init_flags) \
431 REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(init_flags, fname); \
432 fanotify_init_flags_err_msg(#mask, __FILE__, __LINE__, tst_brk_, \
433 fanotify_events_supported_by_kernel(mask, init_flags, mark_type)); \
434 } while (0)
435
get_event_info(struct fanotify_event_metadata * event,int info_type)436 struct fanotify_event_info_header *get_event_info(
437 struct fanotify_event_metadata *event,
438 int info_type)
439 {
440 struct fanotify_event_info_header *hdr = NULL;
441 char *start = (char *) event;
442 int off;
443
444 for (off = event->metadata_len; (off+sizeof(*hdr)) < event->event_len;
445 off += hdr->len) {
446 hdr = (struct fanotify_event_info_header *) &(start[off]);
447 if (hdr->info_type == info_type)
448 return hdr;
449 }
450 return NULL;
451 }
452
453 #define get_event_info_error(event) \
454 ((struct fanotify_event_info_error *) \
455 get_event_info((event), FAN_EVENT_INFO_TYPE_ERROR))
456
457 #define get_event_info_fid(event) \
458 ((struct fanotify_event_info_fid *) \
459 get_event_info((event), FAN_EVENT_INFO_TYPE_FID))
460
461 #endif /* __FANOTIFY_H__ */
462