xref: /openbmc/linux/fs/notify/fanotify/fanotify_user.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
233d3dfffSAndreas Gruenbacher #include <linux/fanotify.h>
311637e4bSEric Paris #include <linux/fcntl.h>
4af579bebSMatthew Bobrowski #include <linux/fdtable.h>
52a3edf86SEric Paris #include <linux/file.h>
611637e4bSEric Paris #include <linux/fs.h>
752c923ddSEric Paris #include <linux/anon_inodes.h>
811637e4bSEric Paris #include <linux/fsnotify_backend.h>
92a3edf86SEric Paris #include <linux/init.h>
10a1014f10SEric Paris #include <linux/mount.h>
112a3edf86SEric Paris #include <linux/namei.h>
12a1014f10SEric Paris #include <linux/poll.h>
1311637e4bSEric Paris #include <linux/security.h>
1411637e4bSEric Paris #include <linux/syscalls.h>
15e4e047a2STejun Heo #include <linux/slab.h>
162a3edf86SEric Paris #include <linux/types.h>
17a1014f10SEric Paris #include <linux/uaccess.h>
1891c2e0bcSAl Viro #include <linux/compat.h>
19174cd4b1SIngo Molnar #include <linux/sched/signal.h>
20d46eb14bSShakeel Butt #include <linux/memcontrol.h>
21a8b13aa2SAmir Goldstein #include <linux/statfs.h>
22a8b13aa2SAmir Goldstein #include <linux/exportfs.h>
23a1014f10SEric Paris 
24a1014f10SEric Paris #include <asm/ioctls.h>
2511637e4bSEric Paris 
26c63181e6SAl Viro #include "../../mount.h"
27be77196bSCyrill Gorcunov #include "../fdinfo.h"
287053aee2SJan Kara #include "fanotify.h"
29c63181e6SAl Viro 
302529a0dfSEric Paris #define FANOTIFY_DEFAULT_MAX_EVENTS	16384
315b8fea65SAmir Goldstein #define FANOTIFY_OLD_DEFAULT_MAX_MARKS	8192
325b8fea65SAmir Goldstein #define FANOTIFY_DEFAULT_MAX_GROUPS	128
33734a1a5eSGabriel Krisman Bertazi #define FANOTIFY_DEFAULT_FEE_POOL_SIZE	32
345b8fea65SAmir Goldstein 
355b8fea65SAmir Goldstein /*
365b8fea65SAmir Goldstein  * Legacy fanotify marks limits (8192) is per group and we introduced a tunable
375b8fea65SAmir Goldstein  * limit of marks per user, similar to inotify.  Effectively, the legacy limit
385b8fea65SAmir Goldstein  * of fanotify marks per user is <max marks per group> * <max groups per user>.
395b8fea65SAmir Goldstein  * This default limit (1M) also happens to match the increased limit of inotify
405b8fea65SAmir Goldstein  * max_user_watches since v5.10.
415b8fea65SAmir Goldstein  */
425b8fea65SAmir Goldstein #define FANOTIFY_DEFAULT_MAX_USER_MARKS	\
435b8fea65SAmir Goldstein 	(FANOTIFY_OLD_DEFAULT_MAX_MARKS * FANOTIFY_DEFAULT_MAX_GROUPS)
445b8fea65SAmir Goldstein 
455b8fea65SAmir Goldstein /*
465b8fea65SAmir Goldstein  * Most of the memory cost of adding an inode mark is pinning the marked inode.
475b8fea65SAmir Goldstein  * The size of the filesystem inode struct is not uniform across filesystems,
485b8fea65SAmir Goldstein  * so double the size of a VFS inode is used as a conservative approximation.
495b8fea65SAmir Goldstein  */
505b8fea65SAmir Goldstein #define INODE_MARK_COST	(2 * sizeof(struct inode))
515b8fea65SAmir Goldstein 
525b8fea65SAmir Goldstein /* configurable via /proc/sys/fs/fanotify/ */
535b8fea65SAmir Goldstein static int fanotify_max_queued_events __read_mostly;
545b8fea65SAmir Goldstein 
555b8fea65SAmir Goldstein #ifdef CONFIG_SYSCTL
565b8fea65SAmir Goldstein 
575b8fea65SAmir Goldstein #include <linux/sysctl.h>
585b8fea65SAmir Goldstein 
59f153c224SSven Schnelle static long ft_zero = 0;
60f153c224SSven Schnelle static long ft_int_max = INT_MAX;
61f153c224SSven Schnelle 
627b9ad122SXiaoming Ni static struct ctl_table fanotify_table[] = {
635b8fea65SAmir Goldstein 	{
645b8fea65SAmir Goldstein 		.procname	= "max_user_groups",
655b8fea65SAmir Goldstein 		.data	= &init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS],
66f153c224SSven Schnelle 		.maxlen		= sizeof(long),
675b8fea65SAmir Goldstein 		.mode		= 0644,
68f153c224SSven Schnelle 		.proc_handler	= proc_doulongvec_minmax,
69f153c224SSven Schnelle 		.extra1		= &ft_zero,
70f153c224SSven Schnelle 		.extra2		= &ft_int_max,
715b8fea65SAmir Goldstein 	},
725b8fea65SAmir Goldstein 	{
735b8fea65SAmir Goldstein 		.procname	= "max_user_marks",
745b8fea65SAmir Goldstein 		.data	= &init_user_ns.ucount_max[UCOUNT_FANOTIFY_MARKS],
75f153c224SSven Schnelle 		.maxlen		= sizeof(long),
765b8fea65SAmir Goldstein 		.mode		= 0644,
77f153c224SSven Schnelle 		.proc_handler	= proc_doulongvec_minmax,
78f153c224SSven Schnelle 		.extra1		= &ft_zero,
79f153c224SSven Schnelle 		.extra2		= &ft_int_max,
805b8fea65SAmir Goldstein 	},
815b8fea65SAmir Goldstein 	{
825b8fea65SAmir Goldstein 		.procname	= "max_queued_events",
835b8fea65SAmir Goldstein 		.data		= &fanotify_max_queued_events,
845b8fea65SAmir Goldstein 		.maxlen		= sizeof(int),
855b8fea65SAmir Goldstein 		.mode		= 0644,
865b8fea65SAmir Goldstein 		.proc_handler	= proc_dointvec_minmax,
875b8fea65SAmir Goldstein 		.extra1		= SYSCTL_ZERO
885b8fea65SAmir Goldstein 	},
895b8fea65SAmir Goldstein 	{ }
905b8fea65SAmir Goldstein };
917b9ad122SXiaoming Ni 
fanotify_sysctls_init(void)927b9ad122SXiaoming Ni static void __init fanotify_sysctls_init(void)
937b9ad122SXiaoming Ni {
947b9ad122SXiaoming Ni 	register_sysctl("fs/fanotify", fanotify_table);
957b9ad122SXiaoming Ni }
967b9ad122SXiaoming Ni #else
977b9ad122SXiaoming Ni #define fanotify_sysctls_init() do { } while (0)
985b8fea65SAmir Goldstein #endif /* CONFIG_SYSCTL */
992529a0dfSEric Paris 
10048149e9dSHeinrich Schuchardt /*
10148149e9dSHeinrich Schuchardt  * All flags that may be specified in parameter event_f_flags of fanotify_init.
10248149e9dSHeinrich Schuchardt  *
10348149e9dSHeinrich Schuchardt  * Internal and external open flags are stored together in field f_flags of
10448149e9dSHeinrich Schuchardt  * struct file. Only external open flags shall be allowed in event_f_flags.
10548149e9dSHeinrich Schuchardt  * Internal flags like FMODE_NONOTIFY, FMODE_EXEC, FMODE_NOCMTIME shall be
10648149e9dSHeinrich Schuchardt  * excluded.
10748149e9dSHeinrich Schuchardt  */
10848149e9dSHeinrich Schuchardt #define	FANOTIFY_INIT_ALL_EVENT_F_BITS				( \
10948149e9dSHeinrich Schuchardt 		O_ACCMODE	| O_APPEND	| O_NONBLOCK	| \
11048149e9dSHeinrich Schuchardt 		__O_SYNC	| O_DSYNC	| O_CLOEXEC     | \
11148149e9dSHeinrich Schuchardt 		O_LARGEFILE	| O_NOATIME	)
11248149e9dSHeinrich Schuchardt 
11333d3dfffSAndreas Gruenbacher extern const struct fsnotify_ops fanotify_fsnotify_ops;
11411637e4bSEric Paris 
115054c636eSJan Kara struct kmem_cache *fanotify_mark_cache __read_mostly;
1167088f357SJan Kara struct kmem_cache *fanotify_fid_event_cachep __read_mostly;
1177088f357SJan Kara struct kmem_cache *fanotify_path_event_cachep __read_mostly;
118f083441bSJan Kara struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
1192a3edf86SEric Paris 
1205e469c83SAmir Goldstein #define FANOTIFY_EVENT_ALIGN 4
121d3424c9bSMatthew Bobrowski #define FANOTIFY_FID_INFO_HDR_LEN \
12244d705b0SAmir Goldstein 	(sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle))
123af579bebSMatthew Bobrowski #define FANOTIFY_PIDFD_INFO_HDR_LEN \
124af579bebSMatthew Bobrowski 	sizeof(struct fanotify_event_info_pidfd)
125130a3c74SGabriel Krisman Bertazi #define FANOTIFY_ERROR_INFO_LEN \
126130a3c74SGabriel Krisman Bertazi 	(sizeof(struct fanotify_event_info_error))
1275e469c83SAmir Goldstein 
fanotify_fid_info_len(int fh_len,int name_len)12844d705b0SAmir Goldstein static int fanotify_fid_info_len(int fh_len, int name_len)
129d766b553SAmir Goldstein {
13044d705b0SAmir Goldstein 	int info_len = fh_len;
13144d705b0SAmir Goldstein 
13244d705b0SAmir Goldstein 	if (name_len)
13344d705b0SAmir Goldstein 		info_len += name_len + 1;
13444d705b0SAmir Goldstein 
135d3424c9bSMatthew Bobrowski 	return roundup(FANOTIFY_FID_INFO_HDR_LEN + info_len,
136d3424c9bSMatthew Bobrowski 		       FANOTIFY_EVENT_ALIGN);
137d766b553SAmir Goldstein }
138d766b553SAmir Goldstein 
1397326e382SAmir Goldstein /* FAN_RENAME may have one or two dir+name info records */
fanotify_dir_name_info_len(struct fanotify_event * event)1407326e382SAmir Goldstein static int fanotify_dir_name_info_len(struct fanotify_event *event)
1417326e382SAmir Goldstein {
1427326e382SAmir Goldstein 	struct fanotify_info *info = fanotify_event_info(event);
1437326e382SAmir Goldstein 	int dir_fh_len = fanotify_event_dir_fh_len(event);
1447326e382SAmir Goldstein 	int dir2_fh_len = fanotify_event_dir2_fh_len(event);
1457326e382SAmir Goldstein 	int info_len = 0;
1467326e382SAmir Goldstein 
1477326e382SAmir Goldstein 	if (dir_fh_len)
1487326e382SAmir Goldstein 		info_len += fanotify_fid_info_len(dir_fh_len,
1497326e382SAmir Goldstein 						  info->name_len);
1507326e382SAmir Goldstein 	if (dir2_fh_len)
1517326e382SAmir Goldstein 		info_len += fanotify_fid_info_len(dir2_fh_len,
1527326e382SAmir Goldstein 						  info->name2_len);
1537326e382SAmir Goldstein 
1547326e382SAmir Goldstein 	return info_len;
1557326e382SAmir Goldstein }
1567326e382SAmir Goldstein 
fanotify_event_len(unsigned int info_mode,struct fanotify_event * event)157b9928e80SGabriel Krisman Bertazi static size_t fanotify_event_len(unsigned int info_mode,
158929943b3SAmir Goldstein 				 struct fanotify_event *event)
1595e469c83SAmir Goldstein {
160b9928e80SGabriel Krisman Bertazi 	size_t event_len = FAN_EVENT_METADATA_LEN;
161b9928e80SGabriel Krisman Bertazi 	int fh_len;
162929943b3SAmir Goldstein 	int dot_len = 0;
163f454fa61SAmir Goldstein 
164b9928e80SGabriel Krisman Bertazi 	if (!info_mode)
165b9928e80SGabriel Krisman Bertazi 		return event_len;
166b9928e80SGabriel Krisman Bertazi 
167130a3c74SGabriel Krisman Bertazi 	if (fanotify_is_error_event(event->mask))
168130a3c74SGabriel Krisman Bertazi 		event_len += FANOTIFY_ERROR_INFO_LEN;
169130a3c74SGabriel Krisman Bertazi 
1707326e382SAmir Goldstein 	if (fanotify_event_has_any_dir_fh(event)) {
1717326e382SAmir Goldstein 		event_len += fanotify_dir_name_info_len(event);
172d3424c9bSMatthew Bobrowski 	} else if ((info_mode & FAN_REPORT_NAME) &&
173d3424c9bSMatthew Bobrowski 		   (event->mask & FAN_ONDIR)) {
174929943b3SAmir Goldstein 		/*
175929943b3SAmir Goldstein 		 * With group flag FAN_REPORT_NAME, if name was not recorded in
176929943b3SAmir Goldstein 		 * event on a directory, we will report the name ".".
177929943b3SAmir Goldstein 		 */
178929943b3SAmir Goldstein 		dot_len = 1;
179929943b3SAmir Goldstein 	}
180afc894c7SJan Kara 
181af579bebSMatthew Bobrowski 	if (info_mode & FAN_REPORT_PIDFD)
182b9928e80SGabriel Krisman Bertazi 		event_len += FANOTIFY_PIDFD_INFO_HDR_LEN;
183af579bebSMatthew Bobrowski 
1844bd5a5c8SGabriel Krisman Bertazi 	if (fanotify_event_has_object_fh(event)) {
1854bd5a5c8SGabriel Krisman Bertazi 		fh_len = fanotify_event_object_fh_len(event);
186b9928e80SGabriel Krisman Bertazi 		event_len += fanotify_fid_info_len(fh_len, dot_len);
1874bd5a5c8SGabriel Krisman Bertazi 	}
1885e469c83SAmir Goldstein 
189b9928e80SGabriel Krisman Bertazi 	return event_len;
1905e469c83SAmir Goldstein }
1915e469c83SAmir Goldstein 
192a1014f10SEric Paris /*
19394e00d28SAmir Goldstein  * Remove an hashed event from merge hash table.
19494e00d28SAmir Goldstein  */
fanotify_unhash_event(struct fsnotify_group * group,struct fanotify_event * event)19594e00d28SAmir Goldstein static void fanotify_unhash_event(struct fsnotify_group *group,
19694e00d28SAmir Goldstein 				  struct fanotify_event *event)
19794e00d28SAmir Goldstein {
19894e00d28SAmir Goldstein 	assert_spin_locked(&group->notification_lock);
19994e00d28SAmir Goldstein 
20094e00d28SAmir Goldstein 	pr_debug("%s: group=%p event=%p bucket=%u\n", __func__,
20194e00d28SAmir Goldstein 		 group, event, fanotify_event_hash_bucket(group, event));
20294e00d28SAmir Goldstein 
20394e00d28SAmir Goldstein 	if (WARN_ON_ONCE(hlist_unhashed(&event->merge_list)))
20494e00d28SAmir Goldstein 		return;
20594e00d28SAmir Goldstein 
20694e00d28SAmir Goldstein 	hlist_del_init(&event->merge_list);
20794e00d28SAmir Goldstein }
20894e00d28SAmir Goldstein 
20994e00d28SAmir Goldstein /*
2107088f357SJan Kara  * Get an fanotify notification event if one exists and is small
211a1014f10SEric Paris  * enough to fit in "count". Return an error pointer if the count
21240873284SJan Kara  * is not large enough. When permission event is dequeued, its state is
21340873284SJan Kara  * updated accordingly.
214a1014f10SEric Paris  */
get_one_event(struct fsnotify_group * group,size_t count)2157088f357SJan Kara static struct fanotify_event *get_one_event(struct fsnotify_group *group,
216a1014f10SEric Paris 					    size_t count)
217a1014f10SEric Paris {
218b9928e80SGabriel Krisman Bertazi 	size_t event_size;
2197088f357SJan Kara 	struct fanotify_event *event = NULL;
2206f73171eSAmir Goldstein 	struct fsnotify_event *fsn_event;
2210aca67bbSMatthew Bobrowski 	unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES);
222a1014f10SEric Paris 
223a1014f10SEric Paris 	pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
224a1014f10SEric Paris 
2258c554466SJan Kara 	spin_lock(&group->notification_lock);
2266f73171eSAmir Goldstein 	fsn_event = fsnotify_peek_first_event(group);
2276f73171eSAmir Goldstein 	if (!fsn_event)
2288c554466SJan Kara 		goto out;
229a1014f10SEric Paris 
2306f73171eSAmir Goldstein 	event = FANOTIFY_E(fsn_event);
231b9928e80SGabriel Krisman Bertazi 	event_size = fanotify_event_len(info_mode, event);
2325e469c83SAmir Goldstein 
2338c554466SJan Kara 	if (event_size > count) {
2347088f357SJan Kara 		event = ERR_PTR(-EINVAL);
2358c554466SJan Kara 		goto out;
2368c554466SJan Kara 	}
2376f73171eSAmir Goldstein 
2386f73171eSAmir Goldstein 	/*
2396f73171eSAmir Goldstein 	 * Held the notification_lock the whole time, so this is the
2406f73171eSAmir Goldstein 	 * same event we peeked above.
2416f73171eSAmir Goldstein 	 */
2426f73171eSAmir Goldstein 	fsnotify_remove_first_event(group);
2437088f357SJan Kara 	if (fanotify_is_perm_event(event->mask))
2447088f357SJan Kara 		FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED;
24594e00d28SAmir Goldstein 	if (fanotify_is_hashed_event(event->mask))
24694e00d28SAmir Goldstein 		fanotify_unhash_event(group, event);
2478c554466SJan Kara out:
2488c554466SJan Kara 	spin_unlock(&group->notification_lock);
2497088f357SJan Kara 	return event;
250a1014f10SEric Paris }
251a1014f10SEric Paris 
create_fd(struct fsnotify_group * group,const struct path * path,struct file ** file)252d5bf8889SAl Viro static int create_fd(struct fsnotify_group *group, const struct path *path,
253352e3b24SAl Viro 		     struct file **file)
254a1014f10SEric Paris {
255a1014f10SEric Paris 	int client_fd;
256a1014f10SEric Paris 	struct file *new_file;
257a1014f10SEric Paris 
2580b37e097SYann Droneaud 	client_fd = get_unused_fd_flags(group->fanotify_data.f_flags);
259a1014f10SEric Paris 	if (client_fd < 0)
260a1014f10SEric Paris 		return client_fd;
261a1014f10SEric Paris 
262a1014f10SEric Paris 	/*
263a1014f10SEric Paris 	 * we need a new file handle for the userspace program so it can read even if it was
264a1014f10SEric Paris 	 * originally opened O_WRONLY.
265a1014f10SEric Paris 	 */
266a741c2feSJan Kara 	new_file = dentry_open(path,
267dccd8557SVasily Averin 			       group->fanotify_data.f_flags | __FMODE_NONOTIFY,
268a1014f10SEric Paris 			       current_cred());
269a1014f10SEric Paris 	if (IS_ERR(new_file)) {
270a1014f10SEric Paris 		put_unused_fd(client_fd);
271a1014f10SEric Paris 		client_fd = PTR_ERR(new_file);
272a1014f10SEric Paris 	} else {
273352e3b24SAl Viro 		*file = new_file;
274a1014f10SEric Paris 	}
275a1014f10SEric Paris 
27622aa425dSAndreas Gruenbacher 	return client_fd;
277a1014f10SEric Paris }
278a1014f10SEric Paris 
process_access_response_info(const char __user * info,size_t info_len,struct fanotify_response_info_audit_rule * friar)27970529a19SRichard Guy Briggs static int process_access_response_info(const char __user *info,
28070529a19SRichard Guy Briggs 					size_t info_len,
28170529a19SRichard Guy Briggs 				struct fanotify_response_info_audit_rule *friar)
28270529a19SRichard Guy Briggs {
28370529a19SRichard Guy Briggs 	if (info_len != sizeof(*friar))
28470529a19SRichard Guy Briggs 		return -EINVAL;
28570529a19SRichard Guy Briggs 
28670529a19SRichard Guy Briggs 	if (copy_from_user(friar, info, sizeof(*friar)))
28770529a19SRichard Guy Briggs 		return -EFAULT;
28870529a19SRichard Guy Briggs 
28970529a19SRichard Guy Briggs 	if (friar->hdr.type != FAN_RESPONSE_INFO_AUDIT_RULE)
29070529a19SRichard Guy Briggs 		return -EINVAL;
29170529a19SRichard Guy Briggs 	if (friar->hdr.pad != 0)
29270529a19SRichard Guy Briggs 		return -EINVAL;
29370529a19SRichard Guy Briggs 	if (friar->hdr.len != sizeof(*friar))
29470529a19SRichard Guy Briggs 		return -EINVAL;
29570529a19SRichard Guy Briggs 
29670529a19SRichard Guy Briggs 	return info_len;
29770529a19SRichard Guy Briggs }
29870529a19SRichard Guy Briggs 
29940873284SJan Kara /*
30040873284SJan Kara  * Finish processing of permission event by setting it to ANSWERED state and
30140873284SJan Kara  * drop group->notification_lock.
30240873284SJan Kara  */
finish_permission_event(struct fsnotify_group * group,struct fanotify_perm_event * event,u32 response,struct fanotify_response_info_audit_rule * friar)30340873284SJan Kara static void finish_permission_event(struct fsnotify_group *group,
30470529a19SRichard Guy Briggs 				    struct fanotify_perm_event *event, u32 response,
30570529a19SRichard Guy Briggs 				    struct fanotify_response_info_audit_rule *friar)
30640873284SJan Kara 				    __releases(&group->notification_lock)
30740873284SJan Kara {
308fabf7f29SJan Kara 	bool destroy = false;
309fabf7f29SJan Kara 
31040873284SJan Kara 	assert_spin_locked(&group->notification_lock);
31170529a19SRichard Guy Briggs 	event->response = response & ~FAN_INFO;
31270529a19SRichard Guy Briggs 	if (response & FAN_INFO)
31370529a19SRichard Guy Briggs 		memcpy(&event->audit_rule, friar, sizeof(*friar));
31470529a19SRichard Guy Briggs 
315fabf7f29SJan Kara 	if (event->state == FAN_EVENT_CANCELED)
316fabf7f29SJan Kara 		destroy = true;
317fabf7f29SJan Kara 	else
31840873284SJan Kara 		event->state = FAN_EVENT_ANSWERED;
31940873284SJan Kara 	spin_unlock(&group->notification_lock);
320fabf7f29SJan Kara 	if (destroy)
321fabf7f29SJan Kara 		fsnotify_destroy_event(group, &event->fae.fse);
32240873284SJan Kara }
32340873284SJan Kara 
process_access_response(struct fsnotify_group * group,struct fanotify_response * response_struct,const char __user * info,size_t info_len)324b2d87909SEric Paris static int process_access_response(struct fsnotify_group *group,
32570529a19SRichard Guy Briggs 				   struct fanotify_response *response_struct,
32670529a19SRichard Guy Briggs 				   const char __user *info,
32770529a19SRichard Guy Briggs 				   size_t info_len)
328b2d87909SEric Paris {
32933913997SAmir Goldstein 	struct fanotify_perm_event *event;
330f083441bSJan Kara 	int fd = response_struct->fd;
3312e0a5471SRichard Guy Briggs 	u32 response = response_struct->response;
33270529a19SRichard Guy Briggs 	int ret = info_len;
33370529a19SRichard Guy Briggs 	struct fanotify_response_info_audit_rule friar;
334b2d87909SEric Paris 
33570529a19SRichard Guy Briggs 	pr_debug("%s: group=%p fd=%d response=%u buf=%p size=%zu\n", __func__,
33670529a19SRichard Guy Briggs 		 group, fd, response, info, info_len);
337b2d87909SEric Paris 	/*
338b2d87909SEric Paris 	 * make sure the response is valid, if invalid we do nothing and either
33925985edcSLucas De Marchi 	 * userspace can send a valid response or we will clean it up after the
340b2d87909SEric Paris 	 * timeout
341b2d87909SEric Paris 	 */
34270529a19SRichard Guy Briggs 	if (response & ~FANOTIFY_RESPONSE_VALID_MASK)
34370529a19SRichard Guy Briggs 		return -EINVAL;
34470529a19SRichard Guy Briggs 
34570529a19SRichard Guy Briggs 	switch (response & FANOTIFY_RESPONSE_ACCESS) {
346b2d87909SEric Paris 	case FAN_ALLOW:
347b2d87909SEric Paris 	case FAN_DENY:
348b2d87909SEric Paris 		break;
349b2d87909SEric Paris 	default:
350b2d87909SEric Paris 		return -EINVAL;
351b2d87909SEric Paris 	}
352b2d87909SEric Paris 
35370529a19SRichard Guy Briggs 	if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
354b2d87909SEric Paris 		return -EINVAL;
355b2d87909SEric Paris 
35670529a19SRichard Guy Briggs 	if (response & FAN_INFO) {
35770529a19SRichard Guy Briggs 		ret = process_access_response_info(info, info_len, &friar);
35870529a19SRichard Guy Briggs 		if (ret < 0)
35970529a19SRichard Guy Briggs 			return ret;
36070529a19SRichard Guy Briggs 		if (fd == FAN_NOFD)
36170529a19SRichard Guy Briggs 			return ret;
36270529a19SRichard Guy Briggs 	} else {
36370529a19SRichard Guy Briggs 		ret = 0;
36470529a19SRichard Guy Briggs 	}
36570529a19SRichard Guy Briggs 
36670529a19SRichard Guy Briggs 	if (fd < 0)
367de8cd83eSSteve Grubb 		return -EINVAL;
368de8cd83eSSteve Grubb 
369af6a5113SJan Kara 	spin_lock(&group->notification_lock);
370af6a5113SJan Kara 	list_for_each_entry(event, &group->fanotify_data.access_list,
371af6a5113SJan Kara 			    fae.fse.list) {
372af6a5113SJan Kara 		if (event->fd != fd)
373af6a5113SJan Kara 			continue;
374b2d87909SEric Paris 
375af6a5113SJan Kara 		list_del_init(&event->fae.fse.list);
37670529a19SRichard Guy Briggs 		finish_permission_event(group, event, response, &friar);
377b2d87909SEric Paris 		wake_up(&group->fanotify_data.access_waitq);
37870529a19SRichard Guy Briggs 		return ret;
379b2d87909SEric Paris 	}
380af6a5113SJan Kara 	spin_unlock(&group->notification_lock);
381af6a5113SJan Kara 
382af6a5113SJan Kara 	return -ENOENT;
383af6a5113SJan Kara }
384b2d87909SEric Paris 
copy_error_info_to_user(struct fanotify_event * event,char __user * buf,int count)385130a3c74SGabriel Krisman Bertazi static size_t copy_error_info_to_user(struct fanotify_event *event,
386130a3c74SGabriel Krisman Bertazi 				      char __user *buf, int count)
387130a3c74SGabriel Krisman Bertazi {
3883cf984e9SAmir Goldstein 	struct fanotify_event_info_error info = { };
389130a3c74SGabriel Krisman Bertazi 	struct fanotify_error_event *fee = FANOTIFY_EE(event);
390130a3c74SGabriel Krisman Bertazi 
391130a3c74SGabriel Krisman Bertazi 	info.hdr.info_type = FAN_EVENT_INFO_TYPE_ERROR;
392130a3c74SGabriel Krisman Bertazi 	info.hdr.len = FANOTIFY_ERROR_INFO_LEN;
393130a3c74SGabriel Krisman Bertazi 
394130a3c74SGabriel Krisman Bertazi 	if (WARN_ON(count < info.hdr.len))
395130a3c74SGabriel Krisman Bertazi 		return -EFAULT;
396130a3c74SGabriel Krisman Bertazi 
397130a3c74SGabriel Krisman Bertazi 	info.error = fee->error;
398130a3c74SGabriel Krisman Bertazi 	info.error_count = fee->err_count;
399130a3c74SGabriel Krisman Bertazi 
400130a3c74SGabriel Krisman Bertazi 	if (copy_to_user(buf, &info, sizeof(info)))
401130a3c74SGabriel Krisman Bertazi 		return -EFAULT;
402130a3c74SGabriel Krisman Bertazi 
403130a3c74SGabriel Krisman Bertazi 	return info.hdr.len;
404130a3c74SGabriel Krisman Bertazi }
405130a3c74SGabriel Krisman Bertazi 
copy_fid_info_to_user(__kernel_fsid_t * fsid,struct fanotify_fh * fh,int info_type,const char * name,size_t name_len,char __user * buf,size_t count)406d3424c9bSMatthew Bobrowski static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
407d3424c9bSMatthew Bobrowski 				 int info_type, const char *name,
408d3424c9bSMatthew Bobrowski 				 size_t name_len,
40944d705b0SAmir Goldstein 				 char __user *buf, size_t count)
4105e469c83SAmir Goldstein {
4115e469c83SAmir Goldstein 	struct fanotify_event_info_fid info = { };
4125e469c83SAmir Goldstein 	struct file_handle handle = { };
413afc894c7SJan Kara 	unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh_buf;
414cacfb956SAmir Goldstein 	size_t fh_len = fh ? fh->len : 0;
41544d705b0SAmir Goldstein 	size_t info_len = fanotify_fid_info_len(fh_len, name_len);
41644d705b0SAmir Goldstein 	size_t len = info_len;
4175e469c83SAmir Goldstein 
41844d705b0SAmir Goldstein 	pr_debug("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n",
41944d705b0SAmir Goldstein 		 __func__, fh_len, name_len, info_len, count);
42044d705b0SAmir Goldstein 
42144d705b0SAmir Goldstein 	if (WARN_ON_ONCE(len < sizeof(info) || len > count))
4225e469c83SAmir Goldstein 		return -EFAULT;
4235e469c83SAmir Goldstein 
42444d705b0SAmir Goldstein 	/*
42544d705b0SAmir Goldstein 	 * Copy event info fid header followed by variable sized file handle
42644d705b0SAmir Goldstein 	 * and optionally followed by variable sized filename.
42744d705b0SAmir Goldstein 	 */
42883b7a598SAmir Goldstein 	switch (info_type) {
42983b7a598SAmir Goldstein 	case FAN_EVENT_INFO_TYPE_FID:
43083b7a598SAmir Goldstein 	case FAN_EVENT_INFO_TYPE_DFID:
43183b7a598SAmir Goldstein 		if (WARN_ON_ONCE(name_len))
43283b7a598SAmir Goldstein 			return -EFAULT;
43383b7a598SAmir Goldstein 		break;
43483b7a598SAmir Goldstein 	case FAN_EVENT_INFO_TYPE_DFID_NAME:
4357326e382SAmir Goldstein 	case FAN_EVENT_INFO_TYPE_OLD_DFID_NAME:
4367326e382SAmir Goldstein 	case FAN_EVENT_INFO_TYPE_NEW_DFID_NAME:
43783b7a598SAmir Goldstein 		if (WARN_ON_ONCE(!name || !name_len))
43883b7a598SAmir Goldstein 			return -EFAULT;
43983b7a598SAmir Goldstein 		break;
44083b7a598SAmir Goldstein 	default:
44183b7a598SAmir Goldstein 		return -EFAULT;
44283b7a598SAmir Goldstein 	}
44383b7a598SAmir Goldstein 
44483b7a598SAmir Goldstein 	info.hdr.info_type = info_type;
4455e469c83SAmir Goldstein 	info.hdr.len = len;
446d766b553SAmir Goldstein 	info.fsid = *fsid;
4475e469c83SAmir Goldstein 	if (copy_to_user(buf, &info, sizeof(info)))
4485e469c83SAmir Goldstein 		return -EFAULT;
4495e469c83SAmir Goldstein 
4505e469c83SAmir Goldstein 	buf += sizeof(info);
4515e469c83SAmir Goldstein 	len -= sizeof(info);
45244d705b0SAmir Goldstein 	if (WARN_ON_ONCE(len < sizeof(handle)))
45344d705b0SAmir Goldstein 		return -EFAULT;
45444d705b0SAmir Goldstein 
455afc894c7SJan Kara 	handle.handle_type = fh->type;
4565e469c83SAmir Goldstein 	handle.handle_bytes = fh_len;
457936d6a38SGabriel Krisman Bertazi 
458936d6a38SGabriel Krisman Bertazi 	/* Mangle handle_type for bad file_handle */
459936d6a38SGabriel Krisman Bertazi 	if (!fh_len)
460936d6a38SGabriel Krisman Bertazi 		handle.handle_type = FILEID_INVALID;
461936d6a38SGabriel Krisman Bertazi 
4625e469c83SAmir Goldstein 	if (copy_to_user(buf, &handle, sizeof(handle)))
4635e469c83SAmir Goldstein 		return -EFAULT;
4645e469c83SAmir Goldstein 
4655e469c83SAmir Goldstein 	buf += sizeof(handle);
4665e469c83SAmir Goldstein 	len -= sizeof(handle);
46744d705b0SAmir Goldstein 	if (WARN_ON_ONCE(len < fh_len))
46844d705b0SAmir Goldstein 		return -EFAULT;
46944d705b0SAmir Goldstein 
470b2d22b6bSJan Kara 	/*
47144d705b0SAmir Goldstein 	 * For an inline fh and inline file name, copy through stack to exclude
47244d705b0SAmir Goldstein 	 * the copy from usercopy hardening protections.
473b2d22b6bSJan Kara 	 */
474afc894c7SJan Kara 	fh_buf = fanotify_fh_buf(fh);
475b2d22b6bSJan Kara 	if (fh_len <= FANOTIFY_INLINE_FH_LEN) {
476afc894c7SJan Kara 		memcpy(bounce, fh_buf, fh_len);
477afc894c7SJan Kara 		fh_buf = bounce;
478b2d22b6bSJan Kara 	}
479afc894c7SJan Kara 	if (copy_to_user(buf, fh_buf, fh_len))
4805e469c83SAmir Goldstein 		return -EFAULT;
4815e469c83SAmir Goldstein 
4825e469c83SAmir Goldstein 	buf += fh_len;
4835e469c83SAmir Goldstein 	len -= fh_len;
48444d705b0SAmir Goldstein 
48544d705b0SAmir Goldstein 	if (name_len) {
48644d705b0SAmir Goldstein 		/* Copy the filename with terminating null */
48744d705b0SAmir Goldstein 		name_len++;
48844d705b0SAmir Goldstein 		if (WARN_ON_ONCE(len < name_len))
48944d705b0SAmir Goldstein 			return -EFAULT;
49044d705b0SAmir Goldstein 
49144d705b0SAmir Goldstein 		if (copy_to_user(buf, name, name_len))
49244d705b0SAmir Goldstein 			return -EFAULT;
49344d705b0SAmir Goldstein 
49444d705b0SAmir Goldstein 		buf += name_len;
49544d705b0SAmir Goldstein 		len -= name_len;
49644d705b0SAmir Goldstein 	}
49744d705b0SAmir Goldstein 
49844d705b0SAmir Goldstein 	/* Pad with 0's */
4995e469c83SAmir Goldstein 	WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
5005e469c83SAmir Goldstein 	if (len > 0 && clear_user(buf, len))
5015e469c83SAmir Goldstein 		return -EFAULT;
5025e469c83SAmir Goldstein 
50344d705b0SAmir Goldstein 	return info_len;
5045e469c83SAmir Goldstein }
5055e469c83SAmir Goldstein 
copy_pidfd_info_to_user(int pidfd,char __user * buf,size_t count)506af579bebSMatthew Bobrowski static int copy_pidfd_info_to_user(int pidfd,
507af579bebSMatthew Bobrowski 				   char __user *buf,
508af579bebSMatthew Bobrowski 				   size_t count)
509af579bebSMatthew Bobrowski {
510af579bebSMatthew Bobrowski 	struct fanotify_event_info_pidfd info = { };
511af579bebSMatthew Bobrowski 	size_t info_len = FANOTIFY_PIDFD_INFO_HDR_LEN;
512af579bebSMatthew Bobrowski 
513af579bebSMatthew Bobrowski 	if (WARN_ON_ONCE(info_len > count))
514af579bebSMatthew Bobrowski 		return -EFAULT;
515af579bebSMatthew Bobrowski 
516af579bebSMatthew Bobrowski 	info.hdr.info_type = FAN_EVENT_INFO_TYPE_PIDFD;
517af579bebSMatthew Bobrowski 	info.hdr.len = info_len;
518af579bebSMatthew Bobrowski 	info.pidfd = pidfd;
519af579bebSMatthew Bobrowski 
520af579bebSMatthew Bobrowski 	if (copy_to_user(buf, &info, info_len))
521af579bebSMatthew Bobrowski 		return -EFAULT;
522af579bebSMatthew Bobrowski 
523af579bebSMatthew Bobrowski 	return info_len;
524af579bebSMatthew Bobrowski }
525af579bebSMatthew Bobrowski 
copy_info_records_to_user(struct fanotify_event * event,struct fanotify_info * info,unsigned int info_mode,int pidfd,char __user * buf,size_t count)5260aca67bbSMatthew Bobrowski static int copy_info_records_to_user(struct fanotify_event *event,
5270aca67bbSMatthew Bobrowski 				     struct fanotify_info *info,
528af579bebSMatthew Bobrowski 				     unsigned int info_mode, int pidfd,
5290aca67bbSMatthew Bobrowski 				     char __user *buf, size_t count)
5300aca67bbSMatthew Bobrowski {
5310aca67bbSMatthew Bobrowski 	int ret, total_bytes = 0, info_type = 0;
5320aca67bbSMatthew Bobrowski 	unsigned int fid_mode = info_mode & FANOTIFY_FID_BITS;
533af579bebSMatthew Bobrowski 	unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD;
5340aca67bbSMatthew Bobrowski 
5350aca67bbSMatthew Bobrowski 	/*
5367326e382SAmir Goldstein 	 * Event info records order is as follows:
5377326e382SAmir Goldstein 	 * 1. dir fid + name
5387326e382SAmir Goldstein 	 * 2. (optional) new dir fid + new name
5397326e382SAmir Goldstein 	 * 3. (optional) child fid
5400aca67bbSMatthew Bobrowski 	 */
5414bd5a5c8SGabriel Krisman Bertazi 	if (fanotify_event_has_dir_fh(event)) {
5420aca67bbSMatthew Bobrowski 		info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
5430aca67bbSMatthew Bobrowski 					     FAN_EVENT_INFO_TYPE_DFID;
5447326e382SAmir Goldstein 
5457326e382SAmir Goldstein 		/* FAN_RENAME uses special info types */
5467326e382SAmir Goldstein 		if (event->mask & FAN_RENAME)
5477326e382SAmir Goldstein 			info_type = FAN_EVENT_INFO_TYPE_OLD_DFID_NAME;
5487326e382SAmir Goldstein 
5490aca67bbSMatthew Bobrowski 		ret = copy_fid_info_to_user(fanotify_event_fsid(event),
5500aca67bbSMatthew Bobrowski 					    fanotify_info_dir_fh(info),
5510aca67bbSMatthew Bobrowski 					    info_type,
5520aca67bbSMatthew Bobrowski 					    fanotify_info_name(info),
5530aca67bbSMatthew Bobrowski 					    info->name_len, buf, count);
5540aca67bbSMatthew Bobrowski 		if (ret < 0)
5550aca67bbSMatthew Bobrowski 			return ret;
5560aca67bbSMatthew Bobrowski 
5570aca67bbSMatthew Bobrowski 		buf += ret;
5580aca67bbSMatthew Bobrowski 		count -= ret;
5590aca67bbSMatthew Bobrowski 		total_bytes += ret;
5600aca67bbSMatthew Bobrowski 	}
5610aca67bbSMatthew Bobrowski 
5627326e382SAmir Goldstein 	/* New dir fid+name may be reported in addition to old dir fid+name */
5637326e382SAmir Goldstein 	if (fanotify_event_has_dir2_fh(event)) {
5647326e382SAmir Goldstein 		info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
5657326e382SAmir Goldstein 		ret = copy_fid_info_to_user(fanotify_event_fsid(event),
5667326e382SAmir Goldstein 					    fanotify_info_dir2_fh(info),
5677326e382SAmir Goldstein 					    info_type,
5687326e382SAmir Goldstein 					    fanotify_info_name2(info),
5697326e382SAmir Goldstein 					    info->name2_len, buf, count);
5707326e382SAmir Goldstein 		if (ret < 0)
5717326e382SAmir Goldstein 			return ret;
5727326e382SAmir Goldstein 
5737326e382SAmir Goldstein 		buf += ret;
5747326e382SAmir Goldstein 		count -= ret;
5757326e382SAmir Goldstein 		total_bytes += ret;
5767326e382SAmir Goldstein 	}
5777326e382SAmir Goldstein 
5784bd5a5c8SGabriel Krisman Bertazi 	if (fanotify_event_has_object_fh(event)) {
5790aca67bbSMatthew Bobrowski 		const char *dot = NULL;
5800aca67bbSMatthew Bobrowski 		int dot_len = 0;
5810aca67bbSMatthew Bobrowski 
5820aca67bbSMatthew Bobrowski 		if (fid_mode == FAN_REPORT_FID || info_type) {
5830aca67bbSMatthew Bobrowski 			/*
5840aca67bbSMatthew Bobrowski 			 * With only group flag FAN_REPORT_FID only type FID is
5850aca67bbSMatthew Bobrowski 			 * reported. Second info record type is always FID.
5860aca67bbSMatthew Bobrowski 			 */
5870aca67bbSMatthew Bobrowski 			info_type = FAN_EVENT_INFO_TYPE_FID;
5880aca67bbSMatthew Bobrowski 		} else if ((fid_mode & FAN_REPORT_NAME) &&
5890aca67bbSMatthew Bobrowski 			   (event->mask & FAN_ONDIR)) {
5900aca67bbSMatthew Bobrowski 			/*
5910aca67bbSMatthew Bobrowski 			 * With group flag FAN_REPORT_NAME, if name was not
5920aca67bbSMatthew Bobrowski 			 * recorded in an event on a directory, report the name
5930aca67bbSMatthew Bobrowski 			 * "." with info type DFID_NAME.
5940aca67bbSMatthew Bobrowski 			 */
5950aca67bbSMatthew Bobrowski 			info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
5960aca67bbSMatthew Bobrowski 			dot = ".";
5970aca67bbSMatthew Bobrowski 			dot_len = 1;
5980aca67bbSMatthew Bobrowski 		} else if ((event->mask & ALL_FSNOTIFY_DIRENT_EVENTS) ||
5990aca67bbSMatthew Bobrowski 			   (event->mask & FAN_ONDIR)) {
6000aca67bbSMatthew Bobrowski 			/*
6010aca67bbSMatthew Bobrowski 			 * With group flag FAN_REPORT_DIR_FID, a single info
6020aca67bbSMatthew Bobrowski 			 * record has type DFID for directory entry modification
6030aca67bbSMatthew Bobrowski 			 * event and for event on a directory.
6040aca67bbSMatthew Bobrowski 			 */
6050aca67bbSMatthew Bobrowski 			info_type = FAN_EVENT_INFO_TYPE_DFID;
6060aca67bbSMatthew Bobrowski 		} else {
6070aca67bbSMatthew Bobrowski 			/*
6080aca67bbSMatthew Bobrowski 			 * With group flags FAN_REPORT_DIR_FID|FAN_REPORT_FID,
6090aca67bbSMatthew Bobrowski 			 * a single info record has type FID for event on a
6100aca67bbSMatthew Bobrowski 			 * non-directory, when there is no directory to report.
6110aca67bbSMatthew Bobrowski 			 * For example, on FAN_DELETE_SELF event.
6120aca67bbSMatthew Bobrowski 			 */
6130aca67bbSMatthew Bobrowski 			info_type = FAN_EVENT_INFO_TYPE_FID;
6140aca67bbSMatthew Bobrowski 		}
6150aca67bbSMatthew Bobrowski 
6160aca67bbSMatthew Bobrowski 		ret = copy_fid_info_to_user(fanotify_event_fsid(event),
6170aca67bbSMatthew Bobrowski 					    fanotify_event_object_fh(event),
6180aca67bbSMatthew Bobrowski 					    info_type, dot, dot_len,
6190aca67bbSMatthew Bobrowski 					    buf, count);
6200aca67bbSMatthew Bobrowski 		if (ret < 0)
6210aca67bbSMatthew Bobrowski 			return ret;
6220aca67bbSMatthew Bobrowski 
6230aca67bbSMatthew Bobrowski 		buf += ret;
6240aca67bbSMatthew Bobrowski 		count -= ret;
6250aca67bbSMatthew Bobrowski 		total_bytes += ret;
6260aca67bbSMatthew Bobrowski 	}
6270aca67bbSMatthew Bobrowski 
628af579bebSMatthew Bobrowski 	if (pidfd_mode) {
629af579bebSMatthew Bobrowski 		ret = copy_pidfd_info_to_user(pidfd, buf, count);
630af579bebSMatthew Bobrowski 		if (ret < 0)
631af579bebSMatthew Bobrowski 			return ret;
632af579bebSMatthew Bobrowski 
633af579bebSMatthew Bobrowski 		buf += ret;
634af579bebSMatthew Bobrowski 		count -= ret;
635af579bebSMatthew Bobrowski 		total_bytes += ret;
636af579bebSMatthew Bobrowski 	}
637af579bebSMatthew Bobrowski 
638130a3c74SGabriel Krisman Bertazi 	if (fanotify_is_error_event(event->mask)) {
639130a3c74SGabriel Krisman Bertazi 		ret = copy_error_info_to_user(event, buf, count);
640130a3c74SGabriel Krisman Bertazi 		if (ret < 0)
641130a3c74SGabriel Krisman Bertazi 			return ret;
642130a3c74SGabriel Krisman Bertazi 		buf += ret;
643130a3c74SGabriel Krisman Bertazi 		count -= ret;
644130a3c74SGabriel Krisman Bertazi 		total_bytes += ret;
645130a3c74SGabriel Krisman Bertazi 	}
646130a3c74SGabriel Krisman Bertazi 
6470aca67bbSMatthew Bobrowski 	return total_bytes;
6480aca67bbSMatthew Bobrowski }
6490aca67bbSMatthew Bobrowski 
copy_event_to_user(struct fsnotify_group * group,struct fanotify_event * event,char __user * buf,size_t count)650a1014f10SEric Paris static ssize_t copy_event_to_user(struct fsnotify_group *group,
6517088f357SJan Kara 				  struct fanotify_event *event,
6525b03a472SKees Cook 				  char __user *buf, size_t count)
653a1014f10SEric Paris {
654bb2f7b45SAmir Goldstein 	struct fanotify_event_metadata metadata;
655d5bf8889SAl Viro 	const struct path *path = fanotify_event_path(event);
656f454fa61SAmir Goldstein 	struct fanotify_info *info = fanotify_event_info(event);
6570aca67bbSMatthew Bobrowski 	unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES);
658af579bebSMatthew Bobrowski 	unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD;
659eee3a0e9SChristian Brauner 	struct file *f = NULL, *pidfd_file = NULL;
660*ffe1766aSAmir Goldstein 	int ret, pidfd = -ESRCH, fd = -EBADF;
661a1014f10SEric Paris 
6627088f357SJan Kara 	pr_debug("%s: group=%p event=%p\n", __func__, group, event);
663a1014f10SEric Paris 
664b9928e80SGabriel Krisman Bertazi 	metadata.event_len = fanotify_event_len(info_mode, event);
665bb2f7b45SAmir Goldstein 	metadata.metadata_len = FAN_EVENT_METADATA_LEN;
666bb2f7b45SAmir Goldstein 	metadata.vers = FANOTIFY_METADATA_VERSION;
667bb2f7b45SAmir Goldstein 	metadata.reserved = 0;
668bb2f7b45SAmir Goldstein 	metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
669bb2f7b45SAmir Goldstein 	metadata.pid = pid_vnr(event->pid);
6707cea2a3cSAmir Goldstein 	/*
6717cea2a3cSAmir Goldstein 	 * For an unprivileged listener, event->pid can be used to identify the
6727cea2a3cSAmir Goldstein 	 * events generated by the listener process itself, without disclosing
6737cea2a3cSAmir Goldstein 	 * the pids of other processes.
6747cea2a3cSAmir Goldstein 	 */
675a8b98c80SAmir Goldstein 	if (FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) &&
6767cea2a3cSAmir Goldstein 	    task_tgid(current) != event->pid)
6777cea2a3cSAmir Goldstein 		metadata.pid = 0;
678a1014f10SEric Paris 
679a8b98c80SAmir Goldstein 	/*
680a8b98c80SAmir Goldstein 	 * For now, fid mode is required for an unprivileged listener and
681a8b98c80SAmir Goldstein 	 * fid mode does not report fd in events.  Keep this check anyway
682a8b98c80SAmir Goldstein 	 * for safety in case fid mode requirement is relaxed in the future
683a8b98c80SAmir Goldstein 	 * to allow unprivileged listener to get events with no fd and no fid.
684a8b98c80SAmir Goldstein 	 */
685a8b98c80SAmir Goldstein 	if (!FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) &&
686a8b98c80SAmir Goldstein 	    path && path->mnt && path->dentry) {
687a741c2feSJan Kara 		fd = create_fd(group, path, &f);
688*ffe1766aSAmir Goldstein 		/*
689*ffe1766aSAmir Goldstein 		 * Opening an fd from dentry can fail for several reasons.
690*ffe1766aSAmir Goldstein 		 * For example, when tasks are gone and we try to open their
691*ffe1766aSAmir Goldstein 		 * /proc files or we try to open a WRONLY file like in sysfs
692*ffe1766aSAmir Goldstein 		 * or when trying to open a file that was deleted on the
693*ffe1766aSAmir Goldstein 		 * remote network server.
694*ffe1766aSAmir Goldstein 		 *
695*ffe1766aSAmir Goldstein 		 * For a group with FAN_REPORT_FD_ERROR, we will send the
696*ffe1766aSAmir Goldstein 		 * event with the error instead of the open fd, otherwise
697*ffe1766aSAmir Goldstein 		 * Userspace may not get the error at all.
698*ffe1766aSAmir Goldstein 		 * In any case, userspace will not know which file failed to
699*ffe1766aSAmir Goldstein 		 * open, so add a debug print for further investigation.
700*ffe1766aSAmir Goldstein 		 */
701*ffe1766aSAmir Goldstein 		if (fd < 0) {
702*ffe1766aSAmir Goldstein 			pr_debug("fanotify: create_fd(%pd2) failed err=%d\n",
703*ffe1766aSAmir Goldstein 				 path->dentry, fd);
704*ffe1766aSAmir Goldstein 			if (!FAN_GROUP_FLAG(group, FAN_REPORT_FD_ERROR)) {
705*ffe1766aSAmir Goldstein 				/*
706*ffe1766aSAmir Goldstein 				 * Historically, we've handled EOPENSTALE in a
707*ffe1766aSAmir Goldstein 				 * special way and silently dropped such
708*ffe1766aSAmir Goldstein 				 * events. Now we have to keep it to maintain
709*ffe1766aSAmir Goldstein 				 * backward compatibility...
710*ffe1766aSAmir Goldstein 				 */
711*ffe1766aSAmir Goldstein 				if (fd == -EOPENSTALE)
712*ffe1766aSAmir Goldstein 					fd = 0;
713bb2f7b45SAmir Goldstein 				return fd;
714a741c2feSJan Kara 			}
715*ffe1766aSAmir Goldstein 		}
716*ffe1766aSAmir Goldstein 	}
717*ffe1766aSAmir Goldstein 	if (FAN_GROUP_FLAG(group, FAN_REPORT_FD_ERROR))
718bb2f7b45SAmir Goldstein 		metadata.fd = fd;
719*ffe1766aSAmir Goldstein 	else
720*ffe1766aSAmir Goldstein 		metadata.fd = fd >= 0 ? fd : FAN_NOFD;
721bb2f7b45SAmir Goldstein 
722af579bebSMatthew Bobrowski 	if (pidfd_mode) {
723af579bebSMatthew Bobrowski 		/*
724af579bebSMatthew Bobrowski 		 * Complain if the FAN_REPORT_PIDFD and FAN_REPORT_TID mutual
725af579bebSMatthew Bobrowski 		 * exclusion is ever lifted. At the time of incoporating pidfd
726af579bebSMatthew Bobrowski 		 * support within fanotify, the pidfd API only supported the
727af579bebSMatthew Bobrowski 		 * creation of pidfds for thread-group leaders.
728af579bebSMatthew Bobrowski 		 */
729af579bebSMatthew Bobrowski 		WARN_ON_ONCE(FAN_GROUP_FLAG(group, FAN_REPORT_TID));
730af579bebSMatthew Bobrowski 
731af579bebSMatthew Bobrowski 		/*
732af579bebSMatthew Bobrowski 		 * The PIDTYPE_TGID check for an event->pid is performed
733af579bebSMatthew Bobrowski 		 * preemptively in an attempt to catch out cases where the event
734af579bebSMatthew Bobrowski 		 * listener reads events after the event generating process has
735*ffe1766aSAmir Goldstein 		 * already terminated.  Depending on flag FAN_REPORT_FD_ERROR,
736*ffe1766aSAmir Goldstein 		 * report either -ESRCH or FAN_NOPIDFD to the event listener in
737*ffe1766aSAmir Goldstein 		 * those cases with all other pidfd creation errors reported as
738*ffe1766aSAmir Goldstein 		 * the error code itself or as FAN_EPIDFD.
739af579bebSMatthew Bobrowski 		 */
740*ffe1766aSAmir Goldstein 		if (metadata.pid && pid_has_task(event->pid, PIDTYPE_TGID))
741eee3a0e9SChristian Brauner 			pidfd = pidfd_prepare(event->pid, 0, &pidfd_file);
742*ffe1766aSAmir Goldstein 
743*ffe1766aSAmir Goldstein 		if (!FAN_GROUP_FLAG(group, FAN_REPORT_FD_ERROR) && pidfd < 0)
744*ffe1766aSAmir Goldstein 			pidfd = pidfd == -ESRCH ? FAN_NOPIDFD : FAN_EPIDFD;
745af579bebSMatthew Bobrowski 	}
746af579bebSMatthew Bobrowski 
747352e3b24SAl Viro 	ret = -EFAULT;
7485b03a472SKees Cook 	/*
7495b03a472SKees Cook 	 * Sanity check copy size in case get_one_event() and
750c5e443cbSFabian Frederick 	 * event_len sizes ever get out of sync.
7515b03a472SKees Cook 	 */
752bb2f7b45SAmir Goldstein 	if (WARN_ON_ONCE(metadata.event_len > count))
753352e3b24SAl Viro 		goto out_close_fd;
754352e3b24SAl Viro 
7555e469c83SAmir Goldstein 	if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN))
756bb2f7b45SAmir Goldstein 		goto out_close_fd;
757bb2f7b45SAmir Goldstein 
75844d705b0SAmir Goldstein 	buf += FAN_EVENT_METADATA_LEN;
75944d705b0SAmir Goldstein 	count -= FAN_EVENT_METADATA_LEN;
76044d705b0SAmir Goldstein 
7610aca67bbSMatthew Bobrowski 	if (info_mode) {
762af579bebSMatthew Bobrowski 		ret = copy_info_records_to_user(event, info, info_mode, pidfd,
763d3424c9bSMatthew Bobrowski 						buf, count);
7645e469c83SAmir Goldstein 		if (ret < 0)
765f644bc44SMatthew Bobrowski 			goto out_close_fd;
7665e469c83SAmir Goldstein 	}
7675e469c83SAmir Goldstein 
768ee125951SDan Carpenter 	if (f)
769ee125951SDan Carpenter 		fd_install(fd, f);
770ee125951SDan Carpenter 
771eee3a0e9SChristian Brauner 	if (pidfd_file)
772eee3a0e9SChristian Brauner 		fd_install(pidfd, pidfd_file);
773eee3a0e9SChristian Brauner 
774*ffe1766aSAmir Goldstein 	if (fanotify_is_perm_event(event->mask))
775*ffe1766aSAmir Goldstein 		FANOTIFY_PERM(event)->fd = fd;
776*ffe1766aSAmir Goldstein 
777bb2f7b45SAmir Goldstein 	return metadata.event_len;
778b2d87909SEric Paris 
779b2d87909SEric Paris out_close_fd:
780*ffe1766aSAmir Goldstein 	if (f) {
781352e3b24SAl Viro 		put_unused_fd(fd);
782352e3b24SAl Viro 		fput(f);
783352e3b24SAl Viro 	}
784af579bebSMatthew Bobrowski 
785*ffe1766aSAmir Goldstein 	if (pidfd_file) {
786eee3a0e9SChristian Brauner 		put_unused_fd(pidfd);
787eee3a0e9SChristian Brauner 		fput(pidfd_file);
788eee3a0e9SChristian Brauner 	}
789af579bebSMatthew Bobrowski 
790b2d87909SEric Paris 	return ret;
791a1014f10SEric Paris }
792a1014f10SEric Paris 
793a1014f10SEric Paris /* intofiy userspace file descriptor functions */
fanotify_poll(struct file * file,poll_table * wait)794076ccb76SAl Viro static __poll_t fanotify_poll(struct file *file, poll_table *wait)
795a1014f10SEric Paris {
796a1014f10SEric Paris 	struct fsnotify_group *group = file->private_data;
797076ccb76SAl Viro 	__poll_t ret = 0;
798a1014f10SEric Paris 
799a1014f10SEric Paris 	poll_wait(file, &group->notification_waitq, wait);
800c21dbe20SJan Kara 	spin_lock(&group->notification_lock);
801a1014f10SEric Paris 	if (!fsnotify_notify_queue_is_empty(group))
802a9a08845SLinus Torvalds 		ret = EPOLLIN | EPOLLRDNORM;
803c21dbe20SJan Kara 	spin_unlock(&group->notification_lock);
804a1014f10SEric Paris 
805a1014f10SEric Paris 	return ret;
806a1014f10SEric Paris }
807a1014f10SEric Paris 
fanotify_read(struct file * file,char __user * buf,size_t count,loff_t * pos)808a1014f10SEric Paris static ssize_t fanotify_read(struct file *file, char __user *buf,
809a1014f10SEric Paris 			     size_t count, loff_t *pos)
810a1014f10SEric Paris {
811a1014f10SEric Paris 	struct fsnotify_group *group;
8127088f357SJan Kara 	struct fanotify_event *event;
813a1014f10SEric Paris 	char __user *start;
814a1014f10SEric Paris 	int ret;
815536ebe9cSPeter Zijlstra 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
816a1014f10SEric Paris 
817a1014f10SEric Paris 	start = buf;
818a1014f10SEric Paris 	group = file->private_data;
819a1014f10SEric Paris 
820a1014f10SEric Paris 	pr_debug("%s: group=%p\n", __func__, group);
821a1014f10SEric Paris 
822536ebe9cSPeter Zijlstra 	add_wait_queue(&group->notification_waitq, &wait);
823a1014f10SEric Paris 	while (1) {
82447aaabdeSJan Kara 		/*
82547aaabdeSJan Kara 		 * User can supply arbitrarily large buffer. Avoid softlockups
82647aaabdeSJan Kara 		 * in case there are lots of available events.
82747aaabdeSJan Kara 		 */
82847aaabdeSJan Kara 		cond_resched();
8297088f357SJan Kara 		event = get_one_event(group, count);
8307088f357SJan Kara 		if (IS_ERR(event)) {
8317088f357SJan Kara 			ret = PTR_ERR(event);
832a1014f10SEric Paris 			break;
833d8aaab4fSJan Kara 		}
834d8aaab4fSJan Kara 
8357088f357SJan Kara 		if (!event) {
836d8aaab4fSJan Kara 			ret = -EAGAIN;
837d8aaab4fSJan Kara 			if (file->f_flags & O_NONBLOCK)
838d8aaab4fSJan Kara 				break;
839d8aaab4fSJan Kara 
840d8aaab4fSJan Kara 			ret = -ERESTARTSYS;
841d8aaab4fSJan Kara 			if (signal_pending(current))
842d8aaab4fSJan Kara 				break;
843d8aaab4fSJan Kara 
844d8aaab4fSJan Kara 			if (start != buf)
845d8aaab4fSJan Kara 				break;
846536ebe9cSPeter Zijlstra 
847536ebe9cSPeter Zijlstra 			wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
848d8aaab4fSJan Kara 			continue;
849d8aaab4fSJan Kara 		}
850d8aaab4fSJan Kara 
8517088f357SJan Kara 		ret = copy_event_to_user(group, event, buf, count);
8524ff33aafSAmir Goldstein 
85385816794SJan Kara 		/*
854d8aaab4fSJan Kara 		 * Permission events get queued to wait for response.  Other
855d8aaab4fSJan Kara 		 * events can be destroyed now.
85685816794SJan Kara 		 */
8577088f357SJan Kara 		if (!fanotify_is_perm_event(event->mask)) {
8587088f357SJan Kara 			fsnotify_destroy_event(group, &event->fse);
859d507816bSJan Kara 		} else {
860*ffe1766aSAmir Goldstein 			if (ret <= 0 || FANOTIFY_PERM(event)->fd < 0) {
86140873284SJan Kara 				spin_lock(&group->notification_lock);
86240873284SJan Kara 				finish_permission_event(group,
86370529a19SRichard Guy Briggs 					FANOTIFY_PERM(event), FAN_DENY, NULL);
864d507816bSJan Kara 				wake_up(&group->fanotify_data.access_waitq);
8654ff33aafSAmir Goldstein 			} else {
866073f6552SJan Kara 				spin_lock(&group->notification_lock);
8677088f357SJan Kara 				list_add_tail(&event->fse.list,
868d507816bSJan Kara 					&group->fanotify_data.access_list);
869073f6552SJan Kara 				spin_unlock(&group->notification_lock);
8704ff33aafSAmir Goldstein 			}
871d507816bSJan Kara 		}
8724ff33aafSAmir Goldstein 		if (ret < 0)
8734ff33aafSAmir Goldstein 			break;
874a1014f10SEric Paris 		buf += ret;
875a1014f10SEric Paris 		count -= ret;
876a1014f10SEric Paris 	}
877536ebe9cSPeter Zijlstra 	remove_wait_queue(&group->notification_waitq, &wait);
878a1014f10SEric Paris 
879a1014f10SEric Paris 	if (start != buf && ret != -EFAULT)
880a1014f10SEric Paris 		ret = buf - start;
881a1014f10SEric Paris 	return ret;
882a1014f10SEric Paris }
883a1014f10SEric Paris 
fanotify_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)884b2d87909SEric Paris static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
885b2d87909SEric Paris {
88670529a19SRichard Guy Briggs 	struct fanotify_response response;
887b2d87909SEric Paris 	struct fsnotify_group *group;
888b2d87909SEric Paris 	int ret;
88970529a19SRichard Guy Briggs 	const char __user *info_buf = buf + sizeof(struct fanotify_response);
89070529a19SRichard Guy Briggs 	size_t info_len;
891b2d87909SEric Paris 
8926685df31SMiklos Szeredi 	if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
8936685df31SMiklos Szeredi 		return -EINVAL;
8946685df31SMiklos Szeredi 
895b2d87909SEric Paris 	group = file->private_data;
896b2d87909SEric Paris 
89770529a19SRichard Guy Briggs 	pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
89870529a19SRichard Guy Briggs 
8995e23663bSFabian Frederick 	if (count < sizeof(response))
9005e23663bSFabian Frederick 		return -EINVAL;
9015e23663bSFabian Frederick 
90270529a19SRichard Guy Briggs 	if (copy_from_user(&response, buf, sizeof(response)))
903b2d87909SEric Paris 		return -EFAULT;
904b2d87909SEric Paris 
90570529a19SRichard Guy Briggs 	info_len = count - sizeof(response);
90670529a19SRichard Guy Briggs 
90770529a19SRichard Guy Briggs 	ret = process_access_response(group, &response, info_buf, info_len);
908b2d87909SEric Paris 	if (ret < 0)
909b2d87909SEric Paris 		count = ret;
91070529a19SRichard Guy Briggs 	else
91170529a19SRichard Guy Briggs 		count = sizeof(response) + ret;
912b2d87909SEric Paris 
913b2d87909SEric Paris 	return count;
914b2d87909SEric Paris }
915b2d87909SEric Paris 
fanotify_release(struct inode * ignored,struct file * file)91652c923ddSEric Paris static int fanotify_release(struct inode *ignored, struct file *file)
91752c923ddSEric Paris {
91852c923ddSEric Paris 	struct fsnotify_group *group = file->private_data;
9196f73171eSAmir Goldstein 	struct fsnotify_event *fsn_event;
92019ba54f4SAndrew Morton 
9215838d444SJan Kara 	/*
92296d41019SJan Kara 	 * Stop new events from arriving in the notification queue. since
92396d41019SJan Kara 	 * userspace cannot use fanotify fd anymore, no event can enter or
92496d41019SJan Kara 	 * leave access_list by now either.
92596d41019SJan Kara 	 */
92696d41019SJan Kara 	fsnotify_group_stop_queueing(group);
92796d41019SJan Kara 
92896d41019SJan Kara 	/*
92996d41019SJan Kara 	 * Process all permission events on access_list and notification queue
93096d41019SJan Kara 	 * and simulate reply from userspace.
9315838d444SJan Kara 	 */
932073f6552SJan Kara 	spin_lock(&group->notification_lock);
933ca6f8699SJan Kara 	while (!list_empty(&group->fanotify_data.access_list)) {
9347088f357SJan Kara 		struct fanotify_perm_event *event;
9357088f357SJan Kara 
936ca6f8699SJan Kara 		event = list_first_entry(&group->fanotify_data.access_list,
937ca6f8699SJan Kara 				struct fanotify_perm_event, fae.fse.list);
938f083441bSJan Kara 		list_del_init(&event->fae.fse.list);
93970529a19SRichard Guy Briggs 		finish_permission_event(group, event, FAN_ALLOW, NULL);
94040873284SJan Kara 		spin_lock(&group->notification_lock);
9412eebf582SEric Paris 	}
9422eebf582SEric Paris 
9435838d444SJan Kara 	/*
94496d41019SJan Kara 	 * Destroy all non-permission events. For permission events just
94596d41019SJan Kara 	 * dequeue them and set the response. They will be freed once the
94696d41019SJan Kara 	 * response is consumed and fanotify_get_response() returns.
9475838d444SJan Kara 	 */
9486f73171eSAmir Goldstein 	while ((fsn_event = fsnotify_remove_first_event(group))) {
9496f73171eSAmir Goldstein 		struct fanotify_event *event = FANOTIFY_E(fsn_event);
9507088f357SJan Kara 
9517088f357SJan Kara 		if (!(event->mask & FANOTIFY_PERM_EVENTS)) {
952c21dbe20SJan Kara 			spin_unlock(&group->notification_lock);
9536f73171eSAmir Goldstein 			fsnotify_destroy_event(group, fsn_event);
9546685df31SMiklos Szeredi 		} else {
9557088f357SJan Kara 			finish_permission_event(group, FANOTIFY_PERM(event),
95670529a19SRichard Guy Briggs 						FAN_ALLOW, NULL);
95796d41019SJan Kara 		}
95840873284SJan Kara 		spin_lock(&group->notification_lock);
9596685df31SMiklos Szeredi 	}
960c21dbe20SJan Kara 	spin_unlock(&group->notification_lock);
96196d41019SJan Kara 
96296d41019SJan Kara 	/* Response for all permission events it set, wakeup waiters */
9632eebf582SEric Paris 	wake_up(&group->fanotify_data.access_waitq);
9640a6b6bd5SEric Paris 
96552c923ddSEric Paris 	/* matches the fanotify_init->fsnotify_alloc_group */
966d8153d4dSLino Sanfilippo 	fsnotify_destroy_group(group);
96752c923ddSEric Paris 
96852c923ddSEric Paris 	return 0;
96952c923ddSEric Paris }
97052c923ddSEric Paris 
fanotify_ioctl(struct file * file,unsigned int cmd,unsigned long arg)971a1014f10SEric Paris static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
972a1014f10SEric Paris {
973a1014f10SEric Paris 	struct fsnotify_group *group;
9747053aee2SJan Kara 	struct fsnotify_event *fsn_event;
975a1014f10SEric Paris 	void __user *p;
976a1014f10SEric Paris 	int ret = -ENOTTY;
977a1014f10SEric Paris 	size_t send_len = 0;
978a1014f10SEric Paris 
979a1014f10SEric Paris 	group = file->private_data;
980a1014f10SEric Paris 
981a1014f10SEric Paris 	p = (void __user *) arg;
982a1014f10SEric Paris 
983a1014f10SEric Paris 	switch (cmd) {
984a1014f10SEric Paris 	case FIONREAD:
985c21dbe20SJan Kara 		spin_lock(&group->notification_lock);
9867053aee2SJan Kara 		list_for_each_entry(fsn_event, &group->notification_list, list)
987a1014f10SEric Paris 			send_len += FAN_EVENT_METADATA_LEN;
988c21dbe20SJan Kara 		spin_unlock(&group->notification_lock);
989a1014f10SEric Paris 		ret = put_user(send_len, (int __user *) p);
990a1014f10SEric Paris 		break;
991a1014f10SEric Paris 	}
992a1014f10SEric Paris 
993a1014f10SEric Paris 	return ret;
994a1014f10SEric Paris }
995a1014f10SEric Paris 
99652c923ddSEric Paris static const struct file_operations fanotify_fops = {
997be77196bSCyrill Gorcunov 	.show_fdinfo	= fanotify_show_fdinfo,
998a1014f10SEric Paris 	.poll		= fanotify_poll,
999a1014f10SEric Paris 	.read		= fanotify_read,
1000b2d87909SEric Paris 	.write		= fanotify_write,
100152c923ddSEric Paris 	.fasync		= NULL,
100252c923ddSEric Paris 	.release	= fanotify_release,
1003a1014f10SEric Paris 	.unlocked_ioctl	= fanotify_ioctl,
10041832f2d8SArnd Bergmann 	.compat_ioctl	= compat_ptr_ioctl,
10056038f373SArnd Bergmann 	.llseek		= noop_llseek,
100652c923ddSEric Paris };
100752c923ddSEric Paris 
fanotify_find_path(int dfd,const char __user * filename,struct path * path,unsigned int flags,__u64 mask,unsigned int obj_type)10082a3edf86SEric Paris static int fanotify_find_path(int dfd, const char __user *filename,
1009ac5656d8SAaron Goidel 			      struct path *path, unsigned int flags, __u64 mask,
1010ac5656d8SAaron Goidel 			      unsigned int obj_type)
10112a3edf86SEric Paris {
10122a3edf86SEric Paris 	int ret;
10132a3edf86SEric Paris 
10142a3edf86SEric Paris 	pr_debug("%s: dfd=%d filename=%p flags=%x\n", __func__,
10152a3edf86SEric Paris 		 dfd, filename, flags);
10162a3edf86SEric Paris 
10172a3edf86SEric Paris 	if (filename == NULL) {
10182903ff01SAl Viro 		struct fd f = fdget(dfd);
10192a3edf86SEric Paris 
10202a3edf86SEric Paris 		ret = -EBADF;
10212903ff01SAl Viro 		if (!f.file)
10222a3edf86SEric Paris 			goto out;
10232a3edf86SEric Paris 
10242a3edf86SEric Paris 		ret = -ENOTDIR;
10252a3edf86SEric Paris 		if ((flags & FAN_MARK_ONLYDIR) &&
1026496ad9aaSAl Viro 		    !(S_ISDIR(file_inode(f.file)->i_mode))) {
10272903ff01SAl Viro 			fdput(f);
10282a3edf86SEric Paris 			goto out;
10292a3edf86SEric Paris 		}
10302a3edf86SEric Paris 
10312903ff01SAl Viro 		*path = f.file->f_path;
10322a3edf86SEric Paris 		path_get(path);
10332903ff01SAl Viro 		fdput(f);
10342a3edf86SEric Paris 	} else {
10352a3edf86SEric Paris 		unsigned int lookup_flags = 0;
10362a3edf86SEric Paris 
10372a3edf86SEric Paris 		if (!(flags & FAN_MARK_DONT_FOLLOW))
10382a3edf86SEric Paris 			lookup_flags |= LOOKUP_FOLLOW;
10392a3edf86SEric Paris 		if (flags & FAN_MARK_ONLYDIR)
10402a3edf86SEric Paris 			lookup_flags |= LOOKUP_DIRECTORY;
10412a3edf86SEric Paris 
10422a3edf86SEric Paris 		ret = user_path_at(dfd, filename, lookup_flags, path);
10432a3edf86SEric Paris 		if (ret)
10442a3edf86SEric Paris 			goto out;
10452a3edf86SEric Paris 	}
10462a3edf86SEric Paris 
10472a3edf86SEric Paris 	/* you can only watch an inode if you have read permissions on it */
104802f92b38SChristian Brauner 	ret = path_permission(path, MAY_READ);
1049ac5656d8SAaron Goidel 	if (ret) {
1050ac5656d8SAaron Goidel 		path_put(path);
1051ac5656d8SAaron Goidel 		goto out;
1052ac5656d8SAaron Goidel 	}
1053ac5656d8SAaron Goidel 
1054ac5656d8SAaron Goidel 	ret = security_path_notify(path, mask, obj_type);
10552a3edf86SEric Paris 	if (ret)
10562a3edf86SEric Paris 		path_put(path);
1057ac5656d8SAaron Goidel 
10582a3edf86SEric Paris out:
10592a3edf86SEric Paris 	return ret;
10602a3edf86SEric Paris }
10612a3edf86SEric Paris 
fanotify_mark_remove_from_mask(struct fsnotify_mark * fsn_mark,__u32 mask,unsigned int flags,__u32 umask,int * destroy)1062b9e4e3bdSEric Paris static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
10634ed6814aSAmir Goldstein 					    __u32 mask, unsigned int flags,
10644ed6814aSAmir Goldstein 					    __u32 umask, int *destroy)
1065088b09b0SAndreas Gruenbacher {
10664f0b903dSAmir Goldstein 	__u32 oldmask, newmask;
1067088b09b0SAndreas Gruenbacher 
10684ed6814aSAmir Goldstein 	/* umask bits cannot be removed by user */
10694ed6814aSAmir Goldstein 	mask &= ~umask;
1070088b09b0SAndreas Gruenbacher 	spin_lock(&fsn_mark->lock);
10714f0b903dSAmir Goldstein 	oldmask = fsnotify_calc_mask(fsn_mark);
1072e252f2edSAmir Goldstein 	if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) {
1073a72fd224SAmir Goldstein 		fsn_mark->mask &= ~mask;
1074b9e4e3bdSEric Paris 	} else {
107531a371e4SAmir Goldstein 		fsn_mark->ignore_mask &= ~mask;
1076b9e4e3bdSEric Paris 	}
10774f0b903dSAmir Goldstein 	newmask = fsnotify_calc_mask(fsn_mark);
10784ed6814aSAmir Goldstein 	/*
10794ed6814aSAmir Goldstein 	 * We need to keep the mark around even if remaining mask cannot
10804ed6814aSAmir Goldstein 	 * result in any events (e.g. mask == FAN_ONDIR) to support incremenal
10814ed6814aSAmir Goldstein 	 * changes to the mask.
10824ed6814aSAmir Goldstein 	 * Destroy mark when only umask bits remain.
10834ed6814aSAmir Goldstein 	 */
108431a371e4SAmir Goldstein 	*destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask);
1085088b09b0SAndreas Gruenbacher 	spin_unlock(&fsn_mark->lock);
1086088b09b0SAndreas Gruenbacher 
10874f0b903dSAmir Goldstein 	return oldmask & ~newmask;
1088088b09b0SAndreas Gruenbacher }
1089088b09b0SAndreas Gruenbacher 
fanotify_remove_mark(struct fsnotify_group * group,fsnotify_connp_t * connp,__u32 mask,unsigned int flags,__u32 umask)1090eaa2c6b0SAmir Goldstein static int fanotify_remove_mark(struct fsnotify_group *group,
1091eaa2c6b0SAmir Goldstein 				fsnotify_connp_t *connp, __u32 mask,
10924ed6814aSAmir Goldstein 				unsigned int flags, __u32 umask)
109388826276SEric Paris {
109488826276SEric Paris 	struct fsnotify_mark *fsn_mark = NULL;
1095088b09b0SAndreas Gruenbacher 	__u32 removed;
10966dfbd149SLino Sanfilippo 	int destroy_mark;
109788826276SEric Paris 
1098e79719a2SAmir Goldstein 	fsnotify_group_lock(group);
1099eaa2c6b0SAmir Goldstein 	fsn_mark = fsnotify_find_mark(connp, group);
11007b18527cSLino Sanfilippo 	if (!fsn_mark) {
1101e79719a2SAmir Goldstein 		fsnotify_group_unlock(group);
110288826276SEric Paris 		return -ENOENT;
11037b18527cSLino Sanfilippo 	}
110488826276SEric Paris 
11056dfbd149SLino Sanfilippo 	removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
11064ed6814aSAmir Goldstein 						 umask, &destroy_mark);
11073ac70bfcSAmir Goldstein 	if (removed & fsnotify_conn_mask(fsn_mark->connector))
11083ac70bfcSAmir Goldstein 		fsnotify_recalc_mask(fsn_mark->connector);
11096dfbd149SLino Sanfilippo 	if (destroy_mark)
11104712e722SJan Kara 		fsnotify_detach_mark(fsn_mark);
1111e79719a2SAmir Goldstein 	fsnotify_group_unlock(group);
11124712e722SJan Kara 	if (destroy_mark)
11134712e722SJan Kara 		fsnotify_free_mark(fsn_mark);
11147b18527cSLino Sanfilippo 
1115b1362edfSJan Kara 	/* matches the fsnotify_find_mark() */
11162a3edf86SEric Paris 	fsnotify_put_mark(fsn_mark);
11172a3edf86SEric Paris 	return 0;
11182a3edf86SEric Paris }
11192a3edf86SEric Paris 
fanotify_remove_vfsmount_mark(struct fsnotify_group * group,struct vfsmount * mnt,__u32 mask,unsigned int flags,__u32 umask)1120eaa2c6b0SAmir Goldstein static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
1121eaa2c6b0SAmir Goldstein 					 struct vfsmount *mnt, __u32 mask,
11224ed6814aSAmir Goldstein 					 unsigned int flags, __u32 umask)
1123eaa2c6b0SAmir Goldstein {
1124eaa2c6b0SAmir Goldstein 	return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
11254ed6814aSAmir Goldstein 				    mask, flags, umask);
1126eaa2c6b0SAmir Goldstein }
1127eaa2c6b0SAmir Goldstein 
fanotify_remove_sb_mark(struct fsnotify_group * group,struct super_block * sb,__u32 mask,unsigned int flags,__u32 umask)1128d54f4fbaSAmir Goldstein static int fanotify_remove_sb_mark(struct fsnotify_group *group,
1129d54f4fbaSAmir Goldstein 				   struct super_block *sb, __u32 mask,
11304ed6814aSAmir Goldstein 				   unsigned int flags, __u32 umask)
1131d54f4fbaSAmir Goldstein {
11324ed6814aSAmir Goldstein 	return fanotify_remove_mark(group, &sb->s_fsnotify_marks, mask,
11334ed6814aSAmir Goldstein 				    flags, umask);
1134d54f4fbaSAmir Goldstein }
1135d54f4fbaSAmir Goldstein 
fanotify_remove_inode_mark(struct fsnotify_group * group,struct inode * inode,__u32 mask,unsigned int flags,__u32 umask)1136eaa2c6b0SAmir Goldstein static int fanotify_remove_inode_mark(struct fsnotify_group *group,
1137eaa2c6b0SAmir Goldstein 				      struct inode *inode, __u32 mask,
11384ed6814aSAmir Goldstein 				      unsigned int flags, __u32 umask)
1139eaa2c6b0SAmir Goldstein {
1140eaa2c6b0SAmir Goldstein 	return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask,
11414ed6814aSAmir Goldstein 				    flags, umask);
1142eaa2c6b0SAmir Goldstein }
1143eaa2c6b0SAmir Goldstein 
fanotify_mark_update_flags(struct fsnotify_mark * fsn_mark,unsigned int fan_flags)11448998d110SAmir Goldstein static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,
11458998d110SAmir Goldstein 				       unsigned int fan_flags)
114604e317baSAmir Goldstein {
11477d5e005dSAmir Goldstein 	bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE);
1148e252f2edSAmir Goldstein 	unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS;
11498998d110SAmir Goldstein 	bool recalc = false;
115004e317baSAmir Goldstein 
115104e317baSAmir Goldstein 	/*
1152e252f2edSAmir Goldstein 	 * When using FAN_MARK_IGNORE for the first time, mark starts using
1153e252f2edSAmir Goldstein 	 * independent event flags in ignore mask.  After that, trying to
1154e252f2edSAmir Goldstein 	 * update the ignore mask with the old FAN_MARK_IGNORED_MASK API
1155e252f2edSAmir Goldstein 	 * will result in EEXIST error.
1156e252f2edSAmir Goldstein 	 */
1157e252f2edSAmir Goldstein 	if (ignore == FAN_MARK_IGNORE)
1158e252f2edSAmir Goldstein 		fsn_mark->flags |= FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS;
1159e252f2edSAmir Goldstein 
1160e252f2edSAmir Goldstein 	/*
116104e317baSAmir Goldstein 	 * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
116204e317baSAmir Goldstein 	 * the removal of the FS_MODIFY bit in calculated mask if it was set
116331a371e4SAmir Goldstein 	 * because of an ignore mask that is now going to survive FS_MODIFY.
116404e317baSAmir Goldstein 	 */
1165e252f2edSAmir Goldstein 	if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
116604e317baSAmir Goldstein 	    !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) {
116704e317baSAmir Goldstein 		fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
116804e317baSAmir Goldstein 		if (!(fsn_mark->mask & FS_MODIFY))
11698998d110SAmir Goldstein 			recalc = true;
117004e317baSAmir Goldstein 	}
117104e317baSAmir Goldstein 
11727d5e005dSAmir Goldstein 	if (fsn_mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE ||
11737d5e005dSAmir Goldstein 	    want_iref == !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
11748998d110SAmir Goldstein 		return recalc;
11757d5e005dSAmir Goldstein 
11767d5e005dSAmir Goldstein 	/*
11777d5e005dSAmir Goldstein 	 * NO_IREF may be removed from a mark, but not added.
11787d5e005dSAmir Goldstein 	 * When removed, fsnotify_recalc_mask() will take the inode ref.
11797d5e005dSAmir Goldstein 	 */
11807d5e005dSAmir Goldstein 	WARN_ON_ONCE(!want_iref);
11817d5e005dSAmir Goldstein 	fsn_mark->flags &= ~FSNOTIFY_MARK_FLAG_NO_IREF;
11827d5e005dSAmir Goldstein 
11837d5e005dSAmir Goldstein 	return true;
11848998d110SAmir Goldstein }
11858998d110SAmir Goldstein 
fanotify_mark_add_to_mask(struct fsnotify_mark * fsn_mark,__u32 mask,unsigned int fan_flags)11868998d110SAmir Goldstein static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
11878998d110SAmir Goldstein 				      __u32 mask, unsigned int fan_flags)
1188912ee394SAndreas Gruenbacher {
11898998d110SAmir Goldstein 	bool recalc;
1190912ee394SAndreas Gruenbacher 
1191912ee394SAndreas Gruenbacher 	spin_lock(&fsn_mark->lock);
1192e252f2edSAmir Goldstein 	if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS))
1193a72fd224SAmir Goldstein 		fsn_mark->mask |= mask;
11948998d110SAmir Goldstein 	else
119531a371e4SAmir Goldstein 		fsn_mark->ignore_mask |= mask;
11968998d110SAmir Goldstein 
11978998d110SAmir Goldstein 	recalc = fsnotify_calc_mask(fsn_mark) &
11988998d110SAmir Goldstein 		~fsnotify_conn_mask(fsn_mark->connector);
11998998d110SAmir Goldstein 
12008998d110SAmir Goldstein 	recalc |= fanotify_mark_update_flags(fsn_mark, fan_flags);
1201912ee394SAndreas Gruenbacher 	spin_unlock(&fsn_mark->lock);
1202912ee394SAndreas Gruenbacher 
12038998d110SAmir Goldstein 	return recalc;
1204912ee394SAndreas Gruenbacher }
1205912ee394SAndreas Gruenbacher 
fanotify_add_new_mark(struct fsnotify_group * group,fsnotify_connp_t * connp,unsigned int obj_type,unsigned int fan_flags,__kernel_fsid_t * fsid)12065e9c070cSLino Sanfilippo static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
1207b812a9f5SAmir Goldstein 						   fsnotify_connp_t *connp,
1208ad69cd99SAmir Goldstein 						   unsigned int obj_type,
12097d5e005dSAmir Goldstein 						   unsigned int fan_flags,
121077115225SAmir Goldstein 						   __kernel_fsid_t *fsid)
12115e9c070cSLino Sanfilippo {
12125b8fea65SAmir Goldstein 	struct ucounts *ucounts = group->fanotify_data.ucounts;
12135e9c070cSLino Sanfilippo 	struct fsnotify_mark *mark;
12145e9c070cSLino Sanfilippo 	int ret;
12155e9c070cSLino Sanfilippo 
12165b8fea65SAmir Goldstein 	/*
12175b8fea65SAmir Goldstein 	 * Enforce per user marks limits per user in all containing user ns.
12185b8fea65SAmir Goldstein 	 * A group with FAN_UNLIMITED_MARKS does not contribute to mark count
12195b8fea65SAmir Goldstein 	 * in the limited groups account.
12205b8fea65SAmir Goldstein 	 */
12215b8fea65SAmir Goldstein 	if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS) &&
12225b8fea65SAmir Goldstein 	    !inc_ucount(ucounts->ns, ucounts->uid, UCOUNT_FANOTIFY_MARKS))
12235e9c070cSLino Sanfilippo 		return ERR_PTR(-ENOSPC);
12245e9c070cSLino Sanfilippo 
12255e9c070cSLino Sanfilippo 	mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
12265b8fea65SAmir Goldstein 	if (!mark) {
12275b8fea65SAmir Goldstein 		ret = -ENOMEM;
12285b8fea65SAmir Goldstein 		goto out_dec_ucounts;
12295b8fea65SAmir Goldstein 	}
12305e9c070cSLino Sanfilippo 
1231054c636eSJan Kara 	fsnotify_init_mark(mark, group);
12327d5e005dSAmir Goldstein 	if (fan_flags & FAN_MARK_EVICTABLE)
12337d5e005dSAmir Goldstein 		mark->flags |= FSNOTIFY_MARK_FLAG_NO_IREF;
12347d5e005dSAmir Goldstein 
1235ad69cd99SAmir Goldstein 	ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid);
12365e9c070cSLino Sanfilippo 	if (ret) {
12375e9c070cSLino Sanfilippo 		fsnotify_put_mark(mark);
12385b8fea65SAmir Goldstein 		goto out_dec_ucounts;
12395e9c070cSLino Sanfilippo 	}
12405e9c070cSLino Sanfilippo 
12415e9c070cSLino Sanfilippo 	return mark;
12425b8fea65SAmir Goldstein 
12435b8fea65SAmir Goldstein out_dec_ucounts:
12445b8fea65SAmir Goldstein 	if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS))
12455b8fea65SAmir Goldstein 		dec_ucount(ucounts, UCOUNT_FANOTIFY_MARKS);
12465b8fea65SAmir Goldstein 	return ERR_PTR(ret);
12475e9c070cSLino Sanfilippo }
12485e9c070cSLino Sanfilippo 
fanotify_group_init_error_pool(struct fsnotify_group * group)1249734a1a5eSGabriel Krisman Bertazi static int fanotify_group_init_error_pool(struct fsnotify_group *group)
1250734a1a5eSGabriel Krisman Bertazi {
1251734a1a5eSGabriel Krisman Bertazi 	if (mempool_initialized(&group->fanotify_data.error_events_pool))
1252734a1a5eSGabriel Krisman Bertazi 		return 0;
1253734a1a5eSGabriel Krisman Bertazi 
1254734a1a5eSGabriel Krisman Bertazi 	return mempool_init_kmalloc_pool(&group->fanotify_data.error_events_pool,
1255734a1a5eSGabriel Krisman Bertazi 					 FANOTIFY_DEFAULT_FEE_POOL_SIZE,
1256734a1a5eSGabriel Krisman Bertazi 					 sizeof(struct fanotify_error_event));
1257734a1a5eSGabriel Krisman Bertazi }
12585e9c070cSLino Sanfilippo 
fanotify_may_update_existing_mark(struct fsnotify_mark * fsn_mark,unsigned int fan_flags)12598afd7215SAmir Goldstein static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
12608afd7215SAmir Goldstein 					      unsigned int fan_flags)
12618afd7215SAmir Goldstein {
12628afd7215SAmir Goldstein 	/*
12638afd7215SAmir Goldstein 	 * Non evictable mark cannot be downgraded to evictable mark.
12648afd7215SAmir Goldstein 	 */
12658afd7215SAmir Goldstein 	if (fan_flags & FAN_MARK_EVICTABLE &&
12668afd7215SAmir Goldstein 	    !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF))
12678afd7215SAmir Goldstein 		return -EEXIST;
12688afd7215SAmir Goldstein 
1269e252f2edSAmir Goldstein 	/*
1270e252f2edSAmir Goldstein 	 * New ignore mask semantics cannot be downgraded to old semantics.
1271e252f2edSAmir Goldstein 	 */
1272e252f2edSAmir Goldstein 	if (fan_flags & FAN_MARK_IGNORED_MASK &&
1273e252f2edSAmir Goldstein 	    fsn_mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS)
1274e252f2edSAmir Goldstein 		return -EEXIST;
1275e252f2edSAmir Goldstein 
1276e252f2edSAmir Goldstein 	/*
1277e252f2edSAmir Goldstein 	 * An ignore mask that survives modify could never be downgraded to not
1278e252f2edSAmir Goldstein 	 * survive modify.  With new FAN_MARK_IGNORE semantics we make that rule
1279e252f2edSAmir Goldstein 	 * explicit and return an error when trying to update the ignore mask
1280e252f2edSAmir Goldstein 	 * without the original FAN_MARK_IGNORED_SURV_MODIFY value.
1281e252f2edSAmir Goldstein 	 */
1282e252f2edSAmir Goldstein 	if (fan_flags & FAN_MARK_IGNORE &&
1283e252f2edSAmir Goldstein 	    !(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1284e252f2edSAmir Goldstein 	    fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
1285e252f2edSAmir Goldstein 		return -EEXIST;
1286e252f2edSAmir Goldstein 
12878afd7215SAmir Goldstein 	return 0;
12888afd7215SAmir Goldstein }
12898afd7215SAmir Goldstein 
fanotify_add_mark(struct fsnotify_group * group,fsnotify_connp_t * connp,unsigned int obj_type,__u32 mask,unsigned int fan_flags,__kernel_fsid_t * fsid)1290eaa2c6b0SAmir Goldstein static int fanotify_add_mark(struct fsnotify_group *group,
1291ad69cd99SAmir Goldstein 			     fsnotify_connp_t *connp, unsigned int obj_type,
12928998d110SAmir Goldstein 			     __u32 mask, unsigned int fan_flags,
129377115225SAmir Goldstein 			     __kernel_fsid_t *fsid)
12942a3edf86SEric Paris {
12952a3edf86SEric Paris 	struct fsnotify_mark *fsn_mark;
12968998d110SAmir Goldstein 	bool recalc;
1297734a1a5eSGabriel Krisman Bertazi 	int ret = 0;
129888826276SEric Paris 
1299e79719a2SAmir Goldstein 	fsnotify_group_lock(group);
1300b812a9f5SAmir Goldstein 	fsn_mark = fsnotify_find_mark(connp, group);
130188826276SEric Paris 	if (!fsn_mark) {
13027d5e005dSAmir Goldstein 		fsn_mark = fanotify_add_new_mark(group, connp, obj_type,
13037d5e005dSAmir Goldstein 						 fan_flags, fsid);
13045e9c070cSLino Sanfilippo 		if (IS_ERR(fsn_mark)) {
1305e79719a2SAmir Goldstein 			fsnotify_group_unlock(group);
13065e9c070cSLino Sanfilippo 			return PTR_ERR(fsn_mark);
130788826276SEric Paris 		}
13087b18527cSLino Sanfilippo 	}
1309734a1a5eSGabriel Krisman Bertazi 
1310734a1a5eSGabriel Krisman Bertazi 	/*
13118afd7215SAmir Goldstein 	 * Check if requested mark flags conflict with an existing mark flags.
13127d5e005dSAmir Goldstein 	 */
13138afd7215SAmir Goldstein 	ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags);
13148afd7215SAmir Goldstein 	if (ret)
13157d5e005dSAmir Goldstein 		goto out;
13167d5e005dSAmir Goldstein 
13177d5e005dSAmir Goldstein 	/*
1318734a1a5eSGabriel Krisman Bertazi 	 * Error events are pre-allocated per group, only if strictly
1319734a1a5eSGabriel Krisman Bertazi 	 * needed (i.e. FAN_FS_ERROR was requested).
1320734a1a5eSGabriel Krisman Bertazi 	 */
1321e252f2edSAmir Goldstein 	if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS) &&
1322e252f2edSAmir Goldstein 	    (mask & FAN_FS_ERROR)) {
1323734a1a5eSGabriel Krisman Bertazi 		ret = fanotify_group_init_error_pool(group);
1324734a1a5eSGabriel Krisman Bertazi 		if (ret)
1325734a1a5eSGabriel Krisman Bertazi 			goto out;
1326734a1a5eSGabriel Krisman Bertazi 	}
1327734a1a5eSGabriel Krisman Bertazi 
13288998d110SAmir Goldstein 	recalc = fanotify_mark_add_to_mask(fsn_mark, mask, fan_flags);
13298998d110SAmir Goldstein 	if (recalc)
13303ac70bfcSAmir Goldstein 		fsnotify_recalc_mask(fsn_mark->connector);
1331734a1a5eSGabriel Krisman Bertazi 
1332734a1a5eSGabriel Krisman Bertazi out:
1333e79719a2SAmir Goldstein 	fsnotify_group_unlock(group);
13345e9c070cSLino Sanfilippo 
1335fa218ab9SLino Sanfilippo 	fsnotify_put_mark(fsn_mark);
1336734a1a5eSGabriel Krisman Bertazi 	return ret;
133788826276SEric Paris }
133888826276SEric Paris 
fanotify_add_vfsmount_mark(struct fsnotify_group * group,struct vfsmount * mnt,__u32 mask,unsigned int flags,__kernel_fsid_t * fsid)1339eaa2c6b0SAmir Goldstein static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
1340eaa2c6b0SAmir Goldstein 				      struct vfsmount *mnt, __u32 mask,
134177115225SAmir Goldstein 				      unsigned int flags, __kernel_fsid_t *fsid)
1342eaa2c6b0SAmir Goldstein {
1343eaa2c6b0SAmir Goldstein 	return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
134477115225SAmir Goldstein 				 FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid);
1345eaa2c6b0SAmir Goldstein }
1346eaa2c6b0SAmir Goldstein 
fanotify_add_sb_mark(struct fsnotify_group * group,struct super_block * sb,__u32 mask,unsigned int flags,__kernel_fsid_t * fsid)1347d54f4fbaSAmir Goldstein static int fanotify_add_sb_mark(struct fsnotify_group *group,
1348d54f4fbaSAmir Goldstein 				struct super_block *sb, __u32 mask,
134977115225SAmir Goldstein 				unsigned int flags, __kernel_fsid_t *fsid)
1350d54f4fbaSAmir Goldstein {
1351d54f4fbaSAmir Goldstein 	return fanotify_add_mark(group, &sb->s_fsnotify_marks,
135277115225SAmir Goldstein 				 FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid);
1353d54f4fbaSAmir Goldstein }
1354d54f4fbaSAmir Goldstein 
fanotify_add_inode_mark(struct fsnotify_group * group,struct inode * inode,__u32 mask,unsigned int flags,__kernel_fsid_t * fsid)135552202dfbSAndreas Gruenbacher static int fanotify_add_inode_mark(struct fsnotify_group *group,
1356b9e4e3bdSEric Paris 				   struct inode *inode, __u32 mask,
135777115225SAmir Goldstein 				   unsigned int flags, __kernel_fsid_t *fsid)
135888826276SEric Paris {
135988826276SEric Paris 	pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
13602a3edf86SEric Paris 
13615322a59fSEric Paris 	/*
13625322a59fSEric Paris 	 * If some other task has this inode open for write we should not add
136331a371e4SAmir Goldstein 	 * an ignore mask, unless that ignore mask is supposed to survive
13645322a59fSEric Paris 	 * modification changes anyway.
13655322a59fSEric Paris 	 */
1366e252f2edSAmir Goldstein 	if ((flags & FANOTIFY_MARK_IGNORE_BITS) &&
13675322a59fSEric Paris 	    !(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1368ac9498d6SNikolay Borisov 	    inode_is_open_for_write(inode))
13695322a59fSEric Paris 		return 0;
13705322a59fSEric Paris 
1371eaa2c6b0SAmir Goldstein 	return fanotify_add_mark(group, &inode->i_fsnotify_marks,
137277115225SAmir Goldstein 				 FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid);
13732a3edf86SEric Paris }
13742a3edf86SEric Paris 
fanotify_alloc_overflow_event(void)1375b8a6c3a2SAmir Goldstein static struct fsnotify_event *fanotify_alloc_overflow_event(void)
1376b8a6c3a2SAmir Goldstein {
1377b8a6c3a2SAmir Goldstein 	struct fanotify_event *oevent;
1378b8a6c3a2SAmir Goldstein 
1379b8a6c3a2SAmir Goldstein 	oevent = kmalloc(sizeof(*oevent), GFP_KERNEL_ACCOUNT);
1380b8a6c3a2SAmir Goldstein 	if (!oevent)
1381b8a6c3a2SAmir Goldstein 		return NULL;
1382b8a6c3a2SAmir Goldstein 
1383b8a6c3a2SAmir Goldstein 	fanotify_init_event(oevent, 0, FS_Q_OVERFLOW);
1384b8a6c3a2SAmir Goldstein 	oevent->type = FANOTIFY_EVENT_TYPE_OVERFLOW;
1385b8a6c3a2SAmir Goldstein 
1386b8a6c3a2SAmir Goldstein 	return &oevent->fse;
1387b8a6c3a2SAmir Goldstein }
1388b8a6c3a2SAmir Goldstein 
fanotify_alloc_merge_hash(void)138994e00d28SAmir Goldstein static struct hlist_head *fanotify_alloc_merge_hash(void)
139094e00d28SAmir Goldstein {
139194e00d28SAmir Goldstein 	struct hlist_head *hash;
139294e00d28SAmir Goldstein 
139394e00d28SAmir Goldstein 	hash = kmalloc(sizeof(struct hlist_head) << FANOTIFY_HTABLE_BITS,
139494e00d28SAmir Goldstein 		       GFP_KERNEL_ACCOUNT);
139594e00d28SAmir Goldstein 	if (!hash)
139694e00d28SAmir Goldstein 		return NULL;
139794e00d28SAmir Goldstein 
139894e00d28SAmir Goldstein 	__hash_init(hash, FANOTIFY_HTABLE_SIZE);
139994e00d28SAmir Goldstein 
140094e00d28SAmir Goldstein 	return hash;
140194e00d28SAmir Goldstein }
140294e00d28SAmir Goldstein 
140352c923ddSEric Paris /* fanotify syscalls */
SYSCALL_DEFINE2(fanotify_init,unsigned int,flags,unsigned int,event_f_flags)140408ae8938SEric Paris SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
140511637e4bSEric Paris {
140652c923ddSEric Paris 	struct fsnotify_group *group;
140752c923ddSEric Paris 	int f_flags, fd;
140883b7a598SAmir Goldstein 	unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
140983b7a598SAmir Goldstein 	unsigned int class = flags & FANOTIFY_CLASS_BITS;
1410a8b98c80SAmir Goldstein 	unsigned int internal_flags = 0;
141152c923ddSEric Paris 
141296a71f21SAmir Goldstein 	pr_debug("%s: flags=%x event_f_flags=%x\n",
141308ae8938SEric Paris 		 __func__, flags, event_f_flags);
141452c923ddSEric Paris 
14157cea2a3cSAmir Goldstein 	if (!capable(CAP_SYS_ADMIN)) {
14167cea2a3cSAmir Goldstein 		/*
14177cea2a3cSAmir Goldstein 		 * An unprivileged user can setup an fanotify group with
14187cea2a3cSAmir Goldstein 		 * limited functionality - an unprivileged group is limited to
14197cea2a3cSAmir Goldstein 		 * notification events with file handles and it cannot use
14207cea2a3cSAmir Goldstein 		 * unlimited queue/marks.
14217cea2a3cSAmir Goldstein 		 */
14227cea2a3cSAmir Goldstein 		if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || !fid_mode)
1423a2f13ad0SAndreas Gruenbacher 			return -EPERM;
1424a8b98c80SAmir Goldstein 
1425a8b98c80SAmir Goldstein 		/*
1426a8b98c80SAmir Goldstein 		 * Setting the internal flag FANOTIFY_UNPRIV on the group
1427a8b98c80SAmir Goldstein 		 * prevents setting mount/filesystem marks on this group and
1428a8b98c80SAmir Goldstein 		 * prevents reporting pid and open fd in events.
1429a8b98c80SAmir Goldstein 		 */
1430a8b98c80SAmir Goldstein 		internal_flags |= FANOTIFY_UNPRIV;
14317cea2a3cSAmir Goldstein 	}
143252c923ddSEric Paris 
1433de8cd83eSSteve Grubb #ifdef CONFIG_AUDITSYSCALL
143423c9deebSAmir Goldstein 	if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT))
1435de8cd83eSSteve Grubb #else
143623c9deebSAmir Goldstein 	if (flags & ~FANOTIFY_INIT_FLAGS)
1437de8cd83eSSteve Grubb #endif
143852c923ddSEric Paris 		return -EINVAL;
143952c923ddSEric Paris 
1440af579bebSMatthew Bobrowski 	/*
1441af579bebSMatthew Bobrowski 	 * A pidfd can only be returned for a thread-group leader; thus
1442af579bebSMatthew Bobrowski 	 * FAN_REPORT_PIDFD and FAN_REPORT_TID need to remain mutually
1443af579bebSMatthew Bobrowski 	 * exclusive.
1444af579bebSMatthew Bobrowski 	 */
1445af579bebSMatthew Bobrowski 	if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID))
1446af579bebSMatthew Bobrowski 		return -EINVAL;
1447af579bebSMatthew Bobrowski 
144848149e9dSHeinrich Schuchardt 	if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS)
144948149e9dSHeinrich Schuchardt 		return -EINVAL;
145048149e9dSHeinrich Schuchardt 
145148149e9dSHeinrich Schuchardt 	switch (event_f_flags & O_ACCMODE) {
145248149e9dSHeinrich Schuchardt 	case O_RDONLY:
145348149e9dSHeinrich Schuchardt 	case O_RDWR:
145448149e9dSHeinrich Schuchardt 	case O_WRONLY:
145548149e9dSHeinrich Schuchardt 		break;
145648149e9dSHeinrich Schuchardt 	default:
145748149e9dSHeinrich Schuchardt 		return -EINVAL;
145848149e9dSHeinrich Schuchardt 	}
145948149e9dSHeinrich Schuchardt 
146083b7a598SAmir Goldstein 	if (fid_mode && class != FAN_CLASS_NOTIF)
1461a8b13aa2SAmir Goldstein 		return -EINVAL;
1462a8b13aa2SAmir Goldstein 
1463929943b3SAmir Goldstein 	/*
1464929943b3SAmir Goldstein 	 * Child name is reported with parent fid so requires dir fid.
1465691d9763SAmir Goldstein 	 * We can report both child fid and dir fid with or without name.
1466929943b3SAmir Goldstein 	 */
1467691d9763SAmir Goldstein 	if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID))
146883b7a598SAmir Goldstein 		return -EINVAL;
146983b7a598SAmir Goldstein 
1470d61fd650SAmir Goldstein 	/*
1471d61fd650SAmir Goldstein 	 * FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID
1472d61fd650SAmir Goldstein 	 * and is used as an indication to report both dir and child fid on all
1473d61fd650SAmir Goldstein 	 * dirent events.
1474d61fd650SAmir Goldstein 	 */
1475d61fd650SAmir Goldstein 	if ((fid_mode & FAN_REPORT_TARGET_FID) &&
1476d61fd650SAmir Goldstein 	    (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID)))
1477d61fd650SAmir Goldstein 		return -EINVAL;
1478d61fd650SAmir Goldstein 
1479dccd8557SVasily Averin 	f_flags = O_RDWR | __FMODE_NONOTIFY;
148052c923ddSEric Paris 	if (flags & FAN_CLOEXEC)
148152c923ddSEric Paris 		f_flags |= O_CLOEXEC;
148252c923ddSEric Paris 	if (flags & FAN_NONBLOCK)
148352c923ddSEric Paris 		f_flags |= O_NONBLOCK;
148452c923ddSEric Paris 
148552c923ddSEric Paris 	/* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
1486867a448dSAmir Goldstein 	group = fsnotify_alloc_group(&fanotify_fsnotify_ops,
1487e79719a2SAmir Goldstein 				     FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS);
148826379198SEric Paris 	if (IS_ERR(group)) {
148952c923ddSEric Paris 		return PTR_ERR(group);
149026379198SEric Paris 	}
149152c923ddSEric Paris 
14925b8fea65SAmir Goldstein 	/* Enforce groups limits per user in all containing user ns */
14935b8fea65SAmir Goldstein 	group->fanotify_data.ucounts = inc_ucount(current_user_ns(),
14945b8fea65SAmir Goldstein 						  current_euid(),
14955b8fea65SAmir Goldstein 						  UCOUNT_FANOTIFY_GROUPS);
14965b8fea65SAmir Goldstein 	if (!group->fanotify_data.ucounts) {
14975b8fea65SAmir Goldstein 		fd = -EMFILE;
14985b8fea65SAmir Goldstein 		goto out_destroy_group;
14995b8fea65SAmir Goldstein 	}
15005b8fea65SAmir Goldstein 
1501a8b98c80SAmir Goldstein 	group->fanotify_data.flags = flags | internal_flags;
1502d46eb14bSShakeel Butt 	group->memcg = get_mem_cgroup_from_mm(current->mm);
15034afeff85SEric Paris 
150494e00d28SAmir Goldstein 	group->fanotify_data.merge_hash = fanotify_alloc_merge_hash();
150594e00d28SAmir Goldstein 	if (!group->fanotify_data.merge_hash) {
150694e00d28SAmir Goldstein 		fd = -ENOMEM;
150794e00d28SAmir Goldstein 		goto out_destroy_group;
150894e00d28SAmir Goldstein 	}
150994e00d28SAmir Goldstein 
1510b8a6c3a2SAmir Goldstein 	group->overflow_event = fanotify_alloc_overflow_event();
1511b8a6c3a2SAmir Goldstein 	if (unlikely(!group->overflow_event)) {
1512ff57cd58SJan Kara 		fd = -ENOMEM;
1513ff57cd58SJan Kara 		goto out_destroy_group;
1514ff57cd58SJan Kara 	}
1515ff57cd58SJan Kara 
15161e2ee49fSWill Woods 	if (force_o_largefile())
15171e2ee49fSWill Woods 		event_f_flags |= O_LARGEFILE;
151880af2588SEric Paris 	group->fanotify_data.f_flags = event_f_flags;
15199e66e423SEric Paris 	init_waitqueue_head(&group->fanotify_data.access_waitq);
15209e66e423SEric Paris 	INIT_LIST_HEAD(&group->fanotify_data.access_list);
152183b7a598SAmir Goldstein 	switch (class) {
15224231a235SEric Paris 	case FAN_CLASS_NOTIF:
15234231a235SEric Paris 		group->priority = FS_PRIO_0;
15244231a235SEric Paris 		break;
15254231a235SEric Paris 	case FAN_CLASS_CONTENT:
15264231a235SEric Paris 		group->priority = FS_PRIO_1;
15274231a235SEric Paris 		break;
15284231a235SEric Paris 	case FAN_CLASS_PRE_CONTENT:
15294231a235SEric Paris 		group->priority = FS_PRIO_2;
15304231a235SEric Paris 		break;
15314231a235SEric Paris 	default:
15324231a235SEric Paris 		fd = -EINVAL;
1533d8153d4dSLino Sanfilippo 		goto out_destroy_group;
15344231a235SEric Paris 	}
1535cb2d429fSEric Paris 
15365dd03f55SEric Paris 	if (flags & FAN_UNLIMITED_QUEUE) {
15375dd03f55SEric Paris 		fd = -EPERM;
15385dd03f55SEric Paris 		if (!capable(CAP_SYS_ADMIN))
1539d8153d4dSLino Sanfilippo 			goto out_destroy_group;
15405dd03f55SEric Paris 		group->max_events = UINT_MAX;
15415dd03f55SEric Paris 	} else {
15425b8fea65SAmir Goldstein 		group->max_events = fanotify_max_queued_events;
15435dd03f55SEric Paris 	}
15442529a0dfSEric Paris 
1545ac7e22dcSEric Paris 	if (flags & FAN_UNLIMITED_MARKS) {
1546ac7e22dcSEric Paris 		fd = -EPERM;
1547ac7e22dcSEric Paris 		if (!capable(CAP_SYS_ADMIN))
1548d8153d4dSLino Sanfilippo 			goto out_destroy_group;
1549ac7e22dcSEric Paris 	}
1550e7099d8aSEric Paris 
1551de8cd83eSSteve Grubb 	if (flags & FAN_ENABLE_AUDIT) {
1552de8cd83eSSteve Grubb 		fd = -EPERM;
1553de8cd83eSSteve Grubb 		if (!capable(CAP_AUDIT_WRITE))
1554de8cd83eSSteve Grubb 			goto out_destroy_group;
1555de8cd83eSSteve Grubb 	}
1556de8cd83eSSteve Grubb 
155752c923ddSEric Paris 	fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
155852c923ddSEric Paris 	if (fd < 0)
1559d8153d4dSLino Sanfilippo 		goto out_destroy_group;
156052c923ddSEric Paris 
156152c923ddSEric Paris 	return fd;
156252c923ddSEric Paris 
1563d8153d4dSLino Sanfilippo out_destroy_group:
1564d8153d4dSLino Sanfilippo 	fsnotify_destroy_group(group);
156552c923ddSEric Paris 	return fd;
156611637e4bSEric Paris }
1567bbaa4168SEric Paris 
fanotify_test_fsid(struct dentry * dentry,__kernel_fsid_t * fsid)15688299212cSGabriel Krisman Bertazi static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid)
1569a8b13aa2SAmir Goldstein {
157073072283SAmir Goldstein 	__kernel_fsid_t root_fsid;
1571a8b13aa2SAmir Goldstein 	int err;
1572a8b13aa2SAmir Goldstein 
1573a8b13aa2SAmir Goldstein 	/*
15748299212cSGabriel Krisman Bertazi 	 * Make sure dentry is not of a filesystem with zero fsid (e.g. fuse).
1575a8b13aa2SAmir Goldstein 	 */
15768299212cSGabriel Krisman Bertazi 	err = vfs_get_fsid(dentry, fsid);
1577a8b13aa2SAmir Goldstein 	if (err)
1578a8b13aa2SAmir Goldstein 		return err;
1579a8b13aa2SAmir Goldstein 
158073072283SAmir Goldstein 	if (!fsid->val[0] && !fsid->val[1])
1581a8b13aa2SAmir Goldstein 		return -ENODEV;
1582a8b13aa2SAmir Goldstein 
1583a8b13aa2SAmir Goldstein 	/*
15848299212cSGabriel Krisman Bertazi 	 * Make sure dentry is not of a filesystem subvolume (e.g. btrfs)
1585a8b13aa2SAmir Goldstein 	 * which uses a different fsid than sb root.
1586a8b13aa2SAmir Goldstein 	 */
15878299212cSGabriel Krisman Bertazi 	err = vfs_get_fsid(dentry->d_sb->s_root, &root_fsid);
1588a8b13aa2SAmir Goldstein 	if (err)
1589a8b13aa2SAmir Goldstein 		return err;
1590a8b13aa2SAmir Goldstein 
159173072283SAmir Goldstein 	if (root_fsid.val[0] != fsid->val[0] ||
159273072283SAmir Goldstein 	    root_fsid.val[1] != fsid->val[1])
1593a8b13aa2SAmir Goldstein 		return -EXDEV;
1594a8b13aa2SAmir Goldstein 
15958299212cSGabriel Krisman Bertazi 	return 0;
15968299212cSGabriel Krisman Bertazi }
15978299212cSGabriel Krisman Bertazi 
15988299212cSGabriel Krisman Bertazi /* Check if filesystem can encode a unique fid */
fanotify_test_fid(struct dentry * dentry,unsigned int flags)159997ac4897SAmir Goldstein static int fanotify_test_fid(struct dentry *dentry, unsigned int flags)
16008299212cSGabriel Krisman Bertazi {
160197ac4897SAmir Goldstein 	unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
160297ac4897SAmir Goldstein 	const struct export_operations *nop = dentry->d_sb->s_export_op;
160397ac4897SAmir Goldstein 
1604a8b13aa2SAmir Goldstein 	/*
160597ac4897SAmir Goldstein 	 * We need to make sure that the filesystem supports encoding of
160697ac4897SAmir Goldstein 	 * file handles so user can use name_to_handle_at() to compare fids
160797ac4897SAmir Goldstein 	 * reported with events to the file handle of watched objects.
1608a8b13aa2SAmir Goldstein 	 */
160997ac4897SAmir Goldstein 	if (!nop)
161097ac4897SAmir Goldstein 		return -EOPNOTSUPP;
161197ac4897SAmir Goldstein 
161297ac4897SAmir Goldstein 	/*
161397ac4897SAmir Goldstein 	 * For sb/mount mark, we also need to make sure that the filesystem
161497ac4897SAmir Goldstein 	 * supports decoding file handles, so user has a way to map back the
161597ac4897SAmir Goldstein 	 * reported fids to filesystem objects.
161697ac4897SAmir Goldstein 	 */
161797ac4897SAmir Goldstein 	if (mark_type != FAN_MARK_INODE && !nop->fh_to_dentry)
1618a8b13aa2SAmir Goldstein 		return -EOPNOTSUPP;
1619a8b13aa2SAmir Goldstein 
1620a8b13aa2SAmir Goldstein 	return 0;
1621a8b13aa2SAmir Goldstein }
1622a8b13aa2SAmir Goldstein 
fanotify_events_supported(struct fsnotify_group * group,const struct path * path,__u64 mask,unsigned int flags)16238698e3baSAmir Goldstein static int fanotify_events_supported(struct fsnotify_group *group,
1624d5bf8889SAl Viro 				     const struct path *path, __u64 mask,
16258698e3baSAmir Goldstein 				     unsigned int flags)
16260b3b094aSJan Kara {
16278698e3baSAmir Goldstein 	unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
16288698e3baSAmir Goldstein 	/* Strict validation of events in non-dir inode mask with v5.17+ APIs */
16298698e3baSAmir Goldstein 	bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) ||
1630e252f2edSAmir Goldstein 				 (mask & FAN_RENAME) ||
1631e252f2edSAmir Goldstein 				 (flags & FAN_MARK_IGNORE);
16328698e3baSAmir Goldstein 
16330b3b094aSJan Kara 	/*
16340b3b094aSJan Kara 	 * Some filesystems such as 'proc' acquire unusual locks when opening
16350b3b094aSJan Kara 	 * files. For them fanotify permission events have high chances of
16360b3b094aSJan Kara 	 * deadlocking the system - open done when reporting fanotify event
16370b3b094aSJan Kara 	 * blocks on this "unusual" lock while another process holding the lock
16380b3b094aSJan Kara 	 * waits for fanotify permission event to be answered. Just disallow
16390b3b094aSJan Kara 	 * permission events for such filesystems.
16400b3b094aSJan Kara 	 */
16410b3b094aSJan Kara 	if (mask & FANOTIFY_PERM_EVENTS &&
16420b3b094aSJan Kara 	    path->mnt->mnt_sb->s_type->fs_flags & FS_DISALLOW_NOTIFY_PERM)
16430b3b094aSJan Kara 		return -EINVAL;
16448698e3baSAmir Goldstein 
16458698e3baSAmir Goldstein 	/*
164669562eb0SAmir Goldstein 	 * mount and sb marks are not allowed on kernel internal pseudo fs,
164769562eb0SAmir Goldstein 	 * like pipe_mnt, because that would subscribe to events on all the
164869562eb0SAmir Goldstein 	 * anonynous pipes in the system.
164969562eb0SAmir Goldstein 	 *
165069562eb0SAmir Goldstein 	 * SB_NOUSER covers all of the internal pseudo fs whose objects are not
165169562eb0SAmir Goldstein 	 * exposed to user's mount namespace, but there are other SB_KERNMOUNT
165269562eb0SAmir Goldstein 	 * fs, like nsfs, debugfs, for which the value of allowing sb and mount
165369562eb0SAmir Goldstein 	 * mark is questionable. For now we leave them alone.
165469562eb0SAmir Goldstein 	 */
165569562eb0SAmir Goldstein 	if (mark_type != FAN_MARK_INODE &&
165669562eb0SAmir Goldstein 	    path->mnt->mnt_sb->s_flags & SB_NOUSER)
165769562eb0SAmir Goldstein 		return -EINVAL;
165869562eb0SAmir Goldstein 
165969562eb0SAmir Goldstein 	/*
16608698e3baSAmir Goldstein 	 * We shouldn't have allowed setting dirent events and the directory
16618698e3baSAmir Goldstein 	 * flags FAN_ONDIR and FAN_EVENT_ON_CHILD in mask of non-dir inode,
16628698e3baSAmir Goldstein 	 * but because we always allowed it, error only when using new APIs.
16638698e3baSAmir Goldstein 	 */
16648698e3baSAmir Goldstein 	if (strict_dir_events && mark_type == FAN_MARK_INODE &&
16658698e3baSAmir Goldstein 	    !d_is_dir(path->dentry) && (mask & FANOTIFY_DIRONLY_EVENT_BITS))
16668698e3baSAmir Goldstein 		return -ENOTDIR;
16678698e3baSAmir Goldstein 
16680b3b094aSJan Kara 	return 0;
16690b3b094aSJan Kara }
16700b3b094aSJan Kara 
do_fanotify_mark(int fanotify_fd,unsigned int flags,__u64 mask,int dfd,const char __user * pathname)1671183caa3cSDominik Brodowski static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
1672183caa3cSDominik Brodowski 			    int dfd, const char  __user *pathname)
1673bbaa4168SEric Paris {
16740ff21db9SEric Paris 	struct inode *inode = NULL;
16750ff21db9SEric Paris 	struct vfsmount *mnt = NULL;
16762a3edf86SEric Paris 	struct fsnotify_group *group;
16772903ff01SAl Viro 	struct fd f;
16782a3edf86SEric Paris 	struct path path;
167973072283SAmir Goldstein 	__kernel_fsid_t __fsid, *fsid = NULL;
1680bdd5a46fSAmir Goldstein 	u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
168123c9deebSAmir Goldstein 	unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
16828afd7215SAmir Goldstein 	unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
1683e252f2edSAmir Goldstein 	unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
1684d809daf1SAmir Goldstein 	unsigned int obj_type, fid_mode;
168585af5d92SAmir Goldstein 	u32 umask = 0;
16862903ff01SAl Viro 	int ret;
16872a3edf86SEric Paris 
16882a3edf86SEric Paris 	pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
16892a3edf86SEric Paris 		 __func__, fanotify_fd, flags, dfd, pathname, mask);
16902a3edf86SEric Paris 
16912a3edf86SEric Paris 	/* we only use the lower 32 bits as of right now. */
169222d483b9SChristian Brauner 	if (upper_32_bits(mask))
16932a3edf86SEric Paris 		return -EINVAL;
16942a3edf86SEric Paris 
169523c9deebSAmir Goldstein 	if (flags & ~FANOTIFY_MARK_FLAGS)
169688380fe6SAndreas Gruenbacher 		return -EINVAL;
1697d54f4fbaSAmir Goldstein 
1698d54f4fbaSAmir Goldstein 	switch (mark_type) {
1699d54f4fbaSAmir Goldstein 	case FAN_MARK_INODE:
1700ac5656d8SAaron Goidel 		obj_type = FSNOTIFY_OBJ_TYPE_INODE;
1701ac5656d8SAaron Goidel 		break;
1702d54f4fbaSAmir Goldstein 	case FAN_MARK_MOUNT:
1703ac5656d8SAaron Goidel 		obj_type = FSNOTIFY_OBJ_TYPE_VFSMOUNT;
1704ac5656d8SAaron Goidel 		break;
1705d54f4fbaSAmir Goldstein 	case FAN_MARK_FILESYSTEM:
1706ac5656d8SAaron Goidel 		obj_type = FSNOTIFY_OBJ_TYPE_SB;
1707d54f4fbaSAmir Goldstein 		break;
1708d54f4fbaSAmir Goldstein 	default:
1709d54f4fbaSAmir Goldstein 		return -EINVAL;
1710d54f4fbaSAmir Goldstein 	}
1711d54f4fbaSAmir Goldstein 
17128afd7215SAmir Goldstein 	switch (mark_cmd) {
1713df561f66SGustavo A. R. Silva 	case FAN_MARK_ADD:
171488380fe6SAndreas Gruenbacher 	case FAN_MARK_REMOVE:
17151734dee4SLino Sanfilippo 		if (!mask)
17161734dee4SLino Sanfilippo 			return -EINVAL;
1717cc299a98SHeinrich Schuchardt 		break;
17184d92604cSEric Paris 	case FAN_MARK_FLUSH:
171923c9deebSAmir Goldstein 		if (flags & ~(FANOTIFY_MARK_TYPE_BITS | FAN_MARK_FLUSH))
1720cc299a98SHeinrich Schuchardt 			return -EINVAL;
172188380fe6SAndreas Gruenbacher 		break;
172288380fe6SAndreas Gruenbacher 	default:
172388380fe6SAndreas Gruenbacher 		return -EINVAL;
172488380fe6SAndreas Gruenbacher 	}
17258fcd6528SEric Paris 
17266685df31SMiklos Szeredi 	if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
172723c9deebSAmir Goldstein 		valid_mask |= FANOTIFY_PERM_EVENTS;
17286685df31SMiklos Szeredi 
17296685df31SMiklos Szeredi 	if (mask & ~valid_mask)
17302a3edf86SEric Paris 		return -EINVAL;
17312a3edf86SEric Paris 
1732e252f2edSAmir Goldstein 
1733e252f2edSAmir Goldstein 	/* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */
1734e252f2edSAmir Goldstein 	if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK))
1735e252f2edSAmir Goldstein 		return -EINVAL;
1736e252f2edSAmir Goldstein 
173731a371e4SAmir Goldstein 	/*
173831a371e4SAmir Goldstein 	 * Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with
173931a371e4SAmir Goldstein 	 * FAN_MARK_IGNORED_MASK.
174031a371e4SAmir Goldstein 	 */
1741e252f2edSAmir Goldstein 	if (ignore == FAN_MARK_IGNORED_MASK) {
17423ef86653SAmir Goldstein 		mask &= ~FANOTIFY_EVENT_FLAGS;
1743e252f2edSAmir Goldstein 		umask = FANOTIFY_EVENT_FLAGS;
1744e252f2edSAmir Goldstein 	}
17453ef86653SAmir Goldstein 
17462903ff01SAl Viro 	f = fdget(fanotify_fd);
17472903ff01SAl Viro 	if (unlikely(!f.file))
17482a3edf86SEric Paris 		return -EBADF;
17492a3edf86SEric Paris 
17502a3edf86SEric Paris 	/* verify that this is indeed an fanotify instance */
17512a3edf86SEric Paris 	ret = -EINVAL;
17522903ff01SAl Viro 	if (unlikely(f.file->f_op != &fanotify_fops))
17532a3edf86SEric Paris 		goto fput_and_out;
17542903ff01SAl Viro 	group = f.file->private_data;
17554231a235SEric Paris 
17564231a235SEric Paris 	/*
1757a8b98c80SAmir Goldstein 	 * An unprivileged user is not allowed to setup mount nor filesystem
1758a8b98c80SAmir Goldstein 	 * marks.  This also includes setting up such marks by a group that
1759a8b98c80SAmir Goldstein 	 * was initialized by an unprivileged user.
17607cea2a3cSAmir Goldstein 	 */
17617cea2a3cSAmir Goldstein 	ret = -EPERM;
1762a8b98c80SAmir Goldstein 	if ((!capable(CAP_SYS_ADMIN) ||
1763a8b98c80SAmir Goldstein 	     FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV)) &&
17647cea2a3cSAmir Goldstein 	    mark_type != FAN_MARK_INODE)
17657cea2a3cSAmir Goldstein 		goto fput_and_out;
17667cea2a3cSAmir Goldstein 
17677cea2a3cSAmir Goldstein 	/*
17684231a235SEric Paris 	 * group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF.  These are not
17694231a235SEric Paris 	 * allowed to set permissions events.
17704231a235SEric Paris 	 */
17714231a235SEric Paris 	ret = -EINVAL;
177223c9deebSAmir Goldstein 	if (mask & FANOTIFY_PERM_EVENTS &&
17734231a235SEric Paris 	    group->priority == FS_PRIO_0)
17744231a235SEric Paris 		goto fput_and_out;
17752a3edf86SEric Paris 
17769709bd54SGabriel Krisman Bertazi 	if (mask & FAN_FS_ERROR &&
17779709bd54SGabriel Krisman Bertazi 	    mark_type != FAN_MARK_FILESYSTEM)
17789709bd54SGabriel Krisman Bertazi 		goto fput_and_out;
17799709bd54SGabriel Krisman Bertazi 
1780235328d1SAmir Goldstein 	/*
17817d5e005dSAmir Goldstein 	 * Evictable is only relevant for inode marks, because only inode object
17827d5e005dSAmir Goldstein 	 * can be evicted on memory pressure.
17837d5e005dSAmir Goldstein 	 */
17847d5e005dSAmir Goldstein 	if (flags & FAN_MARK_EVICTABLE &&
17857d5e005dSAmir Goldstein 	     mark_type != FAN_MARK_INODE)
17867d5e005dSAmir Goldstein 		goto fput_and_out;
17877d5e005dSAmir Goldstein 
17887d5e005dSAmir Goldstein 	/*
17894fe595cfSGabriel Krisman Bertazi 	 * Events that do not carry enough information to report
17904fe595cfSGabriel Krisman Bertazi 	 * event->fd require a group that supports reporting fid.  Those
17914fe595cfSGabriel Krisman Bertazi 	 * events are not supported on a mount mark, because they do not
17924fe595cfSGabriel Krisman Bertazi 	 * carry enough information (i.e. path) to be filtered by mount
17934fe595cfSGabriel Krisman Bertazi 	 * point.
1794235328d1SAmir Goldstein 	 */
1795d809daf1SAmir Goldstein 	fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
17964fe595cfSGabriel Krisman Bertazi 	if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_EVENT_FLAGS) &&
1797d809daf1SAmir Goldstein 	    (!fid_mode || mark_type == FAN_MARK_MOUNT))
1798235328d1SAmir Goldstein 		goto fput_and_out;
1799235328d1SAmir Goldstein 
18008cc3b1ccSAmir Goldstein 	/*
18018cc3b1ccSAmir Goldstein 	 * FAN_RENAME uses special info type records to report the old and
18028cc3b1ccSAmir Goldstein 	 * new parent+name.  Reporting only old and new parent id is less
18038cc3b1ccSAmir Goldstein 	 * useful and was not implemented.
18048cc3b1ccSAmir Goldstein 	 */
18058cc3b1ccSAmir Goldstein 	if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME))
18068cc3b1ccSAmir Goldstein 		goto fput_and_out;
18078cc3b1ccSAmir Goldstein 
18088afd7215SAmir Goldstein 	if (mark_cmd == FAN_MARK_FLUSH) {
18090a8dd2dbSHeinrich Schuchardt 		ret = 0;
1810d54f4fbaSAmir Goldstein 		if (mark_type == FAN_MARK_MOUNT)
18110a8dd2dbSHeinrich Schuchardt 			fsnotify_clear_vfsmount_marks_by_group(group);
1812d54f4fbaSAmir Goldstein 		else if (mark_type == FAN_MARK_FILESYSTEM)
1813d54f4fbaSAmir Goldstein 			fsnotify_clear_sb_marks_by_group(group);
18140a8dd2dbSHeinrich Schuchardt 		else
18150a8dd2dbSHeinrich Schuchardt 			fsnotify_clear_inode_marks_by_group(group);
18160a8dd2dbSHeinrich Schuchardt 		goto fput_and_out;
18170a8dd2dbSHeinrich Schuchardt 	}
18180a8dd2dbSHeinrich Schuchardt 
1819ac5656d8SAaron Goidel 	ret = fanotify_find_path(dfd, pathname, &path, flags,
1820ac5656d8SAaron Goidel 			(mask & ALL_FSNOTIFY_EVENTS), obj_type);
18212a3edf86SEric Paris 	if (ret)
18222a3edf86SEric Paris 		goto fput_and_out;
18232a3edf86SEric Paris 
18248afd7215SAmir Goldstein 	if (mark_cmd == FAN_MARK_ADD) {
18258698e3baSAmir Goldstein 		ret = fanotify_events_supported(group, &path, mask, flags);
18260b3b094aSJan Kara 		if (ret)
18270b3b094aSJan Kara 			goto path_put_and_out;
18280b3b094aSJan Kara 	}
18290b3b094aSJan Kara 
1830d809daf1SAmir Goldstein 	if (fid_mode) {
18318299212cSGabriel Krisman Bertazi 		ret = fanotify_test_fsid(path.dentry, &__fsid);
18328299212cSGabriel Krisman Bertazi 		if (ret)
18338299212cSGabriel Krisman Bertazi 			goto path_put_and_out;
18348299212cSGabriel Krisman Bertazi 
183597ac4897SAmir Goldstein 		ret = fanotify_test_fid(path.dentry, flags);
1836a8b13aa2SAmir Goldstein 		if (ret)
1837a8b13aa2SAmir Goldstein 			goto path_put_and_out;
183877115225SAmir Goldstein 
183973072283SAmir Goldstein 		fsid = &__fsid;
1840a8b13aa2SAmir Goldstein 	}
1841a8b13aa2SAmir Goldstein 
18422a3edf86SEric Paris 	/* inode held in place by reference to path; group by fget on fd */
1843d54f4fbaSAmir Goldstein 	if (mark_type == FAN_MARK_INODE)
18442a3edf86SEric Paris 		inode = path.dentry->d_inode;
18450ff21db9SEric Paris 	else
18460ff21db9SEric Paris 		mnt = path.mnt;
18472a3edf86SEric Paris 
1848e252f2edSAmir Goldstein 	ret = mnt ? -EINVAL : -EISDIR;
1849e252f2edSAmir Goldstein 	/* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
1850e252f2edSAmir Goldstein 	if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE &&
1851e252f2edSAmir Goldstein 	    (mnt || S_ISDIR(inode->i_mode)) &&
1852e252f2edSAmir Goldstein 	    !(flags & FAN_MARK_IGNORED_SURV_MODIFY))
1853e252f2edSAmir Goldstein 		goto path_put_and_out;
1854e252f2edSAmir Goldstein 
185585af5d92SAmir Goldstein 	/* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
185685af5d92SAmir Goldstein 	if (mnt || !S_ISDIR(inode->i_mode)) {
185785af5d92SAmir Goldstein 		mask &= ~FAN_EVENT_ON_CHILD;
185885af5d92SAmir Goldstein 		umask = FAN_EVENT_ON_CHILD;
185951280637SAmir Goldstein 		/*
186051280637SAmir Goldstein 		 * If group needs to report parent fid, register for getting
186151280637SAmir Goldstein 		 * events with parent/name info for non-directory.
186251280637SAmir Goldstein 		 */
186351280637SAmir Goldstein 		if ((fid_mode & FAN_REPORT_DIR_FID) &&
186431a371e4SAmir Goldstein 		    (flags & FAN_MARK_ADD) && !ignore)
186551280637SAmir Goldstein 			mask |= FAN_EVENT_ON_CHILD;
186685af5d92SAmir Goldstein 	}
186785af5d92SAmir Goldstein 
18682a3edf86SEric Paris 	/* create/update an inode mark */
18698afd7215SAmir Goldstein 	switch (mark_cmd) {
1870c6223f46SAndreas Gruenbacher 	case FAN_MARK_ADD:
1871d54f4fbaSAmir Goldstein 		if (mark_type == FAN_MARK_MOUNT)
187277115225SAmir Goldstein 			ret = fanotify_add_vfsmount_mark(group, mnt, mask,
187377115225SAmir Goldstein 							 flags, fsid);
1874d54f4fbaSAmir Goldstein 		else if (mark_type == FAN_MARK_FILESYSTEM)
187577115225SAmir Goldstein 			ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask,
187677115225SAmir Goldstein 						   flags, fsid);
18770ff21db9SEric Paris 		else
187877115225SAmir Goldstein 			ret = fanotify_add_inode_mark(group, inode, mask,
187977115225SAmir Goldstein 						      flags, fsid);
1880c6223f46SAndreas Gruenbacher 		break;
1881c6223f46SAndreas Gruenbacher 	case FAN_MARK_REMOVE:
1882d54f4fbaSAmir Goldstein 		if (mark_type == FAN_MARK_MOUNT)
188377115225SAmir Goldstein 			ret = fanotify_remove_vfsmount_mark(group, mnt, mask,
188485af5d92SAmir Goldstein 							    flags, umask);
1885d54f4fbaSAmir Goldstein 		else if (mark_type == FAN_MARK_FILESYSTEM)
188677115225SAmir Goldstein 			ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask,
188785af5d92SAmir Goldstein 						      flags, umask);
1888f3640192SAndreas Gruenbacher 		else
188977115225SAmir Goldstein 			ret = fanotify_remove_inode_mark(group, inode, mask,
189085af5d92SAmir Goldstein 							 flags, umask);
1891c6223f46SAndreas Gruenbacher 		break;
1892c6223f46SAndreas Gruenbacher 	default:
1893c6223f46SAndreas Gruenbacher 		ret = -EINVAL;
1894c6223f46SAndreas Gruenbacher 	}
18952a3edf86SEric Paris 
1896a8b13aa2SAmir Goldstein path_put_and_out:
18972a3edf86SEric Paris 	path_put(&path);
18982a3edf86SEric Paris fput_and_out:
18992903ff01SAl Viro 	fdput(f);
19002a3edf86SEric Paris 	return ret;
1901bbaa4168SEric Paris }
19022a3edf86SEric Paris 
19032ca408d9SBrian Gerst #ifndef CONFIG_ARCH_SPLIT_ARG64
SYSCALL_DEFINE5(fanotify_mark,int,fanotify_fd,unsigned int,flags,__u64,mask,int,dfd,const char __user *,pathname)1904183caa3cSDominik Brodowski SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
1905183caa3cSDominik Brodowski 			      __u64, mask, int, dfd,
1906183caa3cSDominik Brodowski 			      const char  __user *, pathname)
1907183caa3cSDominik Brodowski {
1908183caa3cSDominik Brodowski 	return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname);
1909183caa3cSDominik Brodowski }
19102ca408d9SBrian Gerst #endif
1911183caa3cSDominik Brodowski 
19122ca408d9SBrian Gerst #if defined(CONFIG_ARCH_SPLIT_ARG64) || defined(CONFIG_COMPAT)
SYSCALL32_DEFINE6(fanotify_mark,int,fanotify_fd,unsigned int,flags,SC_ARG64 (mask),int,dfd,const char __user *,pathname)19132ca408d9SBrian Gerst SYSCALL32_DEFINE6(fanotify_mark,
191491c2e0bcSAl Viro 				int, fanotify_fd, unsigned int, flags,
19152ca408d9SBrian Gerst 				SC_ARG64(mask), int, dfd,
191691c2e0bcSAl Viro 				const char  __user *, pathname)
191791c2e0bcSAl Viro {
19182ca408d9SBrian Gerst 	return do_fanotify_mark(fanotify_fd, flags, SC_VAL64(__u64, mask),
191991c2e0bcSAl Viro 				dfd, pathname);
192091c2e0bcSAl Viro }
192191c2e0bcSAl Viro #endif
192291c2e0bcSAl Viro 
19232a3edf86SEric Paris /*
1924ae0e47f0SJustin P. Mattock  * fanotify_user_setup - Our initialization function.  Note that we cannot return
19252a3edf86SEric Paris  * error because we have compiled-in VFS hooks.  So an (unlikely) failure here
19262a3edf86SEric Paris  * must result in panic().
19272a3edf86SEric Paris  */
fanotify_user_setup(void)19282a3edf86SEric Paris static int __init fanotify_user_setup(void)
19292a3edf86SEric Paris {
19305b8fea65SAmir Goldstein 	struct sysinfo si;
19315b8fea65SAmir Goldstein 	int max_marks;
19325b8fea65SAmir Goldstein 
19335b8fea65SAmir Goldstein 	si_meminfo(&si);
19345b8fea65SAmir Goldstein 	/*
19355b8fea65SAmir Goldstein 	 * Allow up to 1% of addressable memory to be accounted for per user
19365b8fea65SAmir Goldstein 	 * marks limited to the range [8192, 1048576]. mount and sb marks are
19375b8fea65SAmir Goldstein 	 * a lot cheaper than inode marks, but there is no reason for a user
19385b8fea65SAmir Goldstein 	 * to have many of those, so calculate by the cost of inode marks.
19395b8fea65SAmir Goldstein 	 */
19405b8fea65SAmir Goldstein 	max_marks = (((si.totalram - si.totalhigh) / 100) << PAGE_SHIFT) /
19415b8fea65SAmir Goldstein 		    INODE_MARK_COST;
19425b8fea65SAmir Goldstein 	max_marks = clamp(max_marks, FANOTIFY_OLD_DEFAULT_MAX_MARKS,
19435b8fea65SAmir Goldstein 				     FANOTIFY_DEFAULT_MAX_USER_MARKS);
19445b8fea65SAmir Goldstein 
1945a8b98c80SAmir Goldstein 	BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS);
1946*ffe1766aSAmir Goldstein 	BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 13);
1947e252f2edSAmir Goldstein 	BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11);
1948bdd5a46fSAmir Goldstein 
1949d46eb14bSShakeel Butt 	fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
1950d46eb14bSShakeel Butt 					 SLAB_PANIC|SLAB_ACCOUNT);
19517088f357SJan Kara 	fanotify_fid_event_cachep = KMEM_CACHE(fanotify_fid_event,
19527088f357SJan Kara 					       SLAB_PANIC);
19537088f357SJan Kara 	fanotify_path_event_cachep = KMEM_CACHE(fanotify_path_event,
19547088f357SJan Kara 						SLAB_PANIC);
19556685df31SMiklos Szeredi 	if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) {
19566685df31SMiklos Szeredi 		fanotify_perm_event_cachep =
195733913997SAmir Goldstein 			KMEM_CACHE(fanotify_perm_event, SLAB_PANIC);
19586685df31SMiklos Szeredi 	}
19592a3edf86SEric Paris 
19605b8fea65SAmir Goldstein 	fanotify_max_queued_events = FANOTIFY_DEFAULT_MAX_EVENTS;
19615b8fea65SAmir Goldstein 	init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS] =
19625b8fea65SAmir Goldstein 					FANOTIFY_DEFAULT_MAX_GROUPS;
19635b8fea65SAmir Goldstein 	init_user_ns.ucount_max[UCOUNT_FANOTIFY_MARKS] = max_marks;
19647b9ad122SXiaoming Ni 	fanotify_sysctls_init();
19655b8fea65SAmir Goldstein 
19662a3edf86SEric Paris 	return 0;
19672a3edf86SEric Paris }
19682a3edf86SEric Paris device_initcall(fanotify_user_setup);
1969