|
@@ -28,14 +28,8 @@
|
|
extern const struct fsnotify_ops fanotify_fsnotify_ops;
|
|
extern const struct fsnotify_ops fanotify_fsnotify_ops;
|
|
|
|
|
|
static struct kmem_cache *fanotify_mark_cache __read_mostly;
|
|
static struct kmem_cache *fanotify_mark_cache __read_mostly;
|
|
-static struct kmem_cache *fanotify_response_event_cache __read_mostly;
|
|
|
|
struct kmem_cache *fanotify_event_cachep __read_mostly;
|
|
struct kmem_cache *fanotify_event_cachep __read_mostly;
|
|
-
|
|
|
|
-struct fanotify_response_event {
|
|
|
|
- struct list_head list;
|
|
|
|
- __s32 fd;
|
|
|
|
- struct fanotify_event_info *event;
|
|
|
|
-};
|
|
|
|
|
|
+struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Get an fsnotify notification event if one exists and is small
|
|
* Get an fsnotify notification event if one exists and is small
|
|
@@ -135,33 +129,34 @@ static int fill_event_metadata(struct fsnotify_group *group,
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
-static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group,
|
|
|
|
- __s32 fd)
|
|
|
|
|
|
+static struct fanotify_perm_event_info *dequeue_event(
|
|
|
|
+ struct fsnotify_group *group, int fd)
|
|
{
|
|
{
|
|
- struct fanotify_response_event *re, *return_re = NULL;
|
|
|
|
|
|
+ struct fanotify_perm_event_info *event, *return_e = NULL;
|
|
|
|
|
|
mutex_lock(&group->fanotify_data.access_mutex);
|
|
mutex_lock(&group->fanotify_data.access_mutex);
|
|
- list_for_each_entry(re, &group->fanotify_data.access_list, list) {
|
|
|
|
- if (re->fd != fd)
|
|
|
|
|
|
+ list_for_each_entry(event, &group->fanotify_data.access_list,
|
|
|
|
+ fae.fse.list) {
|
|
|
|
+ if (event->fd != fd)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- list_del_init(&re->list);
|
|
|
|
- return_re = re;
|
|
|
|
|
|
+ list_del_init(&event->fae.fse.list);
|
|
|
|
+ return_e = event;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
mutex_unlock(&group->fanotify_data.access_mutex);
|
|
mutex_unlock(&group->fanotify_data.access_mutex);
|
|
|
|
|
|
- pr_debug("%s: found return_re=%p\n", __func__, return_re);
|
|
|
|
|
|
+ pr_debug("%s: found return_re=%p\n", __func__, return_e);
|
|
|
|
|
|
- return return_re;
|
|
|
|
|
|
+ return return_e;
|
|
}
|
|
}
|
|
|
|
|
|
static int process_access_response(struct fsnotify_group *group,
|
|
static int process_access_response(struct fsnotify_group *group,
|
|
struct fanotify_response *response_struct)
|
|
struct fanotify_response *response_struct)
|
|
{
|
|
{
|
|
- struct fanotify_response_event *re;
|
|
|
|
- __s32 fd = response_struct->fd;
|
|
|
|
- __u32 response = response_struct->response;
|
|
|
|
|
|
+ struct fanotify_perm_event_info *event;
|
|
|
|
+ int fd = response_struct->fd;
|
|
|
|
+ int response = response_struct->response;
|
|
|
|
|
|
pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
|
|
pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
|
|
fd, response);
|
|
fd, response);
|
|
@@ -181,50 +176,15 @@ static int process_access_response(struct fsnotify_group *group,
|
|
if (fd < 0)
|
|
if (fd < 0)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- re = dequeue_re(group, fd);
|
|
|
|
- if (!re)
|
|
|
|
|
|
+ event = dequeue_event(group, fd);
|
|
|
|
+ if (!event)
|
|
return -ENOENT;
|
|
return -ENOENT;
|
|
|
|
|
|
- re->event->response = response;
|
|
|
|
-
|
|
|
|
|
|
+ event->response = response;
|
|
wake_up(&group->fanotify_data.access_waitq);
|
|
wake_up(&group->fanotify_data.access_waitq);
|
|
|
|
|
|
- kmem_cache_free(fanotify_response_event_cache, re);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int prepare_for_access_response(struct fsnotify_group *group,
|
|
|
|
- struct fsnotify_event *event,
|
|
|
|
- __s32 fd)
|
|
|
|
-{
|
|
|
|
- struct fanotify_response_event *re;
|
|
|
|
-
|
|
|
|
- if (!(event->mask & FAN_ALL_PERM_EVENTS))
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
- re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL);
|
|
|
|
- if (!re)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- re->event = FANOTIFY_E(event);
|
|
|
|
- re->fd = fd;
|
|
|
|
-
|
|
|
|
- mutex_lock(&group->fanotify_data.access_mutex);
|
|
|
|
- list_add_tail(&re->list, &group->fanotify_data.access_list);
|
|
|
|
- mutex_unlock(&group->fanotify_data.access_mutex);
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-#else
|
|
|
|
-static int prepare_for_access_response(struct fsnotify_group *group,
|
|
|
|
- struct fsnotify_event *event,
|
|
|
|
- __s32 fd)
|
|
|
|
-{
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
-
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
|
static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
|
@@ -247,9 +207,18 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
|
fanotify_event_metadata.event_len))
|
|
fanotify_event_metadata.event_len))
|
|
goto out_close_fd;
|
|
goto out_close_fd;
|
|
|
|
|
|
- ret = prepare_for_access_response(group, event, fd);
|
|
|
|
- if (ret)
|
|
|
|
- goto out_close_fd;
|
|
|
|
|
|
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
|
|
+ if (event->mask & FAN_ALL_PERM_EVENTS) {
|
|
|
|
+ struct fanotify_perm_event_info *pevent;
|
|
|
|
+
|
|
|
|
+ pevent = FANOTIFY_PE(event);
|
|
|
|
+ pevent->fd = fd;
|
|
|
|
+ mutex_lock(&group->fanotify_data.access_mutex);
|
|
|
|
+ list_add_tail(&pevent->fae.fse.list,
|
|
|
|
+ &group->fanotify_data.access_list);
|
|
|
|
+ mutex_unlock(&group->fanotify_data.access_mutex);
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
|
|
if (fd != FAN_NOFD)
|
|
if (fd != FAN_NOFD)
|
|
fd_install(fd, f);
|
|
fd_install(fd, f);
|
|
@@ -263,7 +232,7 @@ out_close_fd:
|
|
out:
|
|
out:
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
if (event->mask & FAN_ALL_PERM_EVENTS) {
|
|
if (event->mask & FAN_ALL_PERM_EVENTS) {
|
|
- FANOTIFY_E(event)->response = FAN_DENY;
|
|
|
|
|
|
+ FANOTIFY_PE(event)->response = FAN_DENY;
|
|
wake_up(&group->fanotify_data.access_waitq);
|
|
wake_up(&group->fanotify_data.access_waitq);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -312,8 +281,8 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
|
|
break;
|
|
break;
|
|
ret = copy_event_to_user(group, kevent, buf);
|
|
ret = copy_event_to_user(group, kevent, buf);
|
|
/*
|
|
/*
|
|
- * Permission events get destroyed after we
|
|
|
|
- * receive response
|
|
|
|
|
|
+ * Permission events get queued to wait for response.
|
|
|
|
+ * Other events can be destroyed now.
|
|
*/
|
|
*/
|
|
if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
|
|
if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
|
|
fsnotify_destroy_event(group, kevent);
|
|
fsnotify_destroy_event(group, kevent);
|
|
@@ -375,20 +344,19 @@ static int fanotify_release(struct inode *ignored, struct file *file)
|
|
struct fsnotify_group *group = file->private_data;
|
|
struct fsnotify_group *group = file->private_data;
|
|
|
|
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
- struct fanotify_response_event *re, *lre;
|
|
|
|
|
|
+ struct fanotify_perm_event_info *event, *next;
|
|
|
|
|
|
mutex_lock(&group->fanotify_data.access_mutex);
|
|
mutex_lock(&group->fanotify_data.access_mutex);
|
|
|
|
|
|
atomic_inc(&group->fanotify_data.bypass_perm);
|
|
atomic_inc(&group->fanotify_data.bypass_perm);
|
|
|
|
|
|
- list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) {
|
|
|
|
- pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group,
|
|
|
|
- re, re->event);
|
|
|
|
-
|
|
|
|
- list_del_init(&re->list);
|
|
|
|
- re->event->response = FAN_ALLOW;
|
|
|
|
|
|
+ list_for_each_entry_safe(event, next, &group->fanotify_data.access_list,
|
|
|
|
+ fae.fse.list) {
|
|
|
|
+ pr_debug("%s: found group=%p event=%p\n", __func__, group,
|
|
|
|
+ event);
|
|
|
|
|
|
- kmem_cache_free(fanotify_response_event_cache, re);
|
|
|
|
|
|
+ list_del_init(&event->fae.fse.list);
|
|
|
|
+ event->response = FAN_ALLOW;
|
|
}
|
|
}
|
|
mutex_unlock(&group->fanotify_data.access_mutex);
|
|
mutex_unlock(&group->fanotify_data.access_mutex);
|
|
|
|
|
|
@@ -723,20 +691,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
|
group->fanotify_data.user = user;
|
|
group->fanotify_data.user = user;
|
|
atomic_inc(&user->fanotify_listeners);
|
|
atomic_inc(&user->fanotify_listeners);
|
|
|
|
|
|
- oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL);
|
|
|
|
|
|
+ oevent = fanotify_alloc_event(NULL, FS_Q_OVERFLOW, NULL);
|
|
if (unlikely(!oevent)) {
|
|
if (unlikely(!oevent)) {
|
|
fd = -ENOMEM;
|
|
fd = -ENOMEM;
|
|
goto out_destroy_group;
|
|
goto out_destroy_group;
|
|
}
|
|
}
|
|
group->overflow_event = &oevent->fse;
|
|
group->overflow_event = &oevent->fse;
|
|
- fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW);
|
|
|
|
- oevent->tgid = get_pid(task_tgid(current));
|
|
|
|
- oevent->path.mnt = NULL;
|
|
|
|
- oevent->path.dentry = NULL;
|
|
|
|
|
|
|
|
group->fanotify_data.f_flags = event_f_flags;
|
|
group->fanotify_data.f_flags = event_f_flags;
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
- oevent->response = 0;
|
|
|
|
mutex_init(&group->fanotify_data.access_mutex);
|
|
mutex_init(&group->fanotify_data.access_mutex);
|
|
init_waitqueue_head(&group->fanotify_data.access_waitq);
|
|
init_waitqueue_head(&group->fanotify_data.access_waitq);
|
|
INIT_LIST_HEAD(&group->fanotify_data.access_list);
|
|
INIT_LIST_HEAD(&group->fanotify_data.access_list);
|
|
@@ -912,9 +875,11 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
|
|
static int __init fanotify_user_setup(void)
|
|
static int __init fanotify_user_setup(void)
|
|
{
|
|
{
|
|
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
|
|
fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
|
|
- fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
|
|
|
|
- SLAB_PANIC);
|
|
|
|
fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
|
|
fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
|
|
|
|
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
|
|
|
|
+ fanotify_perm_event_cachep = KMEM_CACHE(fanotify_perm_event_info,
|
|
|
|
+ SLAB_PANIC);
|
|
|
|
+#endif
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|