aboutsummaryrefslogtreecommitdiffstats
path: root/fs/notify/fanotify
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
commitb2d879096ac799722e6017ee82c0586f0d101c9c (patch)
tree3628e99772d2bf51ce736a775a056bffaae44e8c /fs/notify/fanotify
parent9e66e4233db9c7e31e9ee706be2c9ddd54cf99b3 (diff)
fanotify: userspace interface for permission responses
fanotify groups need to respond to events which include permissions types. To do so groups will send a response using write() on the fanotify_fd they have open. Signed-off-by: Eric Paris <eparis@redhat.com>
Diffstat (limited to 'fs/notify/fanotify')
-rw-r--r--fs/notify/fanotify/fanotify.c3
-rw-r--r--fs/notify/fanotify/fanotify_user.c182
2 files changed, 179 insertions, 6 deletions
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index 52d0a55a249e..bbcfccd4a8ea 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -114,6 +114,9 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group,
114 event->response = 0; 114 event->response = 0;
115 spin_unlock(&event->lock); 115 spin_unlock(&event->lock);
116 116
117 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
118 group, event, ret);
119
117 return ret; 120 return ret;
118} 121}
119#endif 122#endif
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 09d9bdb62af3..87f0be852f71 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -18,6 +18,13 @@
18extern const struct fsnotify_ops fanotify_fsnotify_ops; 18extern const struct fsnotify_ops fanotify_fsnotify_ops;
19 19
20static struct kmem_cache *fanotify_mark_cache __read_mostly; 20static struct kmem_cache *fanotify_mark_cache __read_mostly;
21static struct kmem_cache *fanotify_response_event_cache __read_mostly;
22
23struct fanotify_response_event {
24 struct list_head list;
25 __s32 fd;
26 struct fsnotify_event *event;
27};
21 28
22/* 29/*
23 * Get an fsnotify notification event if one exists and is small 30 * Get an fsnotify notification event if one exists and is small
@@ -110,23 +117,152 @@ static ssize_t fill_event_metadata(struct fsnotify_group *group,
110 return metadata->fd; 117 return metadata->fd;
111} 118}
112 119
120#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
121static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group,
122 __s32 fd)
123{
124 struct fanotify_response_event *re, *return_re = NULL;
125
126 mutex_lock(&group->fanotify_data.access_mutex);
127 list_for_each_entry(re, &group->fanotify_data.access_list, list) {
128 if (re->fd != fd)
129 continue;
130
131 list_del_init(&re->list);
132 return_re = re;
133 break;
134 }
135 mutex_unlock(&group->fanotify_data.access_mutex);
136
137 pr_debug("%s: found return_re=%p\n", __func__, return_re);
138
139 return return_re;
140}
141
142static int process_access_response(struct fsnotify_group *group,
143 struct fanotify_response *response_struct)
144{
145 struct fanotify_response_event *re;
146 __s32 fd = response_struct->fd;
147 __u32 response = response_struct->response;
148
149 pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
150 fd, response);
151 /*
152 * make sure the response is valid, if invalid we do nothing and either
153 * userspace can send a valid responce or we will clean it up after the
154 * timeout
155 */
156 switch (response) {
157 case FAN_ALLOW:
158 case FAN_DENY:
159 break;
160 default:
161 return -EINVAL;
162 }
163
164 if (fd < 0)
165 return -EINVAL;
166
167 re = dequeue_re(group, fd);
168 if (!re)
169 return -ENOENT;
170
171 re->event->response = response;
172
173 wake_up(&group->fanotify_data.access_waitq);
174
175 kmem_cache_free(fanotify_response_event_cache, re);
176
177 return 0;
178}
179
180static int prepare_for_access_response(struct fsnotify_group *group,
181 struct fsnotify_event *event,
182 __s32 fd)
183{
184 struct fanotify_response_event *re;
185
186 if (!(event->mask & FAN_ALL_PERM_EVENTS))
187 return 0;
188
189 re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL);
190 if (!re)
191 return -ENOMEM;
192
193 re->event = event;
194 re->fd = fd;
195
196 mutex_lock(&group->fanotify_data.access_mutex);
197 list_add_tail(&re->list, &group->fanotify_data.access_list);
198 mutex_unlock(&group->fanotify_data.access_mutex);
199
200 return 0;
201}
202
203static void remove_access_response(struct fsnotify_group *group,
204 struct fsnotify_event *event,
205 __s32 fd)
206{
207 struct fanotify_response_event *re;
208
209 if (!(event->mask & FAN_ALL_PERM_EVENTS))
210 return;
211
212 re = dequeue_re(group, fd);
213 if (!re)
214 return;
215
216 BUG_ON(re->event != event);
217
218 kmem_cache_free(fanotify_response_event_cache, re);
219
220 return;
221}
222#else
223static int prepare_for_access_response(struct fsnotify_group *group,
224 struct fsnotify_event *event,
225 __s32 fd)
226{
227 return 0;
228}
229
230static void remove_access_response(struct fsnotify_group *group,
231 struct fsnotify_event *event,
232 __s32 fd)
233{
234 return 0;
235}
236#endif
237
113static ssize_t copy_event_to_user(struct fsnotify_group *group, 238static ssize_t copy_event_to_user(struct fsnotify_group *group,
114 struct fsnotify_event *event, 239 struct fsnotify_event *event,
115 char __user *buf) 240 char __user *buf)
116{ 241{
117 struct fanotify_event_metadata fanotify_event_metadata; 242 struct fanotify_event_metadata fanotify_event_metadata;
118 int ret; 243 int fd, ret;
119 244
120 pr_debug("%s: group=%p event=%p\n", __func__, group, event); 245 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
121 246
122 ret = fill_event_metadata(group, &fanotify_event_metadata, event); 247 fd = fill_event_metadata(group, &fanotify_event_metadata, event);
123 if (ret < 0) 248 if (fd < 0)
124 return ret; 249 return fd;
250
251 ret = prepare_for_access_response(group, event, fd);
252 if (ret)
253 goto out_close_fd;
125 254
255 ret = -EFAULT;
126 if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) 256 if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN))
127 return -EFAULT; 257 goto out_kill_access_response;
128 258
129 return FAN_EVENT_METADATA_LEN; 259 return FAN_EVENT_METADATA_LEN;
260
261out_kill_access_response:
262 remove_access_response(group, event, fd);
263out_close_fd:
264 sys_close(fd);
265 return ret;
130} 266}
131 267
132/* intofiy userspace file descriptor functions */ 268/* intofiy userspace file descriptor functions */
@@ -197,6 +333,33 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
197 return ret; 333 return ret;
198} 334}
199 335
336static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
337{
338#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
339 struct fanotify_response response = { .fd = -1, .response = -1 };
340 struct fsnotify_group *group;
341 int ret;
342
343 group = file->private_data;
344
345 if (count > sizeof(response))
346 count = sizeof(response);
347
348 pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
349
350 if (copy_from_user(&response, buf, count))
351 return -EFAULT;
352
353 ret = process_access_response(group, &response);
354 if (ret < 0)
355 count = ret;
356
357 return count;
358#else
359 return -EINVAL;
360#endif
361}
362
200static int fanotify_release(struct inode *ignored, struct file *file) 363static int fanotify_release(struct inode *ignored, struct file *file)
201{ 364{
202 struct fsnotify_group *group = file->private_data; 365 struct fsnotify_group *group = file->private_data;
@@ -237,6 +400,7 @@ static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long ar
237static const struct file_operations fanotify_fops = { 400static const struct file_operations fanotify_fops = {
238 .poll = fanotify_poll, 401 .poll = fanotify_poll,
239 .read = fanotify_read, 402 .read = fanotify_read,
403 .write = fanotify_write,
240 .fasync = NULL, 404 .fasync = NULL,
241 .release = fanotify_release, 405 .release = fanotify_release,
242 .unlocked_ioctl = fanotify_ioctl, 406 .unlocked_ioctl = fanotify_ioctl,
@@ -470,7 +634,7 @@ SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
470 if (flags & ~FAN_ALL_INIT_FLAGS) 634 if (flags & ~FAN_ALL_INIT_FLAGS)
471 return -EINVAL; 635 return -EINVAL;
472 636
473 f_flags = (O_RDONLY | FMODE_NONOTIFY); 637 f_flags = O_RDWR | FMODE_NONOTIFY;
474 if (flags & FAN_CLOEXEC) 638 if (flags & FAN_CLOEXEC)
475 f_flags |= O_CLOEXEC; 639 f_flags |= O_CLOEXEC;
476 if (flags & FAN_NONBLOCK) 640 if (flags & FAN_NONBLOCK)
@@ -527,7 +691,11 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
527 default: 691 default:
528 return -EINVAL; 692 return -EINVAL;
529 } 693 }
694#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
695 if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD))
696#else
530 if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD)) 697 if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD))
698#endif
531 return -EINVAL; 699 return -EINVAL;
532 700
533 filp = fget_light(fanotify_fd, &fput_needed); 701 filp = fget_light(fanotify_fd, &fput_needed);
@@ -600,6 +768,8 @@ SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark);
600static int __init fanotify_user_setup(void) 768static int __init fanotify_user_setup(void)
601{ 769{
602 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC); 770 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
771 fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
772 SLAB_PANIC);
603 773
604 return 0; 774 return 0;
605} 775}