linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] fsnotify: Fix handling of overflow events
@ 2014-02-24  9:31 Jan Kara
  2014-02-24  9:31 ` [PATCH 1/3] fsnotify: Fix detection whether overflow event is queued Jan Kara
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Jan Kara @ 2014-02-24  9:31 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: poma, Richard Weinberger, LKML, eparis


  Hello,

  these three patches fix problems with overflow events in fanotify and
inotify frameworks. Part of that (patches 1 & 3) is a fallout of my
rewrite of fsnotify framework. I've implemented testing of generation of
overflow events for fanotify and inotify in LTP and with these patches
the tests pass. Please check whether the patches fix problems for you as
well. I plan to push these fixes to Linus soon...

								Honza

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] fsnotify: Fix detection whether overflow event is queued
  2014-02-24  9:31 [PATCH 0/3] fsnotify: Fix handling of overflow events Jan Kara
@ 2014-02-24  9:31 ` Jan Kara
  2014-02-24  9:31 ` [PATCH 2/3] fanotify: Handle overflow in case of permission events Jan Kara
  2014-02-24  9:31 ` [PATCH 3/3] fsnotify: Allocate overflow events with proper type Jan Kara
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Kara @ 2014-02-24  9:31 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: poma, Richard Weinberger, LKML, eparis, Jan Kara

Currently we didn't initialize event's list head when we removed it from
the event list. Thus a detection whether overflow event is already
queued wasn't working. Fix it by always initializing the list head when
deleting event from a list.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/notify/notification.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 18b3c4427dca..6bec2f4918f9 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -132,7 +132,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group
 
 	event = list_first_entry(&group->notification_list,
 				 struct fsnotify_event, list);
-	list_del(&event->list);
+	/*
+	 * We need to init list head for the case of overflow event so that
+	 * check in fsnotify_add_notify_events() works
+	 */
+	list_del_init(&event->list);
 	group->q_len--;
 
 	return event;
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] fanotify: Handle overflow in case of permission events
  2014-02-24  9:31 [PATCH 0/3] fsnotify: Fix handling of overflow events Jan Kara
  2014-02-24  9:31 ` [PATCH 1/3] fsnotify: Fix detection whether overflow event is queued Jan Kara
@ 2014-02-24  9:31 ` Jan Kara
  2014-02-24  9:31 ` [PATCH 3/3] fsnotify: Allocate overflow events with proper type Jan Kara
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Kara @ 2014-02-24  9:31 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: poma, Richard Weinberger, LKML, eparis, Jan Kara

If the event queue overflows when we are handling permission event, we
will never get response from userspace. So we must avoid waiting for it.
Change fsnotify_add_notify_event() to return whether overflow has
happened so that we can detect it in fanotify_handle_event() and act
accordingly.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/notify/fanotify/fanotify.c |  6 ++++--
 fs/notify/notification.c      | 14 ++++++++++----
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 0e792f5e3147..7564a070e6e8 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group,
 
 	ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
 	if (ret) {
-		BUG_ON(mask & FAN_ALL_PERM_EVENTS);
+		/* Permission events shouldn't be merged */
+		BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS);
 		/* Our event wasn't used in the end. Free it. */
 		fsnotify_destroy_event(group, fsn_event);
-		ret = 0;
+
+		return 0;
 	}
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 6bec2f4918f9..6a4ba17c0395 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
 /*
  * Add an event to the group notification queue.  The group can later pull this
  * event off the queue to deal with.  The function returns 0 if the event was
- * added to the queue, 1 if the event was merged with some other queued event.
+ * added to the queue, 1 if the event was merged with some other queued event,
+ * 2 if the queue of events has overflown.
  */
 int fsnotify_add_notify_event(struct fsnotify_group *group,
 			      struct fsnotify_event *event,
@@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
 	mutex_lock(&group->notification_mutex);
 
 	if (group->q_len >= group->max_events) {
+		ret = 2;
 		/* Queue overflow event only if it isn't already queued */
-		if (list_empty(&group->overflow_event.list))
-			event = &group->overflow_event;
-		ret = 1;
+		if (!list_empty(&group->overflow_event.list)) {
+			mutex_unlock(&group->notification_mutex);
+			return ret;
+		}
+		event = &group->overflow_event;
+		goto queue;
 	}
 
 	if (!list_empty(list) && merge) {
@@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
 		}
 	}
 
+queue:
 	group->q_len++;
 	list_add_tail(&event->list, list);
 	mutex_unlock(&group->notification_mutex);
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] fsnotify: Allocate overflow events with proper type
  2014-02-24  9:31 [PATCH 0/3] fsnotify: Fix handling of overflow events Jan Kara
  2014-02-24  9:31 ` [PATCH 1/3] fsnotify: Fix detection whether overflow event is queued Jan Kara
  2014-02-24  9:31 ` [PATCH 2/3] fanotify: Handle overflow in case of permission events Jan Kara
@ 2014-02-24  9:31 ` Jan Kara
  2 siblings, 0 replies; 4+ messages in thread
From: Jan Kara @ 2014-02-24  9:31 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: poma, Richard Weinberger, LKML, eparis, Jan Kara

Commit 7053aee26a35 "fsnotify: do not share events between notification
groups" used overflow event statically allocated in a group with the
size of the generic notification event. This causes problems because
some code looks at type specific parts of event structure and gets
confused by a random data it sees there and causes crashes.

Fix the problem by allocating overflow event with type corresponding to
the group type so code cannot get confused.

Signed-off-by: Jan Kara <jack@suse.cz>
---
 fs/notify/fanotify/fanotify_user.c | 13 +++++++++++++
 fs/notify/group.c                  |  8 +++++++-
 fs/notify/inotify/inotify_user.c   | 12 ++++++++++++
 fs/notify/notification.c           |  4 ++--
 include/linux/fsnotify_backend.h   |  2 +-
 5 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index b6175fa11bf8..287a22c04149 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	struct fsnotify_group *group;
 	int f_flags, fd;
 	struct user_struct *user;
+	struct fanotify_event_info *oevent;
 
 	pr_debug("%s: flags=%d event_f_flags=%d\n",
 		__func__, flags, event_f_flags);
@@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 	group->fanotify_data.user = user;
 	atomic_inc(&user->fanotify_listeners);
 
+	oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
+	if (unlikely(!oevent)) {
+		fd = -ENOMEM;
+		goto out_destroy_group;
+	}
+	group->overflow_event = &oevent->fse;
+	fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+	oevent->tgid = get_pid(task_tgid(current));
+	oevent->path.mnt = NULL;
+	oevent->path.dentry = NULL;
+
 	group->fanotify_data.f_flags = event_f_flags;
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+	oevent->response = 0;
 	mutex_init(&group->fanotify_data.access_mutex);
 	init_waitqueue_head(&group->fanotify_data.access_waitq);
 	INIT_LIST_HEAD(&group->fanotify_data.access_list);
diff --git a/fs/notify/group.c b/fs/notify/group.c
index ee674fe2cec7..ad1995980456 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
 	/* clear the notification queue of all events */
 	fsnotify_flush_notify(group);
 
+	/*
+	 * Destroy overflow event (we cannot use fsnotify_destroy_event() as
+	 * that deliberately ignores overflow events.
+	 */
+	if (group->overflow_event)
+		group->ops->free_event(group->overflow_event);
+
 	fsnotify_put_group(group);
 }
 
@@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
 	INIT_LIST_HEAD(&group->marks_list);
 
 	group->ops = ops;
-	fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW);
 
 	return group;
 }
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index 497395c8274b..99528618d382 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod
 static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 {
 	struct fsnotify_group *group;
+	struct inotify_event_info *oevent;
 
 	group = fsnotify_alloc_group(&inotify_fsnotify_ops);
 	if (IS_ERR(group))
 		return group;
 
+	oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL);
+	if (unlikely(!oevent)) {
+		fsnotify_destroy_group(group);
+		return ERR_PTR(-ENOMEM);
+	}
+	group->overflow_event = &oevent->fse;
+	fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
+	oevent->wd = -1;
+	oevent->sync_cookie = 0;
+	oevent->name_len = 0;
+
 	group->max_events = max_events;
 
 	spin_lock_init(&group->inotify_data.idr_lock);
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index 6a4ba17c0395..1e58402171a5 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -98,11 +98,11 @@ int fsnotify_add_notify_event(struct fsnotify_group *group,
 	if (group->q_len >= group->max_events) {
 		ret = 2;
 		/* Queue overflow event only if it isn't already queued */
-		if (!list_empty(&group->overflow_event.list)) {
+		if (!list_empty(&group->overflow_event->list)) {
 			mutex_unlock(&group->notification_mutex);
 			return ret;
 		}
-		event = &group->overflow_event;
+		event = group->overflow_event;
 		goto queue;
 	}
 
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 3d286ff49ab0..99644e18544a 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -160,7 +160,7 @@ struct fsnotify_group {
 
 	struct fasync_struct *fsn_fa;    /* async notification */
 
-	struct fsnotify_event overflow_event;	/* Event we queue when the
+	struct fsnotify_event *overflow_event;	/* Event we queue when the
 						 * notification list is too
 						 * full */
 
-- 
1.8.1.4

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-02-24  9:31 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-24  9:31 [PATCH 0/3] fsnotify: Fix handling of overflow events Jan Kara
2014-02-24  9:31 ` [PATCH 1/3] fsnotify: Fix detection whether overflow event is queued Jan Kara
2014-02-24  9:31 ` [PATCH 2/3] fanotify: Handle overflow in case of permission events Jan Kara
2014-02-24  9:31 ` [PATCH 3/3] fsnotify: Allocate overflow events with proper type Jan Kara

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).