Skip to content

Commit

Permalink
notify: unused event private race
Browse files Browse the repository at this point in the history
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: Eric Paris <eparis@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Eric Paris authored and Linus Torvalds committed Aug 17, 2009
1 parent 0f66f96 commit eef3a11
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 14 deletions.
13 changes: 7 additions & 6 deletions fs/notify/inotify/inotify_fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
event_priv->wd = wd;

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

/* did event_priv get attached? */
if (list_empty(&fsn_event_priv->event_list))
if (ret) {
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
Expand Down
7 changes: 3 additions & 4 deletions fs/notify/inotify/inotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
struct fsnotify_event *ignored_event;
struct inotify_event_private_data *event_priv;
struct fsnotify_event_private_data *fsn_event_priv;
int ret;

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

fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);

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

skip_send_ignore:
Expand Down
7 changes: 3 additions & 4 deletions fs/notify/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
struct list_head *list = &group->notification_list;
struct fsnotify_event_holder *last_holder;
struct fsnotify_event *last_event;

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

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

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

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

/*
Expand Down

0 comments on commit eef3a11

Please sign in to comment.