• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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