Commit 85816794 authored by Jan Kara's avatar Jan Kara

fanotify: Fix use after free for permission events

Currently struct fanotify_event_info has been destroyed immediately
after reporting its contents to userspace. However that is wrong for
permission events because those need to stay around until userspace
provides response which is filled back in fanotify_event_info. So change
to code to free permission events only after we have got the response
from userspace.
Reported-and-tested-by: default avatarJiri Kosina <jkosina@suse.cz>
Reported-and-tested-by: default avatarDave Jones <davej@fedoraproject.org>
Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent 83c0e1b4
...@@ -192,14 +192,17 @@ static int fanotify_handle_event(struct fsnotify_group *group, ...@@ -192,14 +192,17 @@ static int fanotify_handle_event(struct fsnotify_group *group,
ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
if (ret) { if (ret) {
BUG_ON(mask & FAN_ALL_PERM_EVENTS);
/* Our event wasn't used in the end. Free it. */ /* Our event wasn't used in the end. Free it. */
fsnotify_destroy_event(group, fsn_event); fsnotify_destroy_event(group, fsn_event);
ret = 0; ret = 0;
} }
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
if (mask & FAN_ALL_PERM_EVENTS) if (mask & FAN_ALL_PERM_EVENTS) {
ret = fanotify_get_response_from_access(group, event); ret = fanotify_get_response_from_access(group, event);
fsnotify_destroy_event(group, fsn_event);
}
#endif #endif
return ret; return ret;
} }
......
...@@ -4,6 +4,13 @@ ...@@ -4,6 +4,13 @@
extern struct kmem_cache *fanotify_event_cachep; extern struct kmem_cache *fanotify_event_cachep;
/*
* Lifetime of the structure differs for normal and permission events. In both
* cases the structure is allocated in fanotify_handle_event(). For normal
* events the structure is freed immediately after reporting it to userspace.
* For permission events we free it only after we receive response from
* userspace.
*/
struct fanotify_event_info { struct fanotify_event_info {
struct fsnotify_event fse; struct fsnotify_event fse;
/* /*
......
...@@ -319,7 +319,12 @@ static ssize_t fanotify_read(struct file *file, char __user *buf, ...@@ -319,7 +319,12 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
if (IS_ERR(kevent)) if (IS_ERR(kevent))
break; break;
ret = copy_event_to_user(group, kevent, buf); ret = copy_event_to_user(group, kevent, buf);
fsnotify_destroy_event(group, kevent); /*
* Permission events get destroyed after we
* receive response
*/
if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
fsnotify_destroy_event(group, kevent);
if (ret < 0) if (ret < 0)
break; break;
buf += ret; buf += ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment