aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify
diff options
context:
space:
mode:
Diffstat (limited to 'fs/notify/fanotify')
-rw-r--r--fs/notify/fanotify/Kconfig14
-rw-r--r--fs/notify/fanotify/fanotify.c54
-rw-r--r--fs/notify/fanotify/fanotify_user.c5
3 files changed, 69 insertions, 4 deletions
diff --git a/fs/notify/fanotify/Kconfig b/fs/notify/fanotify/Kconfig
index 668e5df28e2..566de30395c 100644
--- a/fs/notify/fanotify/Kconfig
+++ b/fs/notify/fanotify/Kconfig
@@ -10,3 +10,17 @@ config FANOTIFY
10 the event. 10 the event.
11 11
12 If unsure, say Y. 12 If unsure, say Y.
13
14config FANOTIFY_ACCESS_PERMISSIONS
15 bool "fanotify permissions checking"
16 depends on FANOTIFY
17 depends on SECURITY
18 default n
19 ---help---
20 Say Y here is you want fanotify listeners to be able to make permissions
21 decisions concerning filesystem events. This is used by some fanotify
22 listeners which need to scan files before allowing the system access to
23 use those files. This is used by some anti-malware vendors and by some
24 hierarchical storage managent systems.
25
26 If unsure, say N.
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 4feed8601e2..52d0a55a249 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -2,9 +2,12 @@
2#include <linux/fdtable.h> 2#include <linux/fdtable.h>
3#include <linux/fsnotify_backend.h> 3#include <linux/fsnotify_backend.h>
4#include <linux/init.h> 4#include <linux/init.h>
5#include <linux/jiffies.h>
5#include <linux/kernel.h> /* UINT_MAX */ 6#include <linux/kernel.h> /* UINT_MAX */
6#include <linux/mount.h> 7#include <linux/mount.h>
8#include <linux/sched.h>
7#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/wait.h>
8 11
9static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) 12static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
10{ 13{
@@ -88,10 +91,37 @@ out:
88 return ret; 91 return ret;
89} 92}
90 93
94#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
95static int fanotify_get_response_from_access(struct fsnotify_group *group,
96 struct fsnotify_event *event)
97{
98 int ret;
99
100 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
101
102 wait_event(group->fanotify_data.access_waitq, event->response);
103
104 /* userspace responded, convert to something usable */
105 spin_lock(&event->lock);
106 switch (event->response) {
107 case FAN_ALLOW:
108 ret = 0;
109 break;
110 case FAN_DENY:
111 default:
112 ret = -EPERM;
113 }
114 event->response = 0;
115 spin_unlock(&event->lock);
116
117 return ret;
118}
119#endif
120
91static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) 121static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
92{ 122{
93 int ret; 123 int ret;
94 struct fsnotify_event *used_event; 124 struct fsnotify_event *notify_event = NULL;
95 125
96 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); 126 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
97 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); 127 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
@@ -100,15 +130,31 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_e
100 BUILD_BUG_ON(FAN_OPEN != FS_OPEN); 130 BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
101 BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD); 131 BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
102 BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW); 132 BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
133 BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
134 BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
103 135
104 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 136 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
105 137
106 ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge, (void **)&used_event); 138 ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge,
139 (void **)&notify_event);
107 /* -EEXIST means this event was merged with another, not that it was an error */ 140 /* -EEXIST means this event was merged with another, not that it was an error */
108 if (ret == -EEXIST) 141 if (ret == -EEXIST)
109 ret = 0; 142 ret = 0;
110 if (used_event) 143 if (ret)
111 fsnotify_put_event(used_event); 144 goto out;
145
146#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
147 if (event->mask & FAN_ALL_PERM_EVENTS) {
148 /* if we merged we need to wait on the new event */
149 if (notify_event)
150 event = notify_event;
151 ret = fanotify_get_response_from_access(group, event);
152 }
153#endif
154
155out:
156 if (notify_event)
157 fsnotify_put_event(notify_event);
112 return ret; 158 return ret;
113} 159}
114 160
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 84d3e2047de..09d9bdb62af 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -482,6 +482,11 @@ SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
482 return PTR_ERR(group); 482 return PTR_ERR(group);
483 483
484 group->priority = priority; 484 group->priority = priority;
485#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
486 mutex_init(&group->fanotify_data.access_mutex);
487 init_waitqueue_head(&group->fanotify_data.access_waitq);
488 INIT_LIST_HEAD(&group->fanotify_data.access_list);
489#endif
485 490
486 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); 491 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
487 if (fd < 0) 492 if (fd < 0)