blob: a90bb19dcfa287c34234b2954524d7047481fe40 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Andreas Gruenbacher33d3dff2009-12-17 21:24:29 -05002#include <linux/fanotify.h>
Eric Paris11637e42009-12-17 21:24:25 -05003#include <linux/fcntl.h>
Eric Paris2a3edf82009-12-17 21:24:26 -05004#include <linux/file.h>
Eric Paris11637e42009-12-17 21:24:25 -05005#include <linux/fs.h>
Eric Paris52c923d2009-12-17 21:24:26 -05006#include <linux/anon_inodes.h>
Eric Paris11637e42009-12-17 21:24:25 -05007#include <linux/fsnotify_backend.h>
Eric Paris2a3edf82009-12-17 21:24:26 -05008#include <linux/init.h>
Eric Parisa1014f12009-12-17 21:24:26 -05009#include <linux/mount.h>
Eric Paris2a3edf82009-12-17 21:24:26 -050010#include <linux/namei.h>
Eric Parisa1014f12009-12-17 21:24:26 -050011#include <linux/poll.h>
Eric Paris11637e42009-12-17 21:24:25 -050012#include <linux/security.h>
13#include <linux/syscalls.h>
Tejun Heoe4e047a2010-05-20 01:36:28 +100014#include <linux/slab.h>
Eric Paris2a3edf82009-12-17 21:24:26 -050015#include <linux/types.h>
Eric Parisa1014f12009-12-17 21:24:26 -050016#include <linux/uaccess.h>
Al Viro91c2e0b2013-03-05 20:10:59 -050017#include <linux/compat.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010018#include <linux/sched/signal.h>
Shakeel Buttd46eb14b2018-08-17 15:46:39 -070019#include <linux/memcontrol.h>
Amir Goldsteina8b13aa2019-01-10 19:04:36 +020020#include <linux/statfs.h>
21#include <linux/exportfs.h>
Eric Parisa1014f12009-12-17 21:24:26 -050022
23#include <asm/ioctls.h>
Eric Paris11637e42009-12-17 21:24:25 -050024
Al Viroc63181e2011-11-25 02:35:16 -050025#include "../../mount.h"
Cyrill Gorcunovbe771962012-12-17 16:05:12 -080026#include "../fdinfo.h"
Jan Kara7053aee2014-01-21 15:48:14 -080027#include "fanotify.h"
Al Viroc63181e2011-11-25 02:35:16 -050028
Eric Paris2529a0d2010-10-28 17:21:57 -040029#define FANOTIFY_DEFAULT_MAX_EVENTS 16384
Eric Parise7099d82010-10-28 17:21:57 -040030#define FANOTIFY_DEFAULT_MAX_MARKS 8192
Eric Paris4afeff82010-10-28 17:21:58 -040031#define FANOTIFY_DEFAULT_MAX_LISTENERS 128
Eric Paris2529a0d2010-10-28 17:21:57 -040032
Heinrich Schuchardt48149e92014-06-04 16:05:44 -070033/*
34 * All flags that may be specified in parameter event_f_flags of fanotify_init.
35 *
36 * Internal and external open flags are stored together in field f_flags of
37 * struct file. Only external open flags shall be allowed in event_f_flags.
38 * Internal flags like FMODE_NONOTIFY, FMODE_EXEC, FMODE_NOCMTIME shall be
39 * excluded.
40 */
41#define FANOTIFY_INIT_ALL_EVENT_F_BITS ( \
42 O_ACCMODE | O_APPEND | O_NONBLOCK | \
43 __O_SYNC | O_DSYNC | O_CLOEXEC | \
44 O_LARGEFILE | O_NOATIME )
45
Andreas Gruenbacher33d3dff2009-12-17 21:24:29 -050046extern const struct fsnotify_ops fanotify_fsnotify_ops;
Eric Paris11637e42009-12-17 21:24:25 -050047
Jan Kara054c6362016-12-21 18:06:12 +010048struct kmem_cache *fanotify_mark_cache __read_mostly;
Jan Kara7053aee2014-01-21 15:48:14 -080049struct kmem_cache *fanotify_event_cachep __read_mostly;
Jan Karaf0834412014-04-03 14:46:33 -070050struct kmem_cache *fanotify_perm_event_cachep __read_mostly;
Eric Paris2a3edf82009-12-17 21:24:26 -050051
Amir Goldstein5e469c82019-01-10 19:04:35 +020052#define FANOTIFY_EVENT_ALIGN 4
53
54static int fanotify_event_info_len(struct fanotify_event *event)
55{
56 if (!fanotify_event_has_fid(event))
57 return 0;
58
59 return roundup(sizeof(struct fanotify_event_info_fid) +
60 sizeof(struct file_handle) + event->fh_len,
61 FANOTIFY_EVENT_ALIGN);
62}
63
Eric Parisa1014f12009-12-17 21:24:26 -050064/*
65 * Get an fsnotify notification event if one exists and is small
66 * enough to fit in "count". Return an error pointer if the count
Jan Kara40873282019-01-08 14:02:44 +010067 * is not large enough. When permission event is dequeued, its state is
68 * updated accordingly.
Eric Parisa1014f12009-12-17 21:24:26 -050069 */
70static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
71 size_t count)
72{
Amir Goldstein5e469c82019-01-10 19:04:35 +020073 size_t event_size = FAN_EVENT_METADATA_LEN;
Jan Kara8c554462019-01-08 13:52:31 +010074 struct fsnotify_event *fsn_event = NULL;
Eric Parisa1014f12009-12-17 21:24:26 -050075
76 pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
77
Jan Kara8c554462019-01-08 13:52:31 +010078 spin_lock(&group->notification_lock);
Eric Parisa1014f12009-12-17 21:24:26 -050079 if (fsnotify_notify_queue_is_empty(group))
Jan Kara8c554462019-01-08 13:52:31 +010080 goto out;
Eric Parisa1014f12009-12-17 21:24:26 -050081
Amir Goldstein5e469c82019-01-10 19:04:35 +020082 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
Jan Kara8c554462019-01-08 13:52:31 +010083 event_size += fanotify_event_info_len(
84 FANOTIFY_E(fsnotify_peek_first_event(group)));
Amir Goldstein5e469c82019-01-10 19:04:35 +020085 }
86
Jan Kara8c554462019-01-08 13:52:31 +010087 if (event_size > count) {
88 fsn_event = ERR_PTR(-EINVAL);
89 goto out;
90 }
91 fsn_event = fsnotify_remove_first_event(group);
Jan Kara40873282019-01-08 14:02:44 +010092 if (fanotify_is_perm_event(FANOTIFY_E(fsn_event)->mask))
93 FANOTIFY_PE(fsn_event)->state = FAN_EVENT_REPORTED;
Jan Kara8c554462019-01-08 13:52:31 +010094out:
95 spin_unlock(&group->notification_lock);
96 return fsn_event;
Eric Parisa1014f12009-12-17 21:24:26 -050097}
98
Al Viro352e3b22012-08-19 12:30:45 -040099static int create_fd(struct fsnotify_group *group,
Amir Goldstein33913992019-01-10 19:04:32 +0200100 struct fanotify_event *event,
Jan Kara7053aee2014-01-21 15:48:14 -0800101 struct file **file)
Eric Parisa1014f12009-12-17 21:24:26 -0500102{
103 int client_fd;
Eric Parisa1014f12009-12-17 21:24:26 -0500104 struct file *new_file;
105
Andreas Gruenbacher22aa4252009-12-17 21:24:26 -0500106 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
Eric Parisa1014f12009-12-17 21:24:26 -0500107
Yann Droneaud0b37e092014-10-09 15:24:40 -0700108 client_fd = get_unused_fd_flags(group->fanotify_data.f_flags);
Eric Parisa1014f12009-12-17 21:24:26 -0500109 if (client_fd < 0)
110 return client_fd;
111
Eric Parisa1014f12009-12-17 21:24:26 -0500112 /*
113 * we need a new file handle for the userspace program so it can read even if it was
114 * originally opened O_WRONLY.
115 */
Eric Parisa1014f12009-12-17 21:24:26 -0500116 /* it's possible this event was an overflow event. in that case dentry and mnt
117 * are NULL; That's fine, just don't call dentry open */
Al Viro765927b2012-06-26 21:58:53 +0400118 if (event->path.dentry && event->path.mnt)
119 new_file = dentry_open(&event->path,
Eric Paris80af2582010-07-28 10:18:37 -0400120 group->fanotify_data.f_flags | FMODE_NONOTIFY,
Eric Parisa1014f12009-12-17 21:24:26 -0500121 current_cred());
122 else
123 new_file = ERR_PTR(-EOVERFLOW);
124 if (IS_ERR(new_file)) {
125 /*
126 * we still send an event even if we can't open the file. this
127 * can happen when say tasks are gone and we try to open their
128 * /proc files or we try to open a WRONLY file like in sysfs
129 * we just send the errno to userspace since there isn't much
130 * else we can do.
131 */
132 put_unused_fd(client_fd);
133 client_fd = PTR_ERR(new_file);
134 } else {
Al Viro352e3b22012-08-19 12:30:45 -0400135 *file = new_file;
Eric Parisa1014f12009-12-17 21:24:26 -0500136 }
137
Andreas Gruenbacher22aa4252009-12-17 21:24:26 -0500138 return client_fd;
Eric Parisa1014f12009-12-17 21:24:26 -0500139}
140
Jan Kara40873282019-01-08 14:02:44 +0100141/*
142 * Finish processing of permission event by setting it to ANSWERED state and
143 * drop group->notification_lock.
144 */
145static void finish_permission_event(struct fsnotify_group *group,
146 struct fanotify_perm_event *event,
147 unsigned int response)
148 __releases(&group->notification_lock)
149{
Jan Karafabf7f22019-01-08 15:18:02 +0100150 bool destroy = false;
151
Jan Kara40873282019-01-08 14:02:44 +0100152 assert_spin_locked(&group->notification_lock);
153 event->response = response;
Jan Karafabf7f22019-01-08 15:18:02 +0100154 if (event->state == FAN_EVENT_CANCELED)
155 destroy = true;
156 else
157 event->state = FAN_EVENT_ANSWERED;
Jan Kara40873282019-01-08 14:02:44 +0100158 spin_unlock(&group->notification_lock);
Jan Karafabf7f22019-01-08 15:18:02 +0100159 if (destroy)
160 fsnotify_destroy_event(group, &event->fae.fse);
Jan Kara40873282019-01-08 14:02:44 +0100161}
162
Eric Parisb2d87902009-12-17 21:24:34 -0500163static int process_access_response(struct fsnotify_group *group,
164 struct fanotify_response *response_struct)
165{
Amir Goldstein33913992019-01-10 19:04:32 +0200166 struct fanotify_perm_event *event;
Jan Karaf0834412014-04-03 14:46:33 -0700167 int fd = response_struct->fd;
168 int response = response_struct->response;
Eric Parisb2d87902009-12-17 21:24:34 -0500169
170 pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
171 fd, response);
172 /*
173 * make sure the response is valid, if invalid we do nothing and either
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300174 * userspace can send a valid response or we will clean it up after the
Eric Parisb2d87902009-12-17 21:24:34 -0500175 * timeout
176 */
Steve Grubbde8cd832017-10-02 20:21:39 -0400177 switch (response & ~FAN_AUDIT) {
Eric Parisb2d87902009-12-17 21:24:34 -0500178 case FAN_ALLOW:
179 case FAN_DENY:
180 break;
181 default:
182 return -EINVAL;
183 }
184
185 if (fd < 0)
186 return -EINVAL;
187
Amir Goldstein96a71f22018-09-21 21:20:30 +0300188 if ((response & FAN_AUDIT) && !FAN_GROUP_FLAG(group, FAN_ENABLE_AUDIT))
Steve Grubbde8cd832017-10-02 20:21:39 -0400189 return -EINVAL;
190
Jan Karaaf6a5112019-01-08 13:28:18 +0100191 spin_lock(&group->notification_lock);
192 list_for_each_entry(event, &group->fanotify_data.access_list,
193 fae.fse.list) {
194 if (event->fd != fd)
195 continue;
Eric Parisb2d87902009-12-17 21:24:34 -0500196
Jan Karaaf6a5112019-01-08 13:28:18 +0100197 list_del_init(&event->fae.fse.list);
Jan Kara40873282019-01-08 14:02:44 +0100198 finish_permission_event(group, event, response);
Jan Karaaf6a5112019-01-08 13:28:18 +0100199 wake_up(&group->fanotify_data.access_waitq);
200 return 0;
201 }
202 spin_unlock(&group->notification_lock);
Eric Parisb2d87902009-12-17 21:24:34 -0500203
Jan Karaaf6a5112019-01-08 13:28:18 +0100204 return -ENOENT;
Eric Parisb2d87902009-12-17 21:24:34 -0500205}
Eric Parisb2d87902009-12-17 21:24:34 -0500206
Amir Goldstein5e469c82019-01-10 19:04:35 +0200207static int copy_fid_to_user(struct fanotify_event *event, char __user *buf)
208{
209 struct fanotify_event_info_fid info = { };
210 struct file_handle handle = { };
Jan Karab2d22b62019-03-12 12:42:37 +0100211 unsigned char bounce[FANOTIFY_INLINE_FH_LEN], *fh;
Amir Goldstein5e469c82019-01-10 19:04:35 +0200212 size_t fh_len = event->fh_len;
213 size_t len = fanotify_event_info_len(event);
214
215 if (!len)
216 return 0;
217
218 if (WARN_ON_ONCE(len < sizeof(info) + sizeof(handle) + fh_len))
219 return -EFAULT;
220
221 /* Copy event info fid header followed by vaiable sized file handle */
222 info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
223 info.hdr.len = len;
224 info.fsid = event->fid.fsid;
225 if (copy_to_user(buf, &info, sizeof(info)))
226 return -EFAULT;
227
228 buf += sizeof(info);
229 len -= sizeof(info);
230 handle.handle_type = event->fh_type;
231 handle.handle_bytes = fh_len;
232 if (copy_to_user(buf, &handle, sizeof(handle)))
233 return -EFAULT;
234
235 buf += sizeof(handle);
236 len -= sizeof(handle);
Jan Karab2d22b62019-03-12 12:42:37 +0100237 /*
238 * For an inline fh, copy through stack to exclude the copy from
239 * usercopy hardening protections.
240 */
241 fh = fanotify_event_fh(event);
242 if (fh_len <= FANOTIFY_INLINE_FH_LEN) {
243 memcpy(bounce, fh, fh_len);
244 fh = bounce;
245 }
246 if (copy_to_user(buf, fh, fh_len))
Amir Goldstein5e469c82019-01-10 19:04:35 +0200247 return -EFAULT;
248
249 /* Pad with 0's */
250 buf += fh_len;
251 len -= fh_len;
252 WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
253 if (len > 0 && clear_user(buf, len))
254 return -EFAULT;
255
256 return 0;
257}
258
Eric Parisa1014f12009-12-17 21:24:26 -0500259static ssize_t copy_event_to_user(struct fsnotify_group *group,
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200260 struct fsnotify_event *fsn_event,
Kees Cook5b03a472018-12-04 15:44:46 -0800261 char __user *buf, size_t count)
Eric Parisa1014f12009-12-17 21:24:26 -0500262{
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200263 struct fanotify_event_metadata metadata;
264 struct fanotify_event *event;
265 struct file *f = NULL;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200266 int ret, fd = FAN_NOFD;
Eric Parisa1014f12009-12-17 21:24:26 -0500267
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200268 pr_debug("%s: group=%p event=%p\n", __func__, group, fsn_event);
Eric Parisa1014f12009-12-17 21:24:26 -0500269
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200270 event = container_of(fsn_event, struct fanotify_event, fse);
271 metadata.event_len = FAN_EVENT_METADATA_LEN;
272 metadata.metadata_len = FAN_EVENT_METADATA_LEN;
273 metadata.vers = FANOTIFY_METADATA_VERSION;
274 metadata.reserved = 0;
275 metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS;
276 metadata.pid = pid_vnr(event->pid);
Eric Parisa1014f12009-12-17 21:24:26 -0500277
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200278 if (fanotify_event_has_path(event)) {
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200279 fd = create_fd(group, event, &f);
280 if (fd < 0)
281 return fd;
Amir Goldstein5e469c82019-01-10 19:04:35 +0200282 } else if (fanotify_event_has_fid(event)) {
283 metadata.event_len += fanotify_event_info_len(event);
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200284 }
285 metadata.fd = fd;
286
Al Viro352e3b22012-08-19 12:30:45 -0400287 ret = -EFAULT;
Kees Cook5b03a472018-12-04 15:44:46 -0800288 /*
289 * Sanity check copy size in case get_one_event() and
290 * fill_event_metadata() event_len sizes ever get out of sync.
291 */
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200292 if (WARN_ON_ONCE(metadata.event_len > count))
Al Viro352e3b22012-08-19 12:30:45 -0400293 goto out_close_fd;
294
Amir Goldstein5e469c82019-01-10 19:04:35 +0200295 if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN))
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200296 goto out_close_fd;
297
298 if (fanotify_is_perm_event(event->mask))
299 FANOTIFY_PE(fsn_event)->fd = fd;
Eric Parisb2d87902009-12-17 21:24:34 -0500300
Amir Goldstein5e469c82019-01-10 19:04:35 +0200301 if (fanotify_event_has_path(event)) {
Al Viro3587b1b2012-11-18 19:19:00 +0000302 fd_install(fd, f);
Amir Goldstein5e469c82019-01-10 19:04:35 +0200303 } else if (fanotify_event_has_fid(event)) {
304 ret = copy_fid_to_user(event, buf + FAN_EVENT_METADATA_LEN);
305 if (ret < 0)
306 return ret;
307 }
308
Amir Goldsteinbb2f7b42019-01-10 19:04:33 +0200309 return metadata.event_len;
Eric Parisb2d87902009-12-17 21:24:34 -0500310
Eric Parisb2d87902009-12-17 21:24:34 -0500311out_close_fd:
Al Viro352e3b22012-08-19 12:30:45 -0400312 if (fd != FAN_NOFD) {
313 put_unused_fd(fd);
314 fput(f);
315 }
Eric Parisb2d87902009-12-17 21:24:34 -0500316 return ret;
Eric Parisa1014f12009-12-17 21:24:26 -0500317}
318
319/* intofiy userspace file descriptor functions */
Al Viro076ccb72017-07-03 01:02:18 -0400320static __poll_t fanotify_poll(struct file *file, poll_table *wait)
Eric Parisa1014f12009-12-17 21:24:26 -0500321{
322 struct fsnotify_group *group = file->private_data;
Al Viro076ccb72017-07-03 01:02:18 -0400323 __poll_t ret = 0;
Eric Parisa1014f12009-12-17 21:24:26 -0500324
325 poll_wait(file, &group->notification_waitq, wait);
Jan Karac21dbe22016-10-07 16:56:52 -0700326 spin_lock(&group->notification_lock);
Eric Parisa1014f12009-12-17 21:24:26 -0500327 if (!fsnotify_notify_queue_is_empty(group))
Linus Torvaldsa9a08842018-02-11 14:34:03 -0800328 ret = EPOLLIN | EPOLLRDNORM;
Jan Karac21dbe22016-10-07 16:56:52 -0700329 spin_unlock(&group->notification_lock);
Eric Parisa1014f12009-12-17 21:24:26 -0500330
331 return ret;
332}
333
334static ssize_t fanotify_read(struct file *file, char __user *buf,
335 size_t count, loff_t *pos)
336{
337 struct fsnotify_group *group;
338 struct fsnotify_event *kevent;
339 char __user *start;
340 int ret;
Peter Zijlstra536ebe9ca2014-12-16 16:28:38 +0100341 DEFINE_WAIT_FUNC(wait, woken_wake_function);
Eric Parisa1014f12009-12-17 21:24:26 -0500342
343 start = buf;
344 group = file->private_data;
345
346 pr_debug("%s: group=%p\n", __func__, group);
347
Peter Zijlstra536ebe9ca2014-12-16 16:28:38 +0100348 add_wait_queue(&group->notification_waitq, &wait);
Eric Parisa1014f12009-12-17 21:24:26 -0500349 while (1) {
Eric Parisa1014f12009-12-17 21:24:26 -0500350 kevent = get_one_event(group, count);
Jan Karad8aaab42014-04-03 14:46:35 -0700351 if (IS_ERR(kevent)) {
Eric Parisa1014f12009-12-17 21:24:26 -0500352 ret = PTR_ERR(kevent);
Jan Karad8aaab42014-04-03 14:46:35 -0700353 break;
354 }
355
356 if (!kevent) {
357 ret = -EAGAIN;
358 if (file->f_flags & O_NONBLOCK)
Eric Parisa1014f12009-12-17 21:24:26 -0500359 break;
Jan Karad8aaab42014-04-03 14:46:35 -0700360
361 ret = -ERESTARTSYS;
362 if (signal_pending(current))
Eric Parisa1014f12009-12-17 21:24:26 -0500363 break;
Jan Karad8aaab42014-04-03 14:46:35 -0700364
365 if (start != buf)
366 break;
Peter Zijlstra536ebe9ca2014-12-16 16:28:38 +0100367
368 wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
Eric Parisa1014f12009-12-17 21:24:26 -0500369 continue;
370 }
371
Kees Cook5b03a472018-12-04 15:44:46 -0800372 ret = copy_event_to_user(group, kevent, buf, count);
Amir Goldstein4ff33aa2017-04-25 14:29:35 +0300373 if (unlikely(ret == -EOPENSTALE)) {
374 /*
375 * We cannot report events with stale fd so drop it.
376 * Setting ret to 0 will continue the event loop and
377 * do the right thing if there are no more events to
378 * read (i.e. return bytes read, -EAGAIN or wait).
379 */
380 ret = 0;
381 }
382
Jan Karad8aaab42014-04-03 14:46:35 -0700383 /*
384 * Permission events get queued to wait for response. Other
385 * events can be destroyed now.
386 */
Amir Goldsteina0a92d22019-01-10 19:04:31 +0200387 if (!fanotify_is_perm_event(FANOTIFY_E(kevent)->mask)) {
Jan Karad8aaab42014-04-03 14:46:35 -0700388 fsnotify_destroy_event(group, kevent);
Jan Karad5078162014-04-03 14:46:36 -0700389 } else {
Amir Goldstein4ff33aa2017-04-25 14:29:35 +0300390 if (ret <= 0) {
Jan Kara40873282019-01-08 14:02:44 +0100391 spin_lock(&group->notification_lock);
392 finish_permission_event(group,
393 FANOTIFY_PE(kevent), FAN_DENY);
Jan Karad5078162014-04-03 14:46:36 -0700394 wake_up(&group->fanotify_data.access_waitq);
Amir Goldstein4ff33aa2017-04-25 14:29:35 +0300395 } else {
396 spin_lock(&group->notification_lock);
397 list_add_tail(&kevent->list,
398 &group->fanotify_data.access_list);
399 spin_unlock(&group->notification_lock);
Jan Karad5078162014-04-03 14:46:36 -0700400 }
Jan Karad5078162014-04-03 14:46:36 -0700401 }
Amir Goldstein4ff33aa2017-04-25 14:29:35 +0300402 if (ret < 0)
403 break;
Jan Karad8aaab42014-04-03 14:46:35 -0700404 buf += ret;
405 count -= ret;
Eric Parisa1014f12009-12-17 21:24:26 -0500406 }
Peter Zijlstra536ebe9ca2014-12-16 16:28:38 +0100407 remove_wait_queue(&group->notification_waitq, &wait);
Eric Parisa1014f12009-12-17 21:24:26 -0500408
Eric Parisa1014f12009-12-17 21:24:26 -0500409 if (start != buf && ret != -EFAULT)
410 ret = buf - start;
411 return ret;
412}
413
Eric Parisb2d87902009-12-17 21:24:34 -0500414static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
415{
Eric Parisb2d87902009-12-17 21:24:34 -0500416 struct fanotify_response response = { .fd = -1, .response = -1 };
417 struct fsnotify_group *group;
418 int ret;
419
Miklos Szeredi6685df32017-10-30 21:14:56 +0100420 if (!IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
421 return -EINVAL;
422
Eric Parisb2d87902009-12-17 21:24:34 -0500423 group = file->private_data;
424
425 if (count > sizeof(response))
426 count = sizeof(response);
427
428 pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
429
430 if (copy_from_user(&response, buf, count))
431 return -EFAULT;
432
433 ret = process_access_response(group, &response);
434 if (ret < 0)
435 count = ret;
436
437 return count;
Eric Parisb2d87902009-12-17 21:24:34 -0500438}
439
Eric Paris52c923d2009-12-17 21:24:26 -0500440static int fanotify_release(struct inode *ignored, struct file *file)
441{
442 struct fsnotify_group *group = file->private_data;
Jan Karaca6f8692019-01-09 13:21:01 +0100443 struct fanotify_perm_event *event;
Jan Kara96d41012016-09-19 14:44:30 -0700444 struct fsnotify_event *fsn_event;
Andrew Morton19ba54f2010-10-28 17:21:59 -0400445
Jan Kara5838d442014-08-06 16:03:28 -0700446 /*
Jan Kara96d41012016-09-19 14:44:30 -0700447 * Stop new events from arriving in the notification queue. since
448 * userspace cannot use fanotify fd anymore, no event can enter or
449 * leave access_list by now either.
450 */
451 fsnotify_group_stop_queueing(group);
452
453 /*
454 * Process all permission events on access_list and notification queue
455 * and simulate reply from userspace.
Jan Kara5838d442014-08-06 16:03:28 -0700456 */
Jan Kara073f6552016-10-07 16:56:55 -0700457 spin_lock(&group->notification_lock);
Jan Karaca6f8692019-01-09 13:21:01 +0100458 while (!list_empty(&group->fanotify_data.access_list)) {
459 event = list_first_entry(&group->fanotify_data.access_list,
460 struct fanotify_perm_event, fae.fse.list);
Jan Karaf0834412014-04-03 14:46:33 -0700461 list_del_init(&event->fae.fse.list);
Jan Kara40873282019-01-08 14:02:44 +0100462 finish_permission_event(group, event, FAN_ALLOW);
463 spin_lock(&group->notification_lock);
Eric Paris2eebf582010-08-18 12:25:50 -0400464 }
Eric Paris2eebf582010-08-18 12:25:50 -0400465
Jan Kara5838d442014-08-06 16:03:28 -0700466 /*
Jan Kara96d41012016-09-19 14:44:30 -0700467 * Destroy all non-permission events. For permission events just
468 * dequeue them and set the response. They will be freed once the
469 * response is consumed and fanotify_get_response() returns.
Jan Kara5838d442014-08-06 16:03:28 -0700470 */
Jan Kara96d41012016-09-19 14:44:30 -0700471 while (!fsnotify_notify_queue_is_empty(group)) {
472 fsn_event = fsnotify_remove_first_event(group);
Amir Goldsteina0a92d22019-01-10 19:04:31 +0200473 if (!(FANOTIFY_E(fsn_event)->mask & FANOTIFY_PERM_EVENTS)) {
Jan Karac21dbe22016-10-07 16:56:52 -0700474 spin_unlock(&group->notification_lock);
Jan Kara96d41012016-09-19 14:44:30 -0700475 fsnotify_destroy_event(group, fsn_event);
Miklos Szeredi6685df32017-10-30 21:14:56 +0100476 } else {
Jan Kara40873282019-01-08 14:02:44 +0100477 finish_permission_event(group, FANOTIFY_PE(fsn_event),
478 FAN_ALLOW);
Miklos Szeredi6685df32017-10-30 21:14:56 +0100479 }
Jan Kara40873282019-01-08 14:02:44 +0100480 spin_lock(&group->notification_lock);
Jan Kara96d41012016-09-19 14:44:30 -0700481 }
Jan Karac21dbe22016-10-07 16:56:52 -0700482 spin_unlock(&group->notification_lock);
Jan Kara96d41012016-09-19 14:44:30 -0700483
484 /* Response for all permission events it set, wakeup waiters */
Eric Paris2eebf582010-08-18 12:25:50 -0400485 wake_up(&group->fanotify_data.access_waitq);
Eric Paris0a6b6bd2011-10-14 17:43:39 -0400486
Eric Paris52c923d2009-12-17 21:24:26 -0500487 /* matches the fanotify_init->fsnotify_alloc_group */
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200488 fsnotify_destroy_group(group);
Eric Paris52c923d2009-12-17 21:24:26 -0500489
490 return 0;
491}
492
Eric Parisa1014f12009-12-17 21:24:26 -0500493static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
494{
495 struct fsnotify_group *group;
Jan Kara7053aee2014-01-21 15:48:14 -0800496 struct fsnotify_event *fsn_event;
Eric Parisa1014f12009-12-17 21:24:26 -0500497 void __user *p;
498 int ret = -ENOTTY;
499 size_t send_len = 0;
500
501 group = file->private_data;
502
503 p = (void __user *) arg;
504
505 switch (cmd) {
506 case FIONREAD:
Jan Karac21dbe22016-10-07 16:56:52 -0700507 spin_lock(&group->notification_lock);
Jan Kara7053aee2014-01-21 15:48:14 -0800508 list_for_each_entry(fsn_event, &group->notification_list, list)
Eric Parisa1014f12009-12-17 21:24:26 -0500509 send_len += FAN_EVENT_METADATA_LEN;
Jan Karac21dbe22016-10-07 16:56:52 -0700510 spin_unlock(&group->notification_lock);
Eric Parisa1014f12009-12-17 21:24:26 -0500511 ret = put_user(send_len, (int __user *) p);
512 break;
513 }
514
515 return ret;
516}
517
Eric Paris52c923d2009-12-17 21:24:26 -0500518static const struct file_operations fanotify_fops = {
Cyrill Gorcunovbe771962012-12-17 16:05:12 -0800519 .show_fdinfo = fanotify_show_fdinfo,
Eric Parisa1014f12009-12-17 21:24:26 -0500520 .poll = fanotify_poll,
521 .read = fanotify_read,
Eric Parisb2d87902009-12-17 21:24:34 -0500522 .write = fanotify_write,
Eric Paris52c923d2009-12-17 21:24:26 -0500523 .fasync = NULL,
524 .release = fanotify_release,
Eric Parisa1014f12009-12-17 21:24:26 -0500525 .unlocked_ioctl = fanotify_ioctl,
526 .compat_ioctl = fanotify_ioctl,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200527 .llseek = noop_llseek,
Eric Paris52c923d2009-12-17 21:24:26 -0500528};
529
Eric Paris2a3edf82009-12-17 21:24:26 -0500530static int fanotify_find_path(int dfd, const char __user *filename,
531 struct path *path, unsigned int flags)
532{
533 int ret;
534
535 pr_debug("%s: dfd=%d filename=%p flags=%x\n", __func__,
536 dfd, filename, flags);
537
538 if (filename == NULL) {
Al Viro2903ff02012-08-28 12:52:22 -0400539 struct fd f = fdget(dfd);
Eric Paris2a3edf82009-12-17 21:24:26 -0500540
541 ret = -EBADF;
Al Viro2903ff02012-08-28 12:52:22 -0400542 if (!f.file)
Eric Paris2a3edf82009-12-17 21:24:26 -0500543 goto out;
544
545 ret = -ENOTDIR;
546 if ((flags & FAN_MARK_ONLYDIR) &&
Al Viro496ad9a2013-01-23 17:07:38 -0500547 !(S_ISDIR(file_inode(f.file)->i_mode))) {
Al Viro2903ff02012-08-28 12:52:22 -0400548 fdput(f);
Eric Paris2a3edf82009-12-17 21:24:26 -0500549 goto out;
550 }
551
Al Viro2903ff02012-08-28 12:52:22 -0400552 *path = f.file->f_path;
Eric Paris2a3edf82009-12-17 21:24:26 -0500553 path_get(path);
Al Viro2903ff02012-08-28 12:52:22 -0400554 fdput(f);
Eric Paris2a3edf82009-12-17 21:24:26 -0500555 } else {
556 unsigned int lookup_flags = 0;
557
558 if (!(flags & FAN_MARK_DONT_FOLLOW))
559 lookup_flags |= LOOKUP_FOLLOW;
560 if (flags & FAN_MARK_ONLYDIR)
561 lookup_flags |= LOOKUP_DIRECTORY;
562
563 ret = user_path_at(dfd, filename, lookup_flags, path);
564 if (ret)
565 goto out;
566 }
567
568 /* you can only watch an inode if you have read permissions on it */
569 ret = inode_permission(path->dentry->d_inode, MAY_READ);
570 if (ret)
571 path_put(path);
572out:
573 return ret;
574}
575
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500576static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
577 __u32 mask,
Lino Sanfilippo6dfbd142011-06-14 17:29:49 +0200578 unsigned int flags,
579 int *destroy)
Andreas Gruenbacher088b09b2009-12-17 21:24:28 -0500580{
Lino Sanfilippod2c18742015-02-10 14:08:24 -0800581 __u32 oldmask = 0;
Andreas Gruenbacher088b09b2009-12-17 21:24:28 -0500582
583 spin_lock(&fsn_mark->lock);
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500584 if (!(flags & FAN_MARK_IGNORED_MASK)) {
585 oldmask = fsn_mark->mask;
Amir Goldsteina72fd222018-10-04 00:25:34 +0300586 fsn_mark->mask &= ~mask;
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500587 } else {
Amir Goldsteina72fd222018-10-04 00:25:34 +0300588 fsn_mark->ignored_mask &= ~mask;
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500589 }
Lino Sanfilippoa1184492015-02-10 14:08:21 -0800590 *destroy = !(fsn_mark->mask | fsn_mark->ignored_mask);
Andreas Gruenbacher088b09b2009-12-17 21:24:28 -0500591 spin_unlock(&fsn_mark->lock);
592
Andreas Gruenbacher088b09b2009-12-17 21:24:28 -0500593 return mask & oldmask;
594}
595
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300596static int fanotify_remove_mark(struct fsnotify_group *group,
597 fsnotify_connp_t *connp, __u32 mask,
598 unsigned int flags)
Eric Paris88826272009-12-17 21:24:28 -0500599{
600 struct fsnotify_mark *fsn_mark = NULL;
Andreas Gruenbacher088b09b2009-12-17 21:24:28 -0500601 __u32 removed;
Lino Sanfilippo6dfbd142011-06-14 17:29:49 +0200602 int destroy_mark;
Eric Paris88826272009-12-17 21:24:28 -0500603
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700604 mutex_lock(&group->mark_mutex);
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300605 fsn_mark = fsnotify_find_mark(connp, group);
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700606 if (!fsn_mark) {
607 mutex_unlock(&group->mark_mutex);
Eric Paris88826272009-12-17 21:24:28 -0500608 return -ENOENT;
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700609 }
Eric Paris88826272009-12-17 21:24:28 -0500610
Lino Sanfilippo6dfbd142011-06-14 17:29:49 +0200611 removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags,
612 &destroy_mark);
Amir Goldstein3ac70bf2018-06-23 17:54:50 +0300613 if (removed & fsnotify_conn_mask(fsn_mark->connector))
614 fsnotify_recalc_mask(fsn_mark->connector);
Lino Sanfilippo6dfbd142011-06-14 17:29:49 +0200615 if (destroy_mark)
Jan Kara4712e7222015-09-04 15:43:12 -0700616 fsnotify_detach_mark(fsn_mark);
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700617 mutex_unlock(&group->mark_mutex);
Jan Kara4712e7222015-09-04 15:43:12 -0700618 if (destroy_mark)
619 fsnotify_free_mark(fsn_mark);
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700620
Jan Karab1362ed2016-12-21 16:28:45 +0100621 /* matches the fsnotify_find_mark() */
Eric Paris2a3edf82009-12-17 21:24:26 -0500622 fsnotify_put_mark(fsn_mark);
Eric Paris2a3edf82009-12-17 21:24:26 -0500623 return 0;
624}
625
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300626static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
627 struct vfsmount *mnt, __u32 mask,
628 unsigned int flags)
629{
630 return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
631 mask, flags);
632}
633
Amir Goldsteind54f4fb2018-09-01 10:41:13 +0300634static int fanotify_remove_sb_mark(struct fsnotify_group *group,
635 struct super_block *sb, __u32 mask,
636 unsigned int flags)
637{
638 return fanotify_remove_mark(group, &sb->s_fsnotify_marks, mask, flags);
639}
640
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300641static int fanotify_remove_inode_mark(struct fsnotify_group *group,
642 struct inode *inode, __u32 mask,
643 unsigned int flags)
644{
645 return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask,
646 flags);
647}
648
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500649static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
650 __u32 mask,
651 unsigned int flags)
Andreas Gruenbacher912ee39462009-12-17 21:24:28 -0500652{
Eric Paris192ca4d2010-10-28 17:21:59 -0400653 __u32 oldmask = -1;
Andreas Gruenbacher912ee39462009-12-17 21:24:28 -0500654
655 spin_lock(&fsn_mark->lock);
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500656 if (!(flags & FAN_MARK_IGNORED_MASK)) {
657 oldmask = fsn_mark->mask;
Amir Goldsteina72fd222018-10-04 00:25:34 +0300658 fsn_mark->mask |= mask;
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500659 } else {
Amir Goldsteina72fd222018-10-04 00:25:34 +0300660 fsn_mark->ignored_mask |= mask;
Eric Parisc9778a92009-12-17 21:24:33 -0500661 if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
662 fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500663 }
Andreas Gruenbacher912ee39462009-12-17 21:24:28 -0500664 spin_unlock(&fsn_mark->lock);
665
666 return mask & ~oldmask;
667}
668
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700669static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
Amir Goldsteinb812a9f2018-06-23 17:54:48 +0300670 fsnotify_connp_t *connp,
Amir Goldstein77115222019-01-10 19:04:37 +0200671 unsigned int type,
672 __kernel_fsid_t *fsid)
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700673{
674 struct fsnotify_mark *mark;
675 int ret;
676
677 if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks)
678 return ERR_PTR(-ENOSPC);
679
680 mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
681 if (!mark)
682 return ERR_PTR(-ENOMEM);
683
Jan Kara054c6362016-12-21 18:06:12 +0100684 fsnotify_init_mark(mark, group);
Amir Goldstein77115222019-01-10 19:04:37 +0200685 ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid);
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700686 if (ret) {
687 fsnotify_put_mark(mark);
688 return ERR_PTR(ret);
689 }
690
691 return mark;
692}
693
694
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300695static int fanotify_add_mark(struct fsnotify_group *group,
696 fsnotify_connp_t *connp, unsigned int type,
Amir Goldstein77115222019-01-10 19:04:37 +0200697 __u32 mask, unsigned int flags,
698 __kernel_fsid_t *fsid)
Eric Paris2a3edf82009-12-17 21:24:26 -0500699{
700 struct fsnotify_mark *fsn_mark;
Andreas Gruenbacher912ee39462009-12-17 21:24:28 -0500701 __u32 added;
Eric Paris2a3edf82009-12-17 21:24:26 -0500702
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700703 mutex_lock(&group->mark_mutex);
Amir Goldsteinb812a9f2018-06-23 17:54:48 +0300704 fsn_mark = fsnotify_find_mark(connp, group);
Eric Paris88826272009-12-17 21:24:28 -0500705 if (!fsn_mark) {
Amir Goldstein77115222019-01-10 19:04:37 +0200706 fsn_mark = fanotify_add_new_mark(group, connp, type, fsid);
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700707 if (IS_ERR(fsn_mark)) {
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700708 mutex_unlock(&group->mark_mutex);
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700709 return PTR_ERR(fsn_mark);
Lino Sanfilippo7b185272013-07-08 15:59:42 -0700710 }
Eric Paris88826272009-12-17 21:24:28 -0500711 }
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500712 added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
Amir Goldstein3ac70bf2018-06-23 17:54:50 +0300713 if (added & ~fsnotify_conn_mask(fsn_mark->connector))
714 fsnotify_recalc_mask(fsn_mark->connector);
Jan Karac9747642016-12-14 13:53:46 +0100715 mutex_unlock(&group->mark_mutex);
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700716
Lino Sanfilippofa218ab2010-11-09 18:18:16 +0100717 fsnotify_put_mark(fsn_mark);
Lino Sanfilippo5e9c070c2013-07-08 15:59:43 -0700718 return 0;
Eric Paris88826272009-12-17 21:24:28 -0500719}
720
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300721static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
722 struct vfsmount *mnt, __u32 mask,
Amir Goldstein77115222019-01-10 19:04:37 +0200723 unsigned int flags, __kernel_fsid_t *fsid)
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300724{
725 return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
Amir Goldstein77115222019-01-10 19:04:37 +0200726 FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid);
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300727}
728
Amir Goldsteind54f4fb2018-09-01 10:41:13 +0300729static int fanotify_add_sb_mark(struct fsnotify_group *group,
Amir Goldstein77115222019-01-10 19:04:37 +0200730 struct super_block *sb, __u32 mask,
731 unsigned int flags, __kernel_fsid_t *fsid)
Amir Goldsteind54f4fb2018-09-01 10:41:13 +0300732{
733 return fanotify_add_mark(group, &sb->s_fsnotify_marks,
Amir Goldstein77115222019-01-10 19:04:37 +0200734 FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid);
Amir Goldsteind54f4fb2018-09-01 10:41:13 +0300735}
736
Andreas Gruenbacher52202df2009-12-17 21:24:28 -0500737static int fanotify_add_inode_mark(struct fsnotify_group *group,
Eric Parisb9e4e3b2009-12-17 21:24:33 -0500738 struct inode *inode, __u32 mask,
Amir Goldstein77115222019-01-10 19:04:37 +0200739 unsigned int flags, __kernel_fsid_t *fsid)
Eric Paris88826272009-12-17 21:24:28 -0500740{
Eric Paris88826272009-12-17 21:24:28 -0500741 pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
Eric Paris2a3edf82009-12-17 21:24:26 -0500742
Eric Paris5322a592010-10-28 17:21:57 -0400743 /*
744 * If some other task has this inode open for write we should not add
745 * an ignored mark, unless that ignored mark is supposed to survive
746 * modification changes anyway.
747 */
748 if ((flags & FAN_MARK_IGNORED_MASK) &&
749 !(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
Nikolay Borisovac9498d2018-12-11 10:27:23 +0200750 inode_is_open_for_write(inode))
Eric Paris5322a592010-10-28 17:21:57 -0400751 return 0;
752
Amir Goldsteineaa2c6b2018-06-23 17:54:51 +0300753 return fanotify_add_mark(group, &inode->i_fsnotify_marks,
Amir Goldstein77115222019-01-10 19:04:37 +0200754 FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid);
Eric Paris88826272009-12-17 21:24:28 -0500755}
Eric Paris2a3edf82009-12-17 21:24:26 -0500756
Eric Paris52c923d2009-12-17 21:24:26 -0500757/* fanotify syscalls */
Eric Paris08ae8932010-05-27 09:41:40 -0400758SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
Eric Paris11637e42009-12-17 21:24:25 -0500759{
Eric Paris52c923d2009-12-17 21:24:26 -0500760 struct fsnotify_group *group;
761 int f_flags, fd;
Eric Paris4afeff82010-10-28 17:21:58 -0400762 struct user_struct *user;
Amir Goldstein33913992019-01-10 19:04:32 +0200763 struct fanotify_event *oevent;
Eric Paris52c923d2009-12-17 21:24:26 -0500764
Amir Goldstein96a71f22018-09-21 21:20:30 +0300765 pr_debug("%s: flags=%x event_f_flags=%x\n",
766 __func__, flags, event_f_flags);
Eric Paris52c923d2009-12-17 21:24:26 -0500767
Eric Paris52c923d2009-12-17 21:24:26 -0500768 if (!capable(CAP_SYS_ADMIN))
Andreas Gruenbachera2f13ad2010-08-24 12:58:54 +0200769 return -EPERM;
Eric Paris52c923d2009-12-17 21:24:26 -0500770
Steve Grubbde8cd832017-10-02 20:21:39 -0400771#ifdef CONFIG_AUDITSYSCALL
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300772 if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT))
Steve Grubbde8cd832017-10-02 20:21:39 -0400773#else
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300774 if (flags & ~FANOTIFY_INIT_FLAGS)
Steve Grubbde8cd832017-10-02 20:21:39 -0400775#endif
Eric Paris52c923d2009-12-17 21:24:26 -0500776 return -EINVAL;
777
Heinrich Schuchardt48149e92014-06-04 16:05:44 -0700778 if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS)
779 return -EINVAL;
780
781 switch (event_f_flags & O_ACCMODE) {
782 case O_RDONLY:
783 case O_RDWR:
784 case O_WRONLY:
785 break;
786 default:
787 return -EINVAL;
788 }
789
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200790 if ((flags & FAN_REPORT_FID) &&
791 (flags & FANOTIFY_CLASS_BITS) != FAN_CLASS_NOTIF)
792 return -EINVAL;
793
Eric Paris4afeff82010-10-28 17:21:58 -0400794 user = get_current_user();
795 if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) {
796 free_uid(user);
797 return -EMFILE;
798 }
799
Eric Parisb2d87902009-12-17 21:24:34 -0500800 f_flags = O_RDWR | FMODE_NONOTIFY;
Eric Paris52c923d2009-12-17 21:24:26 -0500801 if (flags & FAN_CLOEXEC)
802 f_flags |= O_CLOEXEC;
803 if (flags & FAN_NONBLOCK)
804 f_flags |= O_NONBLOCK;
805
806 /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
807 group = fsnotify_alloc_group(&fanotify_fsnotify_ops);
Eric Paris26379192010-11-23 23:48:26 -0500808 if (IS_ERR(group)) {
809 free_uid(user);
Eric Paris52c923d2009-12-17 21:24:26 -0500810 return PTR_ERR(group);
Eric Paris26379192010-11-23 23:48:26 -0500811 }
Eric Paris52c923d2009-12-17 21:24:26 -0500812
Eric Paris4afeff82010-10-28 17:21:58 -0400813 group->fanotify_data.user = user;
Amir Goldstein96a71f22018-09-21 21:20:30 +0300814 group->fanotify_data.flags = flags;
Eric Paris4afeff82010-10-28 17:21:58 -0400815 atomic_inc(&user->fanotify_listeners);
Shakeel Buttd46eb14b2018-08-17 15:46:39 -0700816 group->memcg = get_mem_cgroup_from_mm(current->mm);
Eric Paris4afeff82010-10-28 17:21:58 -0400817
Amir Goldstein83b535d2019-01-10 19:04:42 +0200818 oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL,
819 FSNOTIFY_EVENT_NONE, NULL);
Jan Karaff57cd52014-02-21 19:14:11 +0100820 if (unlikely(!oevent)) {
821 fd = -ENOMEM;
822 goto out_destroy_group;
823 }
824 group->overflow_event = &oevent->fse;
Jan Karaff57cd52014-02-21 19:14:11 +0100825
Will Woods1e2ee492014-05-06 12:50:10 -0700826 if (force_o_largefile())
827 event_f_flags |= O_LARGEFILE;
Eric Paris80af2582010-07-28 10:18:37 -0400828 group->fanotify_data.f_flags = event_f_flags;
Eric Paris9e66e422009-12-17 21:24:34 -0500829 init_waitqueue_head(&group->fanotify_data.access_waitq);
830 INIT_LIST_HEAD(&group->fanotify_data.access_list);
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300831 switch (flags & FANOTIFY_CLASS_BITS) {
Eric Paris4231a232010-10-28 17:21:56 -0400832 case FAN_CLASS_NOTIF:
833 group->priority = FS_PRIO_0;
834 break;
835 case FAN_CLASS_CONTENT:
836 group->priority = FS_PRIO_1;
837 break;
838 case FAN_CLASS_PRE_CONTENT:
839 group->priority = FS_PRIO_2;
840 break;
841 default:
842 fd = -EINVAL;
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200843 goto out_destroy_group;
Eric Paris4231a232010-10-28 17:21:56 -0400844 }
Eric Pariscb2d4292009-12-17 21:24:34 -0500845
Eric Paris5dd03f52010-10-28 17:21:57 -0400846 if (flags & FAN_UNLIMITED_QUEUE) {
847 fd = -EPERM;
848 if (!capable(CAP_SYS_ADMIN))
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200849 goto out_destroy_group;
Eric Paris5dd03f52010-10-28 17:21:57 -0400850 group->max_events = UINT_MAX;
851 } else {
852 group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS;
853 }
Eric Paris2529a0d2010-10-28 17:21:57 -0400854
Eric Parisac7e22d2010-10-28 17:21:58 -0400855 if (flags & FAN_UNLIMITED_MARKS) {
856 fd = -EPERM;
857 if (!capable(CAP_SYS_ADMIN))
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200858 goto out_destroy_group;
Eric Parisac7e22d2010-10-28 17:21:58 -0400859 group->fanotify_data.max_marks = UINT_MAX;
860 } else {
861 group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS;
862 }
Eric Parise7099d82010-10-28 17:21:57 -0400863
Steve Grubbde8cd832017-10-02 20:21:39 -0400864 if (flags & FAN_ENABLE_AUDIT) {
865 fd = -EPERM;
866 if (!capable(CAP_AUDIT_WRITE))
867 goto out_destroy_group;
Steve Grubbde8cd832017-10-02 20:21:39 -0400868 }
869
Eric Paris52c923d2009-12-17 21:24:26 -0500870 fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
871 if (fd < 0)
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200872 goto out_destroy_group;
Eric Paris52c923d2009-12-17 21:24:26 -0500873
874 return fd;
875
Lino Sanfilippod8153d42011-06-14 17:29:45 +0200876out_destroy_group:
877 fsnotify_destroy_group(group);
Eric Paris52c923d2009-12-17 21:24:26 -0500878 return fd;
Eric Paris11637e42009-12-17 21:24:25 -0500879}
Eric Parisbbaa4162009-12-17 21:24:26 -0500880
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200881/* Check if filesystem can encode a unique fid */
Amir Goldstein73072282019-01-10 19:04:39 +0200882static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid)
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200883{
Amir Goldstein73072282019-01-10 19:04:39 +0200884 __kernel_fsid_t root_fsid;
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200885 int err;
886
887 /*
888 * Make sure path is not in filesystem with zero fsid (e.g. tmpfs).
889 */
Amir Goldstein73072282019-01-10 19:04:39 +0200890 err = vfs_get_fsid(path->dentry, fsid);
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200891 if (err)
892 return err;
893
Amir Goldstein73072282019-01-10 19:04:39 +0200894 if (!fsid->val[0] && !fsid->val[1])
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200895 return -ENODEV;
896
897 /*
898 * Make sure path is not inside a filesystem subvolume (e.g. btrfs)
899 * which uses a different fsid than sb root.
900 */
Amir Goldstein73072282019-01-10 19:04:39 +0200901 err = vfs_get_fsid(path->dentry->d_sb->s_root, &root_fsid);
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200902 if (err)
903 return err;
904
Amir Goldstein73072282019-01-10 19:04:39 +0200905 if (root_fsid.val[0] != fsid->val[0] ||
906 root_fsid.val[1] != fsid->val[1])
Amir Goldsteina8b13aa2019-01-10 19:04:36 +0200907 return -EXDEV;
908
909 /*
910 * We need to make sure that the file system supports at least
911 * encoding a file handle so user can use name_to_handle_at() to
912 * compare fid returned with event to the file handle of watched
913 * objects. However, name_to_handle_at() requires that the
914 * filesystem also supports decoding file handles.
915 */
916 if (!path->dentry->d_sb->s_export_op ||
917 !path->dentry->d_sb->s_export_op->fh_to_dentry)
918 return -EOPNOTSUPP;
919
920 return 0;
921}
922
Dominik Brodowski183caa32018-03-17 15:06:11 +0100923static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
924 int dfd, const char __user *pathname)
Eric Parisbbaa4162009-12-17 21:24:26 -0500925{
Eric Paris0ff21db2009-12-17 21:24:29 -0500926 struct inode *inode = NULL;
927 struct vfsmount *mnt = NULL;
Eric Paris2a3edf82009-12-17 21:24:26 -0500928 struct fsnotify_group *group;
Al Viro2903ff02012-08-28 12:52:22 -0400929 struct fd f;
Eric Paris2a3edf82009-12-17 21:24:26 -0500930 struct path path;
Amir Goldstein73072282019-01-10 19:04:39 +0200931 __kernel_fsid_t __fsid, *fsid = NULL;
Amir Goldsteinbdd5a462018-10-04 00:25:37 +0300932 u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS;
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300933 unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS;
Al Viro2903ff02012-08-28 12:52:22 -0400934 int ret;
Eric Paris2a3edf82009-12-17 21:24:26 -0500935
936 pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
937 __func__, fanotify_fd, flags, dfd, pathname, mask);
938
939 /* we only use the lower 32 bits as of right now. */
940 if (mask & ((__u64)0xffffffff << 32))
941 return -EINVAL;
942
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300943 if (flags & ~FANOTIFY_MARK_FLAGS)
Andreas Gruenbacher88380fe2009-12-17 21:24:29 -0500944 return -EINVAL;
Amir Goldsteind54f4fb2018-09-01 10:41:13 +0300945
946 switch (mark_type) {
947 case FAN_MARK_INODE:
948 case FAN_MARK_MOUNT:
949 case FAN_MARK_FILESYSTEM:
950 break;
951 default:
952 return -EINVAL;
953 }
954
Eric Paris4d926042009-12-17 21:24:34 -0500955 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
Lino Sanfilippo1734dee2010-11-22 18:46:33 +0100956 case FAN_MARK_ADD: /* fallthrough */
Andreas Gruenbacher88380fe2009-12-17 21:24:29 -0500957 case FAN_MARK_REMOVE:
Lino Sanfilippo1734dee2010-11-22 18:46:33 +0100958 if (!mask)
959 return -EINVAL;
Heinrich Schuchardtcc299a92014-06-04 16:05:43 -0700960 break;
Eric Paris4d926042009-12-17 21:24:34 -0500961 case FAN_MARK_FLUSH:
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300962 if (flags & ~(FANOTIFY_MARK_TYPE_BITS | FAN_MARK_FLUSH))
Heinrich Schuchardtcc299a92014-06-04 16:05:43 -0700963 return -EINVAL;
Andreas Gruenbacher88380fe2009-12-17 21:24:29 -0500964 break;
965 default:
966 return -EINVAL;
967 }
Eric Paris8fcd6522010-10-28 17:21:59 -0400968
Miklos Szeredi6685df32017-10-30 21:14:56 +0100969 if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS))
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300970 valid_mask |= FANOTIFY_PERM_EVENTS;
Miklos Szeredi6685df32017-10-30 21:14:56 +0100971
972 if (mask & ~valid_mask)
Eric Paris2a3edf82009-12-17 21:24:26 -0500973 return -EINVAL;
974
Al Viro2903ff02012-08-28 12:52:22 -0400975 f = fdget(fanotify_fd);
976 if (unlikely(!f.file))
Eric Paris2a3edf82009-12-17 21:24:26 -0500977 return -EBADF;
978
979 /* verify that this is indeed an fanotify instance */
980 ret = -EINVAL;
Al Viro2903ff02012-08-28 12:52:22 -0400981 if (unlikely(f.file->f_op != &fanotify_fops))
Eric Paris2a3edf82009-12-17 21:24:26 -0500982 goto fput_and_out;
Al Viro2903ff02012-08-28 12:52:22 -0400983 group = f.file->private_data;
Eric Paris4231a232010-10-28 17:21:56 -0400984
985 /*
986 * group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF. These are not
987 * allowed to set permissions events.
988 */
989 ret = -EINVAL;
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300990 if (mask & FANOTIFY_PERM_EVENTS &&
Eric Paris4231a232010-10-28 17:21:56 -0400991 group->priority == FS_PRIO_0)
992 goto fput_and_out;
Eric Paris2a3edf82009-12-17 21:24:26 -0500993
Amir Goldstein235328d2019-01-10 19:04:43 +0200994 /*
995 * Events with data type inode do not carry enough information to report
996 * event->fd, so we do not allow setting a mask for inode events unless
997 * group supports reporting fid.
998 * inode events are not supported on a mount mark, because they do not
999 * carry enough information (i.e. path) to be filtered by mount point.
1000 */
1001 if (mask & FANOTIFY_INODE_EVENTS &&
1002 (!FAN_GROUP_FLAG(group, FAN_REPORT_FID) ||
1003 mark_type == FAN_MARK_MOUNT))
1004 goto fput_and_out;
1005
Heinrich Schuchardt0a8dd2d2014-06-04 16:05:40 -07001006 if (flags & FAN_MARK_FLUSH) {
1007 ret = 0;
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001008 if (mark_type == FAN_MARK_MOUNT)
Heinrich Schuchardt0a8dd2d2014-06-04 16:05:40 -07001009 fsnotify_clear_vfsmount_marks_by_group(group);
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001010 else if (mark_type == FAN_MARK_FILESYSTEM)
1011 fsnotify_clear_sb_marks_by_group(group);
Heinrich Schuchardt0a8dd2d2014-06-04 16:05:40 -07001012 else
1013 fsnotify_clear_inode_marks_by_group(group);
1014 goto fput_and_out;
1015 }
1016
Eric Paris2a3edf82009-12-17 21:24:26 -05001017 ret = fanotify_find_path(dfd, pathname, &path, flags);
1018 if (ret)
1019 goto fput_and_out;
1020
Amir Goldsteina8b13aa2019-01-10 19:04:36 +02001021 if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) {
Amir Goldstein73072282019-01-10 19:04:39 +02001022 ret = fanotify_test_fid(&path, &__fsid);
Amir Goldsteina8b13aa2019-01-10 19:04:36 +02001023 if (ret)
1024 goto path_put_and_out;
Amir Goldstein77115222019-01-10 19:04:37 +02001025
Amir Goldstein73072282019-01-10 19:04:39 +02001026 fsid = &__fsid;
Amir Goldsteina8b13aa2019-01-10 19:04:36 +02001027 }
1028
Eric Paris2a3edf82009-12-17 21:24:26 -05001029 /* inode held in place by reference to path; group by fget on fd */
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001030 if (mark_type == FAN_MARK_INODE)
Eric Paris0ff21db2009-12-17 21:24:29 -05001031 inode = path.dentry->d_inode;
1032 else
1033 mnt = path.mnt;
Eric Paris2a3edf82009-12-17 21:24:26 -05001034
1035 /* create/update an inode mark */
Heinrich Schuchardt0a8dd2d2014-06-04 16:05:40 -07001036 switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) {
Andreas Gruenbacherc6223f42009-12-17 21:24:28 -05001037 case FAN_MARK_ADD:
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001038 if (mark_type == FAN_MARK_MOUNT)
Amir Goldstein77115222019-01-10 19:04:37 +02001039 ret = fanotify_add_vfsmount_mark(group, mnt, mask,
1040 flags, fsid);
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001041 else if (mark_type == FAN_MARK_FILESYSTEM)
Amir Goldstein77115222019-01-10 19:04:37 +02001042 ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask,
1043 flags, fsid);
Eric Paris0ff21db2009-12-17 21:24:29 -05001044 else
Amir Goldstein77115222019-01-10 19:04:37 +02001045 ret = fanotify_add_inode_mark(group, inode, mask,
1046 flags, fsid);
Andreas Gruenbacherc6223f42009-12-17 21:24:28 -05001047 break;
1048 case FAN_MARK_REMOVE:
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001049 if (mark_type == FAN_MARK_MOUNT)
Amir Goldstein77115222019-01-10 19:04:37 +02001050 ret = fanotify_remove_vfsmount_mark(group, mnt, mask,
1051 flags);
Amir Goldsteind54f4fb2018-09-01 10:41:13 +03001052 else if (mark_type == FAN_MARK_FILESYSTEM)
Amir Goldstein77115222019-01-10 19:04:37 +02001053 ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask,
1054 flags);
Andreas Gruenbacherf3640192009-12-17 21:24:29 -05001055 else
Amir Goldstein77115222019-01-10 19:04:37 +02001056 ret = fanotify_remove_inode_mark(group, inode, mask,
1057 flags);
Andreas Gruenbacherc6223f42009-12-17 21:24:28 -05001058 break;
1059 default:
1060 ret = -EINVAL;
1061 }
Eric Paris2a3edf82009-12-17 21:24:26 -05001062
Amir Goldsteina8b13aa2019-01-10 19:04:36 +02001063path_put_and_out:
Eric Paris2a3edf82009-12-17 21:24:26 -05001064 path_put(&path);
1065fput_and_out:
Al Viro2903ff02012-08-28 12:52:22 -04001066 fdput(f);
Eric Paris2a3edf82009-12-17 21:24:26 -05001067 return ret;
Eric Parisbbaa4162009-12-17 21:24:26 -05001068}
Eric Paris2a3edf82009-12-17 21:24:26 -05001069
Dominik Brodowski183caa32018-03-17 15:06:11 +01001070SYSCALL_DEFINE5(fanotify_mark, int, fanotify_fd, unsigned int, flags,
1071 __u64, mask, int, dfd,
1072 const char __user *, pathname)
1073{
1074 return do_fanotify_mark(fanotify_fd, flags, mask, dfd, pathname);
1075}
1076
Al Viro91c2e0b2013-03-05 20:10:59 -05001077#ifdef CONFIG_COMPAT
1078COMPAT_SYSCALL_DEFINE6(fanotify_mark,
1079 int, fanotify_fd, unsigned int, flags,
1080 __u32, mask0, __u32, mask1, int, dfd,
1081 const char __user *, pathname)
1082{
Dominik Brodowski183caa32018-03-17 15:06:11 +01001083 return do_fanotify_mark(fanotify_fd, flags,
Al Viro91c2e0b2013-03-05 20:10:59 -05001084#ifdef __BIG_ENDIAN
Al Viro91c2e0b2013-03-05 20:10:59 -05001085 ((__u64)mask0 << 32) | mask1,
Heiko Carstens592f6b82014-01-27 17:07:19 -08001086#else
1087 ((__u64)mask1 << 32) | mask0,
Al Viro91c2e0b2013-03-05 20:10:59 -05001088#endif
1089 dfd, pathname);
1090}
1091#endif
1092
Eric Paris2a3edf82009-12-17 21:24:26 -05001093/*
Justin P. Mattockae0e47f2011-03-01 15:06:02 +01001094 * fanotify_user_setup - Our initialization function. Note that we cannot return
Eric Paris2a3edf82009-12-17 21:24:26 -05001095 * error because we have compiled-in VFS hooks. So an (unlikely) failure here
1096 * must result in panic().
1097 */
1098static int __init fanotify_user_setup(void)
1099{
Amir Goldsteina8b13aa2019-01-10 19:04:36 +02001100 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 8);
Amir Goldsteinbdd5a462018-10-04 00:25:37 +03001101 BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9);
1102
Shakeel Buttd46eb14b2018-08-17 15:46:39 -07001103 fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
1104 SLAB_PANIC|SLAB_ACCOUNT);
Amir Goldstein33913992019-01-10 19:04:32 +02001105 fanotify_event_cachep = KMEM_CACHE(fanotify_event, SLAB_PANIC);
Miklos Szeredi6685df32017-10-30 21:14:56 +01001106 if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) {
1107 fanotify_perm_event_cachep =
Amir Goldstein33913992019-01-10 19:04:32 +02001108 KMEM_CACHE(fanotify_perm_event, SLAB_PANIC);
Miklos Szeredi6685df32017-10-30 21:14:56 +01001109 }
Eric Paris2a3edf82009-12-17 21:24:26 -05001110
1111 return 0;
1112}
1113device_initcall(fanotify_user_setup);