Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eef3a116 authored by Eric Paris's avatar Eric Paris Committed by Linus Torvalds
Browse files

notify: unused event private race



inotify decides if private data it passed to get added to an event was
used by checking list_empty().  But it's possible that the event may
have been dequeued and the private event removed so it would look empty.

The fix is to use the return code from fsnotify_add_notify_event rather
than looking at the list.

Signed-off-by: default avatarEric Paris <eparis@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0f66f96d
Loading
Loading
Loading
Loading
+7 −6
Original line number Original line Diff line number Diff line
@@ -62,13 +62,14 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
	event_priv->wd = wd;
	event_priv->wd = wd;


	ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
	ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
	/* EEXIST is not an error */
	if (ret) {
	if (ret == -EEXIST)
		ret = 0;

	/* did event_priv get attached? */
	if (list_empty(&fsn_event_priv->event_list))
		inotify_free_event_priv(fsn_event_priv);
		inotify_free_event_priv(fsn_event_priv);
		/* EEXIST says we tail matched, EOVERFLOW isn't something
		 * to report up the stack. */
		if ((ret == -EEXIST) ||
		    (ret == -EOVERFLOW))
			ret = 0;
	}


	/*
	/*
	 * If we hold the entry until after the event is on the queue
	 * If we hold the entry until after the event is on the queue
+3 −4
Original line number Original line Diff line number Diff line
@@ -386,6 +386,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
	struct fsnotify_event *ignored_event;
	struct fsnotify_event *ignored_event;
	struct inotify_event_private_data *event_priv;
	struct inotify_event_private_data *event_priv;
	struct fsnotify_event_private_data *fsn_event_priv;
	struct fsnotify_event_private_data *fsn_event_priv;
	int ret;


	ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
	ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
					      FSNOTIFY_EVENT_NONE, NULL, 0,
					      FSNOTIFY_EVENT_NONE, NULL, 0,
@@ -404,10 +405,8 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
	fsn_event_priv->group = group;
	fsn_event_priv->group = group;
	event_priv->wd = ientry->wd;
	event_priv->wd = ientry->wd;


	fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
	ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);

	if (ret)
	/* did the private data get added? */
	if (list_empty(&fsn_event_priv->event_list))
		inotify_free_event_priv(fsn_event_priv);
		inotify_free_event_priv(fsn_event_priv);


skip_send_ignore:
skip_send_ignore:
+3 −4
Original line number Original line Diff line number Diff line
@@ -171,9 +171,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
	struct list_head *list = &group->notification_list;
	struct list_head *list = &group->notification_list;
	struct fsnotify_event_holder *last_holder;
	struct fsnotify_event_holder *last_holder;
	struct fsnotify_event *last_event;
	struct fsnotify_event *last_event;

	int ret = 0;
	/* easy to tell if priv was attached to the event */
	INIT_LIST_HEAD(&priv->event_list);


	/*
	/*
	 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
	 * There is one fsnotify_event_holder embedded inside each fsnotify_event.
@@ -194,6 +192,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even


	if (group->q_len >= group->max_events) {
	if (group->q_len >= group->max_events) {
		event = &q_overflow_event;
		event = &q_overflow_event;
		ret = -EOVERFLOW;
		/* sorry, no private data on the overflow event */
		/* sorry, no private data on the overflow event */
		priv = NULL;
		priv = NULL;
	}
	}
@@ -235,7 +234,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
	mutex_unlock(&group->notification_mutex);
	mutex_unlock(&group->notification_mutex);


	wake_up(&group->notification_waitq);
	wake_up(&group->notification_waitq);
	return 0;
	return ret;
}
}


/*
/*