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: Eric Paris <eparis@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Eric Paris and committed by Linus Torvalds eef3a116 0f66f96d

+13 -14
+7 -6
fs/notify/inotify/inotify_fsnotify.c
··· 62 62 event_priv->wd = wd; 63 63 64 64 ret = fsnotify_add_notify_event(group, event, fsn_event_priv); 65 - /* EEXIST is not an error */ 66 - if (ret == -EEXIST) 67 - ret = 0; 68 - 69 - /* did event_priv get attached? */ 70 - if (list_empty(&fsn_event_priv->event_list)) 65 + if (ret) { 71 66 inotify_free_event_priv(fsn_event_priv); 67 + /* EEXIST says we tail matched, EOVERFLOW isn't something 68 + * to report up the stack. */ 69 + if ((ret == -EEXIST) || 70 + (ret == -EOVERFLOW)) 71 + ret = 0; 72 + } 72 73 73 74 /* 74 75 * If we hold the entry until after the event is on the queue
+3 -4
fs/notify/inotify/inotify_user.c
··· 386 386 struct fsnotify_event *ignored_event; 387 387 struct inotify_event_private_data *event_priv; 388 388 struct fsnotify_event_private_data *fsn_event_priv; 389 + int ret; 389 390 390 391 ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL, 391 392 FSNOTIFY_EVENT_NONE, NULL, 0, ··· 405 404 fsn_event_priv->group = group; 406 405 event_priv->wd = ientry->wd; 407 406 408 - fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); 409 - 410 - /* did the private data get added? */ 411 - if (list_empty(&fsn_event_priv->event_list)) 407 + ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); 408 + if (ret) 412 409 inotify_free_event_priv(fsn_event_priv); 413 410 414 411 skip_send_ignore:
+3 -4
fs/notify/notification.c
··· 171 171 struct list_head *list = &group->notification_list; 172 172 struct fsnotify_event_holder *last_holder; 173 173 struct fsnotify_event *last_event; 174 - 175 - /* easy to tell if priv was attached to the event */ 176 - INIT_LIST_HEAD(&priv->event_list); 174 + int ret = 0; 177 175 178 176 /* 179 177 * There is one fsnotify_event_holder embedded inside each fsnotify_event. ··· 192 194 193 195 if (group->q_len >= group->max_events) { 194 196 event = &q_overflow_event; 197 + ret = -EOVERFLOW; 195 198 /* sorry, no private data on the overflow event */ 196 199 priv = NULL; 197 200 } ··· 234 235 mutex_unlock(&group->notification_mutex); 235 236 236 237 wake_up(&group->notification_waitq); 237 - return 0; 238 + return ret; 238 239 } 239 240 240 241 /*