aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-12-17 21:24:34 -0500
committerEric Paris <eparis@redhat.com>2010-07-28 09:59:02 -0400
commit9e66e4233db9c7e31e9ee706be2c9ddd54cf99b3 (patch)
tree9d778b358fb6e5f02fb2cf634c2163f34982b7dd
parentc4ec54b40d33f8016fea970a383cc584dd0e6019 (diff)
fanotify: permissions and blocking
This is the backend work needed for fanotify to support the new FS_OPEN_PERM and FS_ACCESS_PERM fsnotify events. This is done using the new fsnotify secondary queue. No userspace interface is provided actually respond to or request these events. Signed-off-by: Eric Paris <eparis@redhat.com>
-rw-r--r--fs/notify/fanotify/Kconfig14
-rw-r--r--fs/notify/fanotify/fanotify.c54
-rw-r--r--fs/notify/fanotify/fanotify_user.c5
-rw-r--r--include/linux/fanotify.h18
-rw-r--r--include/linux/fsnotify_backend.h12
5 files changed, 99 insertions, 4 deletions
diff --git a/fs/notify/fanotify/Kconfig b/fs/notify/fanotify/Kconfig
index 668e5df28e28..566de30395c2 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 4feed8601e29..52d0a55a249e 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 84d3e2047de3..09d9bdb62af3 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)
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
index 385896c9f828..02f80676c238 100644
--- a/include/linux/fanotify.h
+++ b/include/linux/fanotify.h
@@ -15,6 +15,9 @@
15/* FIXME currently Q's have no limit.... */ 15/* FIXME currently Q's have no limit.... */
16#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ 16#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
17 17
18#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
19#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
20
18/* helper events */ 21/* helper events */
19#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ 22#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
20 23
@@ -52,7 +55,14 @@
52 FAN_CLOSE |\ 55 FAN_CLOSE |\
53 FAN_OPEN) 56 FAN_OPEN)
54 57
58/*
59 * All events which require a permission response from userspace
60 */
61#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
62 FAN_ACCESS_PERM)
63
55#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\ 64#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\
65 FAN_ALL_PERM_EVENTS |\
56 FAN_Q_OVERFLOW) 66 FAN_Q_OVERFLOW)
57 67
58#define FANOTIFY_METADATA_VERSION 1 68#define FANOTIFY_METADATA_VERSION 1
@@ -65,6 +75,10 @@ struct fanotify_event_metadata {
65 __s64 pid; 75 __s64 pid;
66} __attribute__ ((packed)); 76} __attribute__ ((packed));
67 77
78/* Legit userspace responses to a _PERM event */
79#define FAN_ALLOW 0x01
80#define FAN_DENY 0x02
81
68/* Helper functions to deal with fanotify_event_metadata buffers */ 82/* Helper functions to deal with fanotify_event_metadata buffers */
69#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) 83#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
70 84
@@ -78,5 +92,9 @@ struct fanotify_event_metadata {
78 92
79#ifdef __KERNEL__ 93#ifdef __KERNEL__
80 94
95struct fanotify_wait {
96 struct fsnotify_event *event;
97 __s32 fd;
98};
81#endif /* __KERNEL__ */ 99#endif /* __KERNEL__ */
82#endif /* _LINUX_FANOTIFY_H */ 100#endif /* _LINUX_FANOTIFY_H */
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index c34728e7d8cb..b0d00fd6bfad 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -160,6 +160,14 @@ struct fsnotify_group {
160 struct user_struct *user; 160 struct user_struct *user;
161 } inotify_data; 161 } inotify_data;
162#endif 162#endif
163#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
164 struct fanotify_group_private_data {
165 /* allows a group to block waiting for a userspace response */
166 struct mutex access_mutex;
167 struct list_head access_list;
168 wait_queue_head_t access_waitq;
169 } fanotify_data;
170#endif
163 }; 171 };
164}; 172};
165 173
@@ -227,6 +235,10 @@ struct fsnotify_event {
227 size_t name_len; 235 size_t name_len;
228 struct pid *tgid; 236 struct pid *tgid;
229 237
238#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
239 __u32 response; /* userspace answer to question */
240#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
241
230 struct list_head private_data_list; /* groups can store private data here */ 242 struct list_head private_data_list; /* groups can store private data here */
231}; 243};
232 244