]> bbs.cooldavid.org Git - net-next-2.6.git/blob - fs/notify/fanotify/fanotify_user.c
bc4fa48157f15bd16d43757b201d1b3c54c334f3
[net-next-2.6.git] / fs / notify / fanotify / fanotify_user.c
1 #include <linux/fcntl.h>
2 #include <linux/file.h>
3 #include <linux/fs.h>
4 #include <linux/anon_inodes.h>
5 #include <linux/fsnotify_backend.h>
6 #include <linux/init.h>
7 #include <linux/namei.h>
8 #include <linux/security.h>
9 #include <linux/syscalls.h>
10 #include <linux/types.h>
11
12 #include "fanotify.h"
13
14 static struct kmem_cache *fanotify_mark_cache __read_mostly;
15
16 static int fanotify_release(struct inode *ignored, struct file *file)
17 {
18         struct fsnotify_group *group = file->private_data;
19
20         pr_debug("%s: file=%p group=%p\n", __func__, file, group);
21
22         /* matches the fanotify_init->fsnotify_alloc_group */
23         fsnotify_put_group(group);
24
25         return 0;
26 }
27
28 static const struct file_operations fanotify_fops = {
29         .poll           = NULL,
30         .read           = NULL,
31         .fasync         = NULL,
32         .release        = fanotify_release,
33         .unlocked_ioctl = NULL,
34         .compat_ioctl   = NULL,
35 };
36
37 static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
38 {
39         kmem_cache_free(fanotify_mark_cache, fsn_mark);
40 }
41
42 static int fanotify_find_path(int dfd, const char __user *filename,
43                               struct path *path, unsigned int flags)
44 {
45         int ret;
46
47         pr_debug("%s: dfd=%d filename=%p flags=%x\n", __func__,
48                  dfd, filename, flags);
49
50         if (filename == NULL) {
51                 struct file *file;
52                 int fput_needed;
53
54                 ret = -EBADF;
55                 file = fget_light(dfd, &fput_needed);
56                 if (!file)
57                         goto out;
58
59                 ret = -ENOTDIR;
60                 if ((flags & FAN_MARK_ONLYDIR) &&
61                     !(S_ISDIR(file->f_path.dentry->d_inode->i_mode))) {
62                         fput_light(file, fput_needed);
63                         goto out;
64                 }
65
66                 *path = file->f_path;
67                 path_get(path);
68                 fput_light(file, fput_needed);
69         } else {
70                 unsigned int lookup_flags = 0;
71
72                 if (!(flags & FAN_MARK_DONT_FOLLOW))
73                         lookup_flags |= LOOKUP_FOLLOW;
74                 if (flags & FAN_MARK_ONLYDIR)
75                         lookup_flags |= LOOKUP_DIRECTORY;
76
77                 ret = user_path_at(dfd, filename, lookup_flags, path);
78                 if (ret)
79                         goto out;
80         }
81
82         /* you can only watch an inode if you have read permissions on it */
83         ret = inode_permission(path->dentry->d_inode, MAY_READ);
84         if (ret)
85                 path_put(path);
86 out:
87         return ret;
88 }
89
90 static int fanotify_remove_mark(struct fsnotify_group *group,
91                                 struct inode *inode,
92                                 __u32 mask)
93 {
94         struct fsnotify_mark *fsn_mark;
95         __u32 new_mask;
96
97         pr_debug("%s: group=%p inode=%p mask=%x\n", __func__,
98                  group, inode, mask);
99
100         fsn_mark = fsnotify_find_mark(group, inode);
101         if (!fsn_mark)
102                 return -ENOENT;
103
104         spin_lock(&fsn_mark->lock);
105         fsn_mark->mask &= ~mask;
106         new_mask = fsn_mark->mask;
107         spin_unlock(&fsn_mark->lock);
108
109         if (!new_mask)
110                 fsnotify_destroy_mark(fsn_mark);
111         else
112                 fsnotify_recalc_inode_mask(inode);
113
114         fsnotify_recalc_group_mask(group);
115
116         /* matches the fsnotify_find_mark() */
117         fsnotify_put_mark(fsn_mark);
118
119         return 0;
120 }
121
122 static int fanotify_add_mark(struct fsnotify_group *group,
123                              struct inode *inode,
124                              __u32 mask)
125 {
126         struct fsnotify_mark *fsn_mark;
127         __u32 old_mask, new_mask;
128         int ret;
129
130         pr_debug("%s: group=%p inode=%p mask=%x\n", __func__,
131                  group, inode, mask);
132
133         fsn_mark = fsnotify_find_mark(group, inode);
134         if (!fsn_mark) {
135                 struct fsnotify_mark *new_fsn_mark;
136
137                 ret = -ENOMEM;
138                 new_fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
139                 if (!new_fsn_mark)
140                         goto out;
141
142                 fsnotify_init_mark(new_fsn_mark, fanotify_free_mark);
143                 ret = fsnotify_add_mark(new_fsn_mark, group, inode, 0);
144                 if (ret) {
145                         fanotify_free_mark(new_fsn_mark);
146                         goto out;
147                 }
148
149                 fsn_mark = new_fsn_mark;
150         }
151
152         ret = 0;
153
154         spin_lock(&fsn_mark->lock);
155         old_mask = fsn_mark->mask;
156         fsn_mark->mask |= mask;
157         new_mask = fsn_mark->mask;
158         spin_unlock(&fsn_mark->lock);
159
160         /* we made changes to a mask, update the group mask and the inode mask
161          * so things happen quickly. */
162         if (old_mask != new_mask) {
163                 /* more bits in old than in new? */
164                 int dropped = (old_mask & ~new_mask);
165                 /* more bits in this mark than the inode's mask? */
166                 int do_inode = (new_mask & ~inode->i_fsnotify_mask);
167                 /* more bits in this mark than the group? */
168                 int do_group = (new_mask & ~group->mask);
169
170                 /* update the inode with this new mark */
171                 if (dropped || do_inode)
172                         fsnotify_recalc_inode_mask(inode);
173
174                 /* update the group mask with the new mask */
175                 if (dropped || do_group)
176                         fsnotify_recalc_group_mask(group);
177         }
178
179         /* match the init or the find.... */
180         fsnotify_put_mark(fsn_mark);
181 out:
182         return ret;
183 }
184
185 static int fanotify_update_mark(struct fsnotify_group *group,
186                                 struct inode *inode, int flags,
187                                 __u32 mask)
188 {
189         pr_debug("%s: group=%p inode=%p flags=%x mask=%x\n", __func__,
190                  group, inode, flags, mask);
191
192         if (flags & FAN_MARK_ADD)
193                 fanotify_add_mark(group, inode, mask);
194         else if (flags & FAN_MARK_REMOVE)
195                 fanotify_remove_mark(group, inode, mask);
196         else
197                 BUG();
198
199         return 0;
200 }
201
202 static bool fanotify_mark_validate_input(int flags,
203                                          __u32 mask)
204 {
205         pr_debug("%s: flags=%x mask=%x\n", __func__, flags, mask);
206
207         /* are flags valid of this operation? */
208         if (!fanotify_mark_flags_valid(flags))
209                 return false;
210         /* is the mask valid? */
211         if (!fanotify_mask_valid(mask))
212                 return false;
213         return true;
214 }
215
216 /* fanotify syscalls */
217 SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
218                 unsigned int, priority)
219 {
220         struct fsnotify_group *group;
221         int f_flags, fd;
222
223         pr_debug("%s: flags=%d event_f_flags=%d priority=%d\n",
224                 __func__, flags, event_f_flags, priority);
225
226         if (event_f_flags)
227                 return -EINVAL;
228         if (priority)
229                 return -EINVAL;
230
231         if (!capable(CAP_SYS_ADMIN))
232                 return -EACCES;
233
234         if (flags & ~FAN_ALL_INIT_FLAGS)
235                 return -EINVAL;
236
237         f_flags = (O_RDONLY | FMODE_NONOTIFY);
238         if (flags & FAN_CLOEXEC)
239                 f_flags |= O_CLOEXEC;
240         if (flags & FAN_NONBLOCK)
241                 f_flags |= O_NONBLOCK;
242
243         /* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
244         group = fsnotify_alloc_group(&fanotify_fsnotify_ops);
245         if (IS_ERR(group))
246                 return PTR_ERR(group);
247
248         fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
249         if (fd < 0)
250                 goto out_put_group;
251
252         return fd;
253
254 out_put_group:
255         fsnotify_put_group(group);
256         return fd;
257 }
258
259 SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
260                 __u64, mask, int, dfd, const char  __user *, pathname)
261 {
262         struct inode *inode;
263         struct fsnotify_group *group;
264         struct file *filp;
265         struct path path;
266         int ret, fput_needed;
267
268         pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
269                  __func__, fanotify_fd, flags, dfd, pathname, mask);
270
271         /* we only use the lower 32 bits as of right now. */
272         if (mask & ((__u64)0xffffffff << 32))
273                 return -EINVAL;
274
275         if (!fanotify_mark_validate_input(flags, mask))
276                 return -EINVAL;
277
278         filp = fget_light(fanotify_fd, &fput_needed);
279         if (unlikely(!filp))
280                 return -EBADF;
281
282         /* verify that this is indeed an fanotify instance */
283         ret = -EINVAL;
284         if (unlikely(filp->f_op != &fanotify_fops))
285                 goto fput_and_out;
286
287         ret = fanotify_find_path(dfd, pathname, &path, flags);
288         if (ret)
289                 goto fput_and_out;
290
291         /* inode held in place by reference to path; group by fget on fd */
292         inode = path.dentry->d_inode;
293         group = filp->private_data;
294
295         /* create/update an inode mark */
296         ret = fanotify_update_mark(group, inode, flags, mask);
297
298         path_put(&path);
299 fput_and_out:
300         fput_light(filp, fput_needed);
301         return ret;
302 }
303
304 /*
305  * fanotify_user_setup - Our initialization function.  Note that we cannnot return
306  * error because we have compiled-in VFS hooks.  So an (unlikely) failure here
307  * must result in panic().
308  */
309 static int __init fanotify_user_setup(void)
310 {
311         fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
312
313         return 0;
314 }
315 device_initcall(fanotify_user_setup);