xref: /linux/fs/notify/inotify/inotify_fsnotify.c (revision c915d8f5)
13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
263c882a0SEric Paris /*
363c882a0SEric Paris  * fs/inotify_user.c - inotify support for userspace
463c882a0SEric Paris  *
563c882a0SEric Paris  * Authors:
663c882a0SEric Paris  *	John McCutchan	<ttb@tentacle.dhs.org>
763c882a0SEric Paris  *	Robert Love	<rml@novell.com>
863c882a0SEric Paris  *
963c882a0SEric Paris  * Copyright (C) 2005 John McCutchan
1063c882a0SEric Paris  * Copyright 2006 Hewlett-Packard Development Company, L.P.
1163c882a0SEric Paris  *
1263c882a0SEric Paris  * Copyright (C) 2009 Eric Paris <Red Hat Inc>
1363c882a0SEric Paris  * inotify was largely rewriten to make use of the fsnotify infrastructure
1463c882a0SEric Paris  */
1563c882a0SEric Paris 
168c1934c8SEric Paris #include <linux/dcache.h> /* d_unlinked */
1763c882a0SEric Paris #include <linux/fs.h> /* struct inode */
1863c882a0SEric Paris #include <linux/fsnotify_backend.h>
1963c882a0SEric Paris #include <linux/inotify.h>
2063c882a0SEric Paris #include <linux/path.h> /* struct path */
2163c882a0SEric Paris #include <linux/slab.h> /* kmem_* */
2263c882a0SEric Paris #include <linux/types.h>
23b3b38d84SPavel Emelyanov #include <linux/sched.h>
245b825c3aSIngo Molnar #include <linux/sched/user.h>
25d46eb14bSShakeel Butt #include <linux/sched/mm.h>
2663c882a0SEric Paris 
2763c882a0SEric Paris #include "inotify.h"
2863c882a0SEric Paris 
2974766bbfSEric Paris /*
307053aee2SJan Kara  * Check if 2 events contain the same information.
3174766bbfSEric Paris  */
event_compare(struct fsnotify_event * old_fsn,struct fsnotify_event * new_fsn)327053aee2SJan Kara static bool event_compare(struct fsnotify_event *old_fsn,
337053aee2SJan Kara 			  struct fsnotify_event *new_fsn)
3474766bbfSEric Paris {
357053aee2SJan Kara 	struct inotify_event_info *old, *new;
367053aee2SJan Kara 
377053aee2SJan Kara 	old = INOTIFY_E(old_fsn);
387053aee2SJan Kara 	new = INOTIFY_E(new_fsn);
39a0a92d26SAmir Goldstein 	if (old->mask & FS_IN_IGNORED)
40a0a92d26SAmir Goldstein 		return false;
41a0a92d26SAmir Goldstein 	if ((old->mask == new->mask) &&
42956235afSAmir Goldstein 	    (old->wd == new->wd) &&
437053aee2SJan Kara 	    (old->name_len == new->name_len) &&
447053aee2SJan Kara 	    (!old->name_len || !strcmp(old->name, new->name)))
4574766bbfSEric Paris 		return true;
4674766bbfSEric Paris 	return false;
4774766bbfSEric Paris }
4874766bbfSEric Paris 
inotify_merge(struct fsnotify_group * group,struct fsnotify_event * event)4994e00d28SAmir Goldstein static int inotify_merge(struct fsnotify_group *group,
50f70ab54cSEric Paris 			 struct fsnotify_event *event)
5174766bbfSEric Paris {
5294e00d28SAmir Goldstein 	struct list_head *list = &group->notification_list;
5374766bbfSEric Paris 	struct fsnotify_event *last_event;
5474766bbfSEric Paris 
557053aee2SJan Kara 	last_event = list_entry(list->prev, struct fsnotify_event, list);
5683c0e1b4SJan Kara 	return event_compare(last_event, event);
5774766bbfSEric Paris }
5874766bbfSEric Paris 
inotify_handle_inode_event(struct fsnotify_mark * inode_mark,u32 mask,struct inode * inode,struct inode * dir,const struct qstr * name,u32 cookie)591a2620a9SAmir Goldstein int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask,
601a2620a9SAmir Goldstein 			       struct inode *inode, struct inode *dir,
611a2620a9SAmir Goldstein 			       const struct qstr *name, u32 cookie)
6263c882a0SEric Paris {
63000285deSEric Paris 	struct inotify_inode_mark *i_mark;
647053aee2SJan Kara 	struct inotify_event_info *event;
657053aee2SJan Kara 	struct fsnotify_event *fsn_event;
661a2620a9SAmir Goldstein 	struct fsnotify_group *group = inode_mark->group;
6783c0e1b4SJan Kara 	int ret;
68*c915d8f5SJan Kara 	int len = 0, wd;
697053aee2SJan Kara 	int alloc_len = sizeof(struct inotify_event_info);
70b87d8cefSRoman Gushchin 	struct mem_cgroup *old_memcg;
7163c882a0SEric Paris 
721a2620a9SAmir Goldstein 	if (name) {
731a2620a9SAmir Goldstein 		len = name->len;
747053aee2SJan Kara 		alloc_len += len + 1;
757053aee2SJan Kara 	}
765ba08e2eSEric Paris 
77b54cecf5SAmir Goldstein 	pr_debug("%s: group=%p mark=%p mask=%x\n", __func__, group, inode_mark,
787053aee2SJan Kara 		 mask);
7963c882a0SEric Paris 
80ce8f76fbSEric Paris 	i_mark = container_of(inode_mark, struct inotify_inode_mark,
81000285deSEric Paris 			      fsn_mark);
8263c882a0SEric Paris 
83ec165450SShakeel Butt 	/*
84*c915d8f5SJan Kara 	 * We can be racing with mark being detached. Don't report event with
85*c915d8f5SJan Kara 	 * invalid wd.
86*c915d8f5SJan Kara 	 */
87*c915d8f5SJan Kara 	wd = READ_ONCE(i_mark->wd);
88*c915d8f5SJan Kara 	if (wd == -1)
89*c915d8f5SJan Kara 		return 0;
90*c915d8f5SJan Kara 	/*
91ec165450SShakeel Butt 	 * Whoever is interested in the event, pays for the allocation. Do not
92ec165450SShakeel Butt 	 * trigger OOM killer in the target monitoring memcg as it may have
93ec165450SShakeel Butt 	 * security repercussion.
94ec165450SShakeel Butt 	 */
95b87d8cefSRoman Gushchin 	old_memcg = set_active_memcg(group->memcg);
96ec165450SShakeel Butt 	event = kmalloc(alloc_len, GFP_KERNEL_ACCOUNT | __GFP_RETRY_MAYFAIL);
97b87d8cefSRoman Gushchin 	set_active_memcg(old_memcg);
98d46eb14bSShakeel Butt 
997b1f6417SJan Kara 	if (unlikely(!event)) {
1007b1f6417SJan Kara 		/*
1017b1f6417SJan Kara 		 * Treat lost event due to ENOMEM the same way as queue
1027b1f6417SJan Kara 		 * overflow to let userspace know event was lost.
1037b1f6417SJan Kara 		 */
1047b1f6417SJan Kara 		fsnotify_queue_overflow(group);
10563c882a0SEric Paris 		return -ENOMEM;
1067b1f6417SJan Kara 	}
10763c882a0SEric Paris 
1080a20df7eSAmir Goldstein 	/*
1090a20df7eSAmir Goldstein 	 * We now report FS_ISDIR flag with MOVE_SELF and DELETE_SELF events
1100a20df7eSAmir Goldstein 	 * for fanotify. inotify never reported IN_ISDIR with those events.
1110a20df7eSAmir Goldstein 	 * It looks like an oversight, but to avoid the risk of breaking
1120a20df7eSAmir Goldstein 	 * existing inotify programs, mask the flag out from those events.
1130a20df7eSAmir Goldstein 	 */
1140a20df7eSAmir Goldstein 	if (mask & (IN_MOVE_SELF | IN_DELETE_SELF))
1150a20df7eSAmir Goldstein 		mask &= ~IN_ISDIR;
1160a20df7eSAmir Goldstein 
1177053aee2SJan Kara 	fsn_event = &event->fse;
1188988f11aSAmir Goldstein 	fsnotify_init_event(fsn_event);
119a0a92d26SAmir Goldstein 	event->mask = mask;
120*c915d8f5SJan Kara 	event->wd = wd;
12145a22f4cSJan Kara 	event->sync_cookie = cookie;
1227053aee2SJan Kara 	event->name_len = len;
1237053aee2SJan Kara 	if (len)
1241a2620a9SAmir Goldstein 		strcpy(event->name, name->name);
12563c882a0SEric Paris 
1261ad03c3aSGabriel Krisman Bertazi 	ret = fsnotify_add_event(group, fsn_event, inotify_merge);
12783c0e1b4SJan Kara 	if (ret) {
1287053aee2SJan Kara 		/* Our event wasn't used in the end. Free it. */
1297053aee2SJan Kara 		fsnotify_destroy_event(group, fsn_event);
130eef3a116SEric Paris 	}
13163c882a0SEric Paris 
13238035c04SAmir Goldstein 	if (inode_mark->flags & FSNOTIFY_MARK_FLAG_IN_ONESHOT)
133e2a29943SLino Sanfilippo 		fsnotify_destroy_mark(inode_mark, group);
13463c882a0SEric Paris 
13583c0e1b4SJan Kara 	return 0;
13663c882a0SEric Paris }
13763c882a0SEric Paris 
inotify_freeing_mark(struct fsnotify_mark * fsn_mark,struct fsnotify_group * group)138000285deSEric Paris static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group)
13963c882a0SEric Paris {
140000285deSEric Paris 	inotify_ignored_and_remove_idr(fsn_mark, group);
14163c882a0SEric Paris }
14263c882a0SEric Paris 
143cf437426SEric Paris /*
144cf437426SEric Paris  * This is NEVER supposed to be called.  Inotify marks should either have been
145cf437426SEric Paris  * removed from the idr when the watch was removed or in the
146cf437426SEric Paris  * fsnotify_destroy_mark_by_group() call when the inotify instance was being
147cf437426SEric Paris  * torn down.  This is only called if the idr is about to be freed but there
148cf437426SEric Paris  * are still marks in it.
149cf437426SEric Paris  */
idr_callback(int id,void * p,void * data)15063c882a0SEric Paris static int idr_callback(int id, void *p, void *data)
15163c882a0SEric Paris {
152000285deSEric Paris 	struct fsnotify_mark *fsn_mark;
153000285deSEric Paris 	struct inotify_inode_mark *i_mark;
154cf437426SEric Paris 	static bool warned = false;
155cf437426SEric Paris 
156cf437426SEric Paris 	if (warned)
157cf437426SEric Paris 		return 0;
158cf437426SEric Paris 
159976ae32bSEric Paris 	warned = true;
160000285deSEric Paris 	fsn_mark = p;
161000285deSEric Paris 	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
162cf437426SEric Paris 
163000285deSEric Paris 	WARN(1, "inotify closing but id=%d for fsn_mark=%p in group=%p still in "
164cf437426SEric Paris 		"idr.  Probably leaking memory\n", id, p, data);
165cf437426SEric Paris 
166cf437426SEric Paris 	/*
167cf437426SEric Paris 	 * I'm taking the liberty of assuming that the mark in question is a
168cf437426SEric Paris 	 * valid address and I'm dereferencing it.  This might help to figure
169cf437426SEric Paris 	 * out why we got here and the panic is no worse than the original
170cf437426SEric Paris 	 * BUG() that was here.
171cf437426SEric Paris 	 */
172000285deSEric Paris 	if (fsn_mark)
17325c829afSJan Kara 		printk(KERN_WARNING "fsn_mark->group=%p wd=%d\n",
17425c829afSJan Kara 			fsn_mark->group, i_mark->wd);
17563c882a0SEric Paris 	return 0;
17663c882a0SEric Paris }
17763c882a0SEric Paris 
inotify_free_group_priv(struct fsnotify_group * group)17863c882a0SEric Paris static void inotify_free_group_priv(struct fsnotify_group *group)
17963c882a0SEric Paris {
18025985edcSLucas De Marchi 	/* ideally the idr is empty and we won't hit the BUG in the callback */
181cf437426SEric Paris 	idr_for_each(&group->inotify_data.idr, idr_callback, group);
18263c882a0SEric Paris 	idr_destroy(&group->inotify_data.idr);
1831cce1eeaSNikolay Borisov 	if (group->inotify_data.ucounts)
1841cce1eeaSNikolay Borisov 		dec_inotify_instances(group->inotify_data.ucounts);
185105d1b42SSasha Levin }
18663c882a0SEric Paris 
inotify_free_event(struct fsnotify_group * group,struct fsnotify_event * fsn_event)187330ae77dSGabriel Krisman Bertazi static void inotify_free_event(struct fsnotify_group *group,
188330ae77dSGabriel Krisman Bertazi 			       struct fsnotify_event *fsn_event)
18963c882a0SEric Paris {
1907053aee2SJan Kara 	kfree(INOTIFY_E(fsn_event));
19163c882a0SEric Paris }
19263c882a0SEric Paris 
193054c636eSJan Kara /* ding dong the mark is dead */
inotify_free_mark(struct fsnotify_mark * fsn_mark)194054c636eSJan Kara static void inotify_free_mark(struct fsnotify_mark *fsn_mark)
195054c636eSJan Kara {
196054c636eSJan Kara 	struct inotify_inode_mark *i_mark;
197054c636eSJan Kara 
198054c636eSJan Kara 	i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
199054c636eSJan Kara 
200054c636eSJan Kara 	kmem_cache_free(inotify_inode_mark_cachep, i_mark);
201054c636eSJan Kara }
202054c636eSJan Kara 
20363c882a0SEric Paris const struct fsnotify_ops inotify_fsnotify_ops = {
2041a2620a9SAmir Goldstein 	.handle_inode_event = inotify_handle_inode_event,
20563c882a0SEric Paris 	.free_group_priv = inotify_free_group_priv,
2067053aee2SJan Kara 	.free_event = inotify_free_event,
20763c882a0SEric Paris 	.freeing_mark = inotify_freeing_mark,
208054c636eSJan Kara 	.free_mark = inotify_free_mark,
20963c882a0SEric Paris };
210