aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify/fanotify.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-01-28 12:29:24 -0500
committerJan Kara <jack@suse.cz>2014-01-29 07:57:04 -0500
commit13116dfd13c8c9d60ea04ece13419af2de8e2e37 (patch)
treebad7a21d6c43925fe4e7102f9816847ed133e775 /fs/notify/fanotify/fanotify.c
parent0e47c969c65e213421450c31043353ebe3c67e0c (diff)
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>
Diffstat (limited to 'fs/notify/fanotify/fanotify.c')
-rw-r--r--fs/notify/fanotify/fanotify.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 58772623f02a..cc78e2fbc8e4 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -16,12 +16,6 @@ static bool should_merge(struct fsnotify_event *old_fsn,
16{ 16{
17 struct fanotify_event_info *old, *new; 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 pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); 19 pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn);
26 old = FANOTIFY_E(old_fsn); 20 old = FANOTIFY_E(old_fsn);
27 new = FANOTIFY_E(new_fsn); 21 new = FANOTIFY_E(new_fsn);
@@ -42,6 +36,16 @@ static struct fsnotify_event *fanotify_merge(struct list_head *list,
42 36
43 pr_debug("%s: list=%p event=%p\n", __func__, list, event); 37 pr_debug("%s: list=%p event=%p\n", __func__, list, event);
44 38
39#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
40 /*
41 * Don't merge a permission event with any other event so that we know
42 * the event structure we have created in fanotify_handle_event() is the
43 * one we should check for permission response.
44 */
45 if (event->mask & FAN_ALL_PERM_EVENTS)
46 return NULL;
47#endif
48
45 list_for_each_entry_reverse(test_event, list, list) { 49 list_for_each_entry_reverse(test_event, list, list) {
46 if (should_merge(test_event, event)) { 50 if (should_merge(test_event, event)) {
47 do_merge = true; 51 do_merge = true;
@@ -195,13 +199,10 @@ static int fanotify_handle_event(struct fsnotify_group *group,
195 fsnotify_destroy_event(group, fsn_event); 199 fsnotify_destroy_event(group, fsn_event);
196 if (IS_ERR(notify_fsn_event)) 200 if (IS_ERR(notify_fsn_event))
197 return PTR_ERR(notify_fsn_event); 201 return PTR_ERR(notify_fsn_event);
198 /* We need to ask about a different events after a merge... */
199 event = FANOTIFY_E(notify_fsn_event);
200 fsn_event = notify_fsn_event;
201 } 202 }
202 203
203#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS 204#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
204 if (fsn_event->mask & FAN_ALL_PERM_EVENTS) 205 if (mask & FAN_ALL_PERM_EVENTS)
205 ret = fanotify_get_response_from_access(group, event); 206 ret = fanotify_get_response_from_access(group, event);
206#endif 207#endif
207 return ret; 208 return ret;