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