Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fanotify: Fix use after free in mask checking

We cannot use the event structure returned from
fsnotify_add_notify_event() because that event can be freed by the time
that function returns. Use the mask argument passed into the event
handler directly instead. This also fixes a possible problem when we
could unnecessarily wait for permission response for a normal fanotify
event which got merged with a permission event.

We also disallow merging of permission event with any other event so
that we know the permission event which we just created is the one on
which we should wait for permission response.

Reported-and-tested-by: Jiri Kosina <jkosina@suse.cz>
Reported-and-tested-by: Dave Jones <davej@fedoraproject.org>
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 13116dfd 0e47c969

+11 -10
+11 -10
fs/notify/fanotify/fanotify.c
··· 16 16 { 17 17 struct fanotify_event_info *old, *new; 18 18 19 - #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 20 - /* dont merge two permission events */ 21 - if ((old_fsn->mask & FAN_ALL_PERM_EVENTS) && 22 - (new_fsn->mask & FAN_ALL_PERM_EVENTS)) 23 - return false; 24 - #endif 25 19 pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); 26 20 old = FANOTIFY_E(old_fsn); 27 21 new = FANOTIFY_E(new_fsn); ··· 35 41 bool do_merge = false; 36 42 37 43 pr_debug("%s: list=%p event=%p\n", __func__, list, event); 44 + 45 + #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 46 + /* 47 + * Don't merge a permission event with any other event so that we know 48 + * the event structure we have created in fanotify_handle_event() is the 49 + * one we should check for permission response. 50 + */ 51 + if (event->mask & FAN_ALL_PERM_EVENTS) 52 + return NULL; 53 + #endif 38 54 39 55 list_for_each_entry_reverse(test_event, list, list) { 40 56 if (should_merge(test_event, event)) { ··· 199 195 fsnotify_destroy_event(group, fsn_event); 200 196 if (IS_ERR(notify_fsn_event)) 201 197 return PTR_ERR(notify_fsn_event); 202 - /* We need to ask about a different events after a merge... */ 203 - event = FANOTIFY_E(notify_fsn_event); 204 - fsn_event = notify_fsn_event; 205 198 } 206 199 207 200 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 208 - if (fsn_event->mask & FAN_ALL_PERM_EVENTS) 201 + if (mask & FAN_ALL_PERM_EVENTS) 209 202 ret = fanotify_get_response_from_access(group, event); 210 203 #endif 211 204 return ret;