blob: cedcb1546804387dc62b97ea88871076290650c8 [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 Parisff0b16a2009-12-17 21:24:25 -05003#include <linux/fdtable.h>
4#include <linux/fsnotify_backend.h>
5#include <linux/init.h>
Eric Paris9e66e422009-12-17 21:24:34 -05006#include <linux/jiffies.h>
Eric Parisff0b16a2009-12-17 21:24:25 -05007#include <linux/kernel.h> /* UINT_MAX */
Eric Paris1c529062009-12-17 21:24:28 -05008#include <linux/mount.h>
Eric Paris9e66e422009-12-17 21:24:34 -05009#include <linux/sched.h>
Ingo Molnar5b825c32017-02-02 17:54:15 +010010#include <linux/sched/user.h>
Eric W. Biederman7a360942017-09-26 12:45:33 -050011#include <linux/sched/signal.h>
Eric Parisff0b16a2009-12-17 21:24:25 -050012#include <linux/types.h>
Eric Paris9e66e422009-12-17 21:24:34 -050013#include <linux/wait.h>
Steve Grubbde8cd832017-10-02 20:21:39 -040014#include <linux/audit.h>
Shakeel Buttd46eb14b2018-08-17 15:46:39 -070015#include <linux/sched/mm.h>
Amir Goldsteine9e0c892019-01-10 19:04:34 +020016#include <linux/statfs.h>
Amir Goldstein7e3e5c62021-03-04 12:48:24 +020017#include <linux/stringhash.h>
Eric Parisff0b16a2009-12-17 21:24:25 -050018
Jan Kara7053aee2014-01-21 15:48:14 -080019#include "fanotify.h"
Eric Paris767cd462009-12-17 21:24:25 -050020
Jan Karaafc894c2020-03-24 16:55:37 +010021static bool fanotify_path_equal(struct path *p1, struct path *p2)
22{
23 return p1->mnt == p2->mnt && p1->dentry == p2->dentry;
24}
25
Amir Goldstein7e3e5c62021-03-04 12:48:24 +020026static unsigned int fanotify_hash_path(const struct path *path)
27{
28 return hash_ptr(path->dentry, FANOTIFY_EVENT_HASH_BITS) ^
29 hash_ptr(path->mnt, FANOTIFY_EVENT_HASH_BITS);
30}
31
Jan Karaafc894c2020-03-24 16:55:37 +010032static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1,
33 __kernel_fsid_t *fsid2)
34{
Nathan Chancellor6def1a12020-03-27 10:10:30 -070035 return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1];
Jan Karaafc894c2020-03-24 16:55:37 +010036}
37
Amir Goldstein7e3e5c62021-03-04 12:48:24 +020038static unsigned int fanotify_hash_fsid(__kernel_fsid_t *fsid)
39{
40 return hash_32(fsid->val[0], FANOTIFY_EVENT_HASH_BITS) ^
41 hash_32(fsid->val[1], FANOTIFY_EVENT_HASH_BITS);
42}
43
Jan Karaafc894c2020-03-24 16:55:37 +010044static bool fanotify_fh_equal(struct fanotify_fh *fh1,
Jan Kara7088f352020-03-24 17:04:20 +010045 struct fanotify_fh *fh2)
Jan Karaafc894c2020-03-24 16:55:37 +010046{
47 if (fh1->type != fh2->type || fh1->len != fh2->len)
48 return false;
49
Jan Karaafc894c2020-03-24 16:55:37 +010050 return !fh1->len ||
51 !memcmp(fanotify_fh_buf(fh1), fanotify_fh_buf(fh2), fh1->len);
52}
53
Amir Goldstein7e3e5c62021-03-04 12:48:24 +020054static unsigned int fanotify_hash_fh(struct fanotify_fh *fh)
55{
56 long salt = (long)fh->type | (long)fh->len << 8;
57
58 /*
59 * full_name_hash() works long by long, so it handles fh buf optimally.
60 */
61 return full_name_hash((void *)salt, fanotify_fh_buf(fh), fh->len);
62}
63
Jan Kara7088f352020-03-24 17:04:20 +010064static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1,
65 struct fanotify_fid_event *ffe2)
66{
67 /* Do not merge fid events without object fh */
68 if (!ffe1->object_fh.len)
69 return false;
70
71 return fanotify_fsid_equal(&ffe1->fsid, &ffe2->fsid) &&
72 fanotify_fh_equal(&ffe1->object_fh, &ffe2->object_fh);
73}
74
Amir Goldsteinf454fa62020-07-16 11:42:17 +030075static bool fanotify_info_equal(struct fanotify_info *info1,
76 struct fanotify_info *info2)
77{
78 if (info1->dir_fh_totlen != info2->dir_fh_totlen ||
79 info1->file_fh_totlen != info2->file_fh_totlen ||
80 info1->name_len != info2->name_len)
81 return false;
82
83 if (info1->dir_fh_totlen &&
84 !fanotify_fh_equal(fanotify_info_dir_fh(info1),
85 fanotify_info_dir_fh(info2)))
86 return false;
87
88 if (info1->file_fh_totlen &&
89 !fanotify_fh_equal(fanotify_info_file_fh(info1),
90 fanotify_info_file_fh(info2)))
91 return false;
92
93 return !info1->name_len ||
94 !memcmp(fanotify_info_name(info1), fanotify_info_name(info2),
95 info1->name_len);
96}
97
Amir Goldsteincacfb952020-03-19 17:10:21 +020098static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
99 struct fanotify_name_event *fne2)
100{
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300101 struct fanotify_info *info1 = &fne1->info;
102 struct fanotify_info *info2 = &fne2->info;
103
Amir Goldstein6ad1aad2020-07-16 11:42:11 +0300104 /* Do not merge name events without dir fh */
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300105 if (!info1->dir_fh_totlen)
Amir Goldsteincacfb952020-03-19 17:10:21 +0200106 return false;
107
Jan Kara8aed8ce2020-07-28 10:58:07 +0200108 if (!fanotify_fsid_equal(&fne1->fsid, &fne2->fsid))
109 return false;
110
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300111 return fanotify_info_equal(info1, info2);
Amir Goldsteincacfb952020-03-19 17:10:21 +0200112}
113
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300114static bool fanotify_error_event_equal(struct fanotify_error_event *fee1,
115 struct fanotify_error_event *fee2)
116{
117 /* Error events against the same file system are always merged. */
118 if (!fanotify_fsid_equal(&fee1->fsid, &fee2->fsid))
119 return false;
120
121 return true;
122}
123
Amir Goldstein8988f112021-03-04 12:48:23 +0200124static bool fanotify_should_merge(struct fanotify_event *old,
125 struct fanotify_event *new)
Jan Kara7053aee2014-01-21 15:48:14 -0800126{
Amir Goldstein8988f112021-03-04 12:48:23 +0200127 pr_debug("%s: old=%p new=%p\n", __func__, old, new);
Jan Kara7053aee2014-01-21 15:48:14 -0800128
Amir Goldstein8988f112021-03-04 12:48:23 +0200129 if (old->hash != new->hash ||
Jan Kara7088f352020-03-24 17:04:20 +0100130 old->type != new->type || old->pid != new->pid)
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200131 return false;
132
Amir Goldstein103ff6a2020-07-16 11:42:10 +0300133 /*
134 * We want to merge many dirent events in the same dir (i.e.
135 * creates/unlinks/renames), but we do not want to merge dirent
136 * events referring to subdirs with dirent events referring to
137 * non subdirs, otherwise, user won't be able to tell from a
138 * mask FAN_CREATE|FAN_DELETE|FAN_ONDIR if it describes mkdir+
139 * unlink pair or rmdir+create pair of events.
140 */
141 if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR))
142 return false;
143
Jan Kara7088f352020-03-24 17:04:20 +0100144 switch (old->type) {
145 case FANOTIFY_EVENT_TYPE_PATH:
Jan Karaafc894c2020-03-24 16:55:37 +0100146 return fanotify_path_equal(fanotify_event_path(old),
147 fanotify_event_path(new));
Jan Kara7088f352020-03-24 17:04:20 +0100148 case FANOTIFY_EVENT_TYPE_FID:
Jan Kara7088f352020-03-24 17:04:20 +0100149 return fanotify_fid_event_equal(FANOTIFY_FE(old),
150 FANOTIFY_FE(new));
Amir Goldsteincacfb952020-03-19 17:10:21 +0200151 case FANOTIFY_EVENT_TYPE_FID_NAME:
152 return fanotify_name_event_equal(FANOTIFY_NE(old),
153 FANOTIFY_NE(new));
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300154 case FANOTIFY_EVENT_TYPE_FS_ERROR:
155 return fanotify_error_event_equal(FANOTIFY_EE(old),
156 FANOTIFY_EE(new));
Jan Kara7088f352020-03-24 17:04:20 +0100157 default:
158 WARN_ON_ONCE(1);
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200159 }
160
Eric Paris767cd462009-12-17 21:24:25 -0500161 return false;
162}
163
Amir Goldsteinb8cd0ee2021-03-04 12:48:26 +0200164/* Limit event merges to limit CPU overhead per event */
165#define FANOTIFY_MAX_MERGE_EVENTS 128
166
Eric Parisf70ab542010-07-28 10:18:37 -0400167/* and the list better be locked by something too! */
Amir Goldstein94e00d22021-03-04 12:48:25 +0200168static int fanotify_merge(struct fsnotify_group *group,
169 struct fsnotify_event *event)
Eric Paris767cd462009-12-17 21:24:25 -0500170{
Amir Goldstein8988f112021-03-04 12:48:23 +0200171 struct fanotify_event *old, *new = FANOTIFY_E(event);
Amir Goldstein94e00d22021-03-04 12:48:25 +0200172 unsigned int bucket = fanotify_event_hash_bucket(group, new);
173 struct hlist_head *hlist = &group->fanotify_data.merge_hash[bucket];
Amir Goldsteinb8cd0ee2021-03-04 12:48:26 +0200174 int i = 0;
Eric Paris767cd462009-12-17 21:24:25 -0500175
Amir Goldstein94e00d22021-03-04 12:48:25 +0200176 pr_debug("%s: group=%p event=%p bucket=%u\n", __func__,
177 group, event, bucket);
Eric Paris767cd462009-12-17 21:24:25 -0500178
Jan Kara13116df2014-01-28 18:29:24 +0100179 /*
180 * Don't merge a permission event with any other event so that we know
181 * the event structure we have created in fanotify_handle_event() is the
182 * one we should check for permission response.
183 */
Amir Goldsteina0a92d22019-01-10 19:04:31 +0200184 if (fanotify_is_perm_event(new->mask))
Jan Kara83c0e1b2014-01-28 18:53:22 +0100185 return 0;
Jan Kara13116df2014-01-28 18:29:24 +0100186
Amir Goldstein94e00d22021-03-04 12:48:25 +0200187 hlist_for_each_entry(old, hlist, merge_list) {
Amir Goldsteinb8cd0ee2021-03-04 12:48:26 +0200188 if (++i > FANOTIFY_MAX_MERGE_EVENTS)
189 break;
Amir Goldstein8988f112021-03-04 12:48:23 +0200190 if (fanotify_should_merge(old, new)) {
191 old->mask |= new->mask;
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300192
193 if (fanotify_is_error_event(old->mask))
194 FANOTIFY_EE(old)->err_count++;
195
Kinglong Mee6c711002017-02-09 20:45:22 +0800196 return 1;
Eric Parisa12a7dd2009-12-17 21:24:25 -0500197 }
198 }
Eric Parisf70ab542010-07-28 10:18:37 -0400199
Kinglong Mee6c711002017-02-09 20:45:22 +0800200 return 0;
Eric Paris767cd462009-12-17 21:24:25 -0500201}
202
Jan Karafabf7f22019-01-08 15:18:02 +0100203/*
204 * Wait for response to permission event. The function also takes care of
205 * freeing the permission event (or offloads that in case the wait is canceled
206 * by a signal). The function returns 0 in case access got allowed by userspace,
207 * -EPERM in case userspace disallowed the access, and -ERESTARTSYS in case
208 * the wait got interrupted by a signal.
209 */
Jan Karaf0834412014-04-03 14:46:33 -0700210static int fanotify_get_response(struct fsnotify_group *group,
Amir Goldstein33913992019-01-10 19:04:32 +0200211 struct fanotify_perm_event *event,
Jan Kara05f0e382016-11-10 17:45:16 +0100212 struct fsnotify_iter_info *iter_info)
Eric Paris9e66e422009-12-17 21:24:34 -0500213{
214 int ret;
215
216 pr_debug("%s: group=%p event=%p\n", __func__, group, event);
217
Jan Karab5190572019-02-21 11:47:23 +0100218 ret = wait_event_killable(group->fanotify_data.access_waitq,
219 event->state == FAN_EVENT_ANSWERED);
Jan Karafabf7f22019-01-08 15:18:02 +0100220 /* Signal pending? */
221 if (ret < 0) {
222 spin_lock(&group->notification_lock);
223 /* Event reported to userspace and no answer yet? */
224 if (event->state == FAN_EVENT_REPORTED) {
225 /* Event will get freed once userspace answers to it */
226 event->state = FAN_EVENT_CANCELED;
227 spin_unlock(&group->notification_lock);
228 return ret;
229 }
230 /* Event not yet reported? Just remove it. */
Amir Goldstein94e00d22021-03-04 12:48:25 +0200231 if (event->state == FAN_EVENT_INIT) {
Jan Karafabf7f22019-01-08 15:18:02 +0100232 fsnotify_remove_queued_event(group, &event->fae.fse);
Amir Goldstein94e00d22021-03-04 12:48:25 +0200233 /* Permission events are not supposed to be hashed */
234 WARN_ON_ONCE(!hlist_unhashed(&event->fae.merge_list));
235 }
Jan Karafabf7f22019-01-08 15:18:02 +0100236 /*
237 * Event may be also answered in case signal delivery raced
238 * with wakeup. In that case we have nothing to do besides
239 * freeing the event and reporting error.
240 */
241 spin_unlock(&group->notification_lock);
242 goto out;
243 }
Eric Paris9e66e422009-12-17 21:24:34 -0500244
245 /* userspace responded, convert to something usable */
Steve Grubbde8cd832017-10-02 20:21:39 -0400246 switch (event->response & ~FAN_AUDIT) {
Eric Paris9e66e422009-12-17 21:24:34 -0500247 case FAN_ALLOW:
248 ret = 0;
249 break;
250 case FAN_DENY:
251 default:
252 ret = -EPERM;
253 }
Steve Grubbde8cd832017-10-02 20:21:39 -0400254
255 /* Check if the response should be audited */
256 if (event->response & FAN_AUDIT)
257 audit_fanotify(event->response & ~FAN_AUDIT);
258
Eric Parisb2d87902009-12-17 21:24:34 -0500259 pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
260 group, event, ret);
Jan Karafabf7f22019-01-08 15:18:02 +0100261out:
262 fsnotify_destroy_event(group, &event->fae.fse);
Amir Goldstein83b535d2019-01-10 19:04:42 +0200263
Eric Paris9e66e422009-12-17 21:24:34 -0500264 return ret;
265}
Eric Paris9e66e422009-12-17 21:24:34 -0500266
Matthew Bobrowski2d10b232018-11-08 14:05:49 +1100267/*
268 * This function returns a mask for an event that only contains the flags
269 * that have been specifically requested by the user. Flags that may have
270 * been included within the event mask, but have not been explicitly
271 * requested by the user, will not be present in the returned mask.
272 */
Amir Goldstein83b535d2019-01-10 19:04:42 +0200273static u32 fanotify_group_event_mask(struct fsnotify_group *group,
274 struct fsnotify_iter_info *iter_info,
275 u32 event_mask, const void *data,
Amir Goldstein83b7a592020-07-16 11:42:26 +0300276 int data_type, struct inode *dir)
Eric Paris1c529062009-12-17 21:24:28 -0500277{
Amir Goldstein54a307b2018-04-04 23:42:18 +0300278 __u32 marks_mask = 0, marks_ignored_mask = 0;
Amir Goldstein0badfa02020-07-16 11:42:09 +0300279 __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS |
280 FANOTIFY_EVENT_FLAGS;
Amir Goldsteinaa93bdc2020-03-19 17:10:12 +0200281 const struct path *path = fsnotify_data_path(data, data_type);
Amir Goldsteind809daf2020-07-16 11:42:12 +0300282 unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
Amir Goldstein837a3932018-04-20 16:10:54 -0700283 struct fsnotify_mark *mark;
284 int type;
Eric Paris1968f5e2010-07-28 10:18:39 -0400285
Amir Goldstein837a3932018-04-20 16:10:54 -0700286 pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
287 __func__, iter_info->report_mask, event_mask, data, data_type);
Eric Paris1968f5e2010-07-28 10:18:39 -0400288
Amir Goldsteind809daf2020-07-16 11:42:12 +0300289 if (!fid_mode) {
Amir Goldstein83b535d2019-01-10 19:04:42 +0200290 /* Do we have path to open a file descriptor? */
Amir Goldsteinaa93bdc2020-03-19 17:10:12 +0200291 if (!path)
Amir Goldstein83b535d2019-01-10 19:04:42 +0200292 return 0;
293 /* Path type events are only relevant for files and dirs */
294 if (!d_is_reg(path->dentry) && !d_can_lookup(path->dentry))
295 return 0;
Amir Goldstein83b7a592020-07-16 11:42:26 +0300296 } else if (!(fid_mode & FAN_REPORT_FID)) {
297 /* Do we have a directory inode to report? */
298 if (!dir && !(event_mask & FS_ISDIR))
299 return 0;
Amir Goldstein83b535d2019-01-10 19:04:42 +0200300 }
Eric Parise1c048b2010-10-28 17:21:58 -0400301
Amir Goldstein837a3932018-04-20 16:10:54 -0700302 fsnotify_foreach_obj_type(type) {
303 if (!fsnotify_iter_should_report_type(iter_info, type))
304 continue;
305 mark = iter_info->marks[type];
Amir Goldstein2f02fd32020-05-24 10:24:41 +0300306
307 /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */
308 marks_ignored_mask |= mark->ignored_mask;
309
Amir Goldstein837a3932018-04-20 16:10:54 -0700310 /*
Amir Goldstein55bf8822020-03-19 17:10:17 +0200311 * If the event is on dir and this mark doesn't care about
312 * events on dir, don't send it!
313 */
314 if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
315 continue;
316
317 /*
Amir Goldsteinfecc4552020-12-02 14:07:09 +0200318 * If the event is on a child and this mark is on a parent not
Amir Goldstein497b0c52020-07-16 11:42:22 +0300319 * watching children, don't send it!
Amir Goldstein837a3932018-04-20 16:10:54 -0700320 */
Amir Goldsteinfecc4552020-12-02 14:07:09 +0200321 if (type == FSNOTIFY_OBJ_TYPE_PARENT &&
322 !(mark->mask & FS_EVENT_ON_CHILD))
Amir Goldstein837a3932018-04-20 16:10:54 -0700323 continue;
Amir Goldstein54a307b2018-04-04 23:42:18 +0300324
Amir Goldstein837a3932018-04-20 16:10:54 -0700325 marks_mask |= mark->mask;
Eric Paris1968f5e2010-07-28 10:18:39 -0400326 }
327
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200328 test_mask = event_mask & marks_mask & ~marks_ignored_mask;
329
330 /*
Amir Goldstein9e2ba2c2020-03-19 17:10:19 +0200331 * For dirent modification events (create/delete/move) that do not carry
332 * the child entry name information, we report FAN_ONDIR for mkdir/rmdir
333 * so user can differentiate them from creat/unlink.
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200334 *
335 * For backward compatibility and consistency, do not report FAN_ONDIR
336 * to user in legacy fanotify mode (reporting fd) and report FAN_ONDIR
Amir Goldstein0badfa02020-07-16 11:42:09 +0300337 * to user in fid mode for all event types.
338 *
339 * We never report FAN_EVENT_ON_CHILD to user, but we do pass it in to
340 * fanotify_alloc_event() when group is reporting fid as indication
341 * that event happened on child.
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200342 */
Amir Goldsteind809daf2020-07-16 11:42:12 +0300343 if (fid_mode) {
Amir Goldstein0badfa02020-07-16 11:42:09 +0300344 /* Do not report event flags without any event */
345 if (!(test_mask & ~FANOTIFY_EVENT_FLAGS))
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200346 return 0;
347 } else {
Amir Goldstein0badfa02020-07-16 11:42:09 +0300348 user_mask &= ~FANOTIFY_EVENT_FLAGS;
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200349 }
350
Amir Goldsteine7fce6d2019-01-10 19:04:44 +0200351 return test_mask & user_mask;
Eric Paris1c529062009-12-17 21:24:28 -0500352}
353
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300354/*
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300355 * Check size needed to encode fanotify_fh.
356 *
357 * Return size of encoded fh without fanotify_fh header.
358 * Return 0 on failure to encode.
359 */
360static int fanotify_encode_fh_len(struct inode *inode)
361{
362 int dwords = 0;
363
364 if (!inode)
365 return 0;
366
367 exportfs_encode_inode_fh(inode, NULL, &dwords, NULL);
368
369 return dwords << 2;
370}
371
372/*
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300373 * Encode fanotify_fh.
374 *
375 * Return total size of encoded fh including fanotify_fh header.
376 * Return 0 on failure to encode.
377 */
378static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200379 unsigned int fh_len, unsigned int *hash,
380 gfp_t gfp)
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200381{
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300382 int dwords, type = 0;
Jan Karaafc894c2020-03-24 16:55:37 +0100383 char *ext_buf = NULL;
384 void *buf = fh->buf;
385 int err;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200386
Amir Goldstein6ad1aad2020-07-16 11:42:11 +0300387 fh->type = FILEID_ROOT;
388 fh->len = 0;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300389 fh->flags = 0;
Gabriel Krisman Bertazi272531a2021-10-25 16:27:30 -0300390
391 /*
392 * Invalid FHs are used by FAN_FS_ERROR for errors not
393 * linked to any inode. The f_handle won't be reported
394 * back to userspace.
395 */
Amir Goldsteincacfb952020-03-19 17:10:21 +0200396 if (!inode)
Gabriel Krisman Bertazi272531a2021-10-25 16:27:30 -0300397 goto out;
Amir Goldsteincacfb952020-03-19 17:10:21 +0200398
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300399 /*
400 * !gpf means preallocated variable size fh, but fh_len could
401 * be zero in that case if encoding fh len failed.
402 */
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200403 err = -ENOENT;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300404 if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4))
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200405 goto out_err;
406
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300407 /* No external buffer in a variable size allocated fh */
408 if (gfp && fh_len > FANOTIFY_INLINE_FH_LEN) {
409 /* Treat failure to allocate fh as failure to encode fh */
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200410 err = -ENOMEM;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300411 ext_buf = kmalloc(fh_len, gfp);
Jan Karaafc894c2020-03-24 16:55:37 +0100412 if (!ext_buf)
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200413 goto out_err;
Jan Karaafc894c2020-03-24 16:55:37 +0100414
415 *fanotify_fh_ext_buf_ptr(fh) = ext_buf;
416 buf = ext_buf;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300417 fh->flags |= FANOTIFY_FH_FLAG_EXT_BUF;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200418 }
419
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300420 dwords = fh_len >> 2;
Jan Karaafc894c2020-03-24 16:55:37 +0100421 type = exportfs_encode_inode_fh(inode, buf, &dwords, NULL);
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200422 err = -EINVAL;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300423 if (!type || type == FILEID_INVALID || fh_len != dwords << 2)
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200424 goto out_err;
425
Jan Karaafc894c2020-03-24 16:55:37 +0100426 fh->type = type;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300427 fh->len = fh_len;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200428
Gabriel Krisman Bertazi272531a2021-10-25 16:27:30 -0300429out:
Gabriel Krisman Bertazi74fe4732021-10-25 16:27:29 -0300430 /*
431 * Mix fh into event merge key. Hash might be NULL in case of
432 * unhashed FID events (i.e. FAN_FS_ERROR).
433 */
434 if (hash)
435 *hash ^= fanotify_hash_fh(fh);
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200436
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300437 return FANOTIFY_FH_HDR_LEN + fh_len;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200438
439out_err:
Jan Karaafc894c2020-03-24 16:55:37 +0100440 pr_warn_ratelimited("fanotify: failed to encode fid (type=%d, len=%d, err=%i)\n",
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300441 type, fh_len, err);
Jan Karaafc894c2020-03-24 16:55:37 +0100442 kfree(ext_buf);
443 *fanotify_fh_ext_buf_ptr(fh) = NULL;
444 /* Report the event without a file identifier on encode error */
445 fh->type = FILEID_INVALID;
446 fh->len = 0;
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300447 return 0;
Amir Goldsteine9e0c892019-01-10 19:04:34 +0200448}
449
Amir Goldstein83b535d2019-01-10 19:04:42 +0200450/*
451 * The inode to use as identifier when reporting fid depends on the event.
452 * Report the modified directory inode on dirent modification events.
453 * Report the "victim" inode otherwise.
454 * For example:
455 * FS_ATTRIB reports the child inode even if reported on a watched parent.
456 * FS_CREATE reports the modified dir inode and not the created inode.
457 */
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300458static struct inode *fanotify_fid_inode(u32 event_mask, const void *data,
459 int data_type, struct inode *dir)
Amir Goldstein83b535d2019-01-10 19:04:42 +0200460{
461 if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS)
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300462 return dir;
Amir Goldsteinaa93bdc2020-03-19 17:10:12 +0200463
Amir Goldsteincbcf47a2020-07-08 14:11:38 +0300464 return fsnotify_data_inode(data, data_type);
Amir Goldstein83b535d2019-01-10 19:04:42 +0200465}
466
Amir Goldstein83b7a592020-07-16 11:42:26 +0300467/*
468 * The inode to use as identifier when reporting dir fid depends on the event.
469 * Report the modified directory inode on dirent modification events.
470 * Report the "victim" inode if "victim" is a directory.
471 * Report the parent inode if "victim" is not a directory and event is
472 * reported to parent.
473 * Otherwise, do not report dir fid.
474 */
475static struct inode *fanotify_dfid_inode(u32 event_mask, const void *data,
476 int data_type, struct inode *dir)
477{
478 struct inode *inode = fsnotify_data_inode(data, data_type);
479
480 if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS)
481 return dir;
482
Gabriel Krisman Bertazi12f47bf2021-10-25 16:27:28 -0300483 if (inode && S_ISDIR(inode->i_mode))
Amir Goldstein83b7a592020-07-16 11:42:26 +0300484 return inode;
485
486 return dir;
487}
488
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300489static struct fanotify_event *fanotify_alloc_path_event(const struct path *path,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200490 unsigned int *hash,
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300491 gfp_t gfp)
492{
493 struct fanotify_path_event *pevent;
494
495 pevent = kmem_cache_alloc(fanotify_path_event_cachep, gfp);
496 if (!pevent)
497 return NULL;
498
499 pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH;
500 pevent->path = *path;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200501 *hash ^= fanotify_hash_path(path);
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300502 path_get(path);
503
504 return &pevent->fae;
505}
506
507static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path,
508 gfp_t gfp)
509{
510 struct fanotify_perm_event *pevent;
511
512 pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
513 if (!pevent)
514 return NULL;
515
516 pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH_PERM;
517 pevent->response = 0;
518 pevent->state = FAN_EVENT_INIT;
519 pevent->path = *path;
520 path_get(path);
521
522 return &pevent->fae;
523}
524
525static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id,
526 __kernel_fsid_t *fsid,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200527 unsigned int *hash,
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300528 gfp_t gfp)
529{
530 struct fanotify_fid_event *ffe;
531
532 ffe = kmem_cache_alloc(fanotify_fid_event_cachep, gfp);
533 if (!ffe)
534 return NULL;
535
536 ffe->fae.type = FANOTIFY_EVENT_TYPE_FID;
537 ffe->fsid = *fsid;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200538 *hash ^= fanotify_hash_fsid(fsid);
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300539 fanotify_encode_fh(&ffe->object_fh, id, fanotify_encode_fh_len(id),
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200540 hash, gfp);
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300541
542 return &ffe->fae;
543}
544
545static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
546 __kernel_fsid_t *fsid,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200547 const struct qstr *name,
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300548 struct inode *child,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200549 unsigned int *hash,
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300550 gfp_t gfp)
551{
552 struct fanotify_name_event *fne;
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300553 struct fanotify_info *info;
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300554 struct fanotify_fh *dfh, *ffh;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300555 unsigned int dir_fh_len = fanotify_encode_fh_len(id);
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300556 unsigned int child_fh_len = fanotify_encode_fh_len(child);
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300557 unsigned int size;
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300558
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300559 size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len;
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300560 if (child_fh_len)
561 size += FANOTIFY_FH_HDR_LEN + child_fh_len;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200562 if (name)
563 size += name->len + 1;
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300564 fne = kmalloc(size, gfp);
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300565 if (!fne)
566 return NULL;
567
568 fne->fae.type = FANOTIFY_EVENT_TYPE_FID_NAME;
569 fne->fsid = *fsid;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200570 *hash ^= fanotify_hash_fsid(fsid);
Amir Goldsteinf454fa62020-07-16 11:42:17 +0300571 info = &fne->info;
572 fanotify_info_init(info);
573 dfh = fanotify_info_dir_fh(info);
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200574 info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0);
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300575 if (child_fh_len) {
576 ffh = fanotify_info_file_fh(info);
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200577 info->file_fh_totlen = fanotify_encode_fh(ffh, child,
578 child_fh_len, hash, 0);
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300579 }
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200580 if (name) {
581 long salt = name->len;
582
583 fanotify_info_copy_name(info, name);
584 *hash ^= full_name_hash((void *)salt, name->name, name->len);
585 }
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300586
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300587 pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n",
588 __func__, id->i_ino, size, dir_fh_len, child_fh_len,
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300589 info->name_len, info->name_len, fanotify_info_name(info));
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300590
591 return &fne->fae;
592}
593
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300594static struct fanotify_event *fanotify_alloc_error_event(
595 struct fsnotify_group *group,
596 __kernel_fsid_t *fsid,
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300597 const void *data, int data_type,
598 unsigned int *hash)
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300599{
600 struct fs_error_report *report =
601 fsnotify_data_error_report(data, data_type);
602 struct fanotify_error_event *fee;
603
604 if (WARN_ON_ONCE(!report))
605 return NULL;
606
607 fee = mempool_alloc(&group->fanotify_data.error_events_pool, GFP_NOFS);
608 if (!fee)
609 return NULL;
610
611 fee->fae.type = FANOTIFY_EVENT_TYPE_FS_ERROR;
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300612 fee->err_count = 1;
613 fee->fsid = *fsid;
614
615 *hash ^= fanotify_hash_fsid(fsid);
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300616
617 return &fee->fae;
618}
619
Amir Goldsteinb8a6c3a2020-07-08 14:11:42 +0300620static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300621 u32 mask, const void *data,
622 int data_type, struct inode *dir,
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300623 const struct qstr *file_name,
624 __kernel_fsid_t *fsid)
Jan Karaf0834412014-04-03 14:46:33 -0700625{
Amir Goldstein33913992019-01-10 19:04:32 +0200626 struct fanotify_event *event = NULL;
Shakeel Buttd46eb14b2018-08-17 15:46:39 -0700627 gfp_t gfp = GFP_KERNEL_ACCOUNT;
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300628 struct inode *id = fanotify_fid_inode(mask, data, data_type, dir);
Amir Goldstein83b7a592020-07-16 11:42:26 +0300629 struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir);
Amir Goldsteinaa93bdc2020-03-19 17:10:12 +0200630 const struct path *path = fsnotify_data_path(data, data_type);
Amir Goldsteind809daf2020-07-16 11:42:12 +0300631 unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS);
Roman Gushchinb87d8ce2020-10-17 16:13:40 -0700632 struct mem_cgroup *old_memcg;
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300633 struct inode *child = NULL;
Amir Goldstein08b95c332020-07-08 14:11:52 +0300634 bool name_event = false;
Amir Goldstein8988f112021-03-04 12:48:23 +0200635 unsigned int hash = 0;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200636 bool ondir = mask & FAN_ONDIR;
637 struct pid *pid;
Jan Kara1f5eaa92018-02-21 14:10:59 +0100638
Amir Goldstein929943b2020-07-16 11:42:28 +0300639 if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) {
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300640 /*
641 * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we
642 * report the child fid for events reported on a non-dir child
Amir Goldstein691d9762020-07-16 11:42:30 +0300643 * in addition to reporting the parent fid and maybe child name.
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300644 */
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200645 if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir)
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300646 child = id;
647
Amir Goldstein83b7a592020-07-16 11:42:26 +0300648 id = dirid;
649
Amir Goldstein929943b2020-07-16 11:42:28 +0300650 /*
651 * We record file name only in a group with FAN_REPORT_NAME
652 * and when we have a directory inode to report.
653 *
654 * For directory entry modification event, we record the fid of
655 * the directory and the name of the modified entry.
656 *
657 * For event on non-directory that is reported to parent, we
658 * record the fid of the parent and the name of the child.
Amir Goldstein691d9762020-07-16 11:42:30 +0300659 *
660 * Even if not reporting name, we need a variable length
661 * fanotify_name_event if reporting both parent and child fids.
Amir Goldstein929943b2020-07-16 11:42:28 +0300662 */
Amir Goldstein691d9762020-07-16 11:42:30 +0300663 if (!(fid_mode & FAN_REPORT_NAME)) {
664 name_event = !!child;
665 file_name = NULL;
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200666 } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) {
Amir Goldstein929943b2020-07-16 11:42:28 +0300667 name_event = true;
Amir Goldstein691d9762020-07-16 11:42:30 +0300668 }
Amir Goldstein929943b2020-07-16 11:42:28 +0300669 }
670
Jan Kara1f5eaa92018-02-21 14:10:59 +0100671 /*
672 * For queues with unlimited length lost events are not expected and
673 * can possibly have security implications. Avoid losing events when
Shakeel Buttec165452019-07-11 20:55:52 -0700674 * memory is short. For the limited size queues, avoid OOM killer in the
675 * target monitoring memcg as it may have security repercussion.
Jan Kara1f5eaa92018-02-21 14:10:59 +0100676 */
677 if (group->max_events == UINT_MAX)
678 gfp |= __GFP_NOFAIL;
Shakeel Buttec165452019-07-11 20:55:52 -0700679 else
680 gfp |= __GFP_RETRY_MAYFAIL;
Jan Karaf0834412014-04-03 14:46:33 -0700681
Shakeel Buttd46eb14b2018-08-17 15:46:39 -0700682 /* Whoever is interested in the event, pays for the allocation. */
Roman Gushchinb87d8ce2020-10-17 16:13:40 -0700683 old_memcg = set_active_memcg(group->memcg);
Shakeel Buttd46eb14b2018-08-17 15:46:39 -0700684
Miklos Szeredi6685df32017-10-30 21:14:56 +0100685 if (fanotify_is_perm_event(mask)) {
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300686 event = fanotify_alloc_perm_event(path, gfp);
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300687 } else if (fanotify_is_error_event(mask)) {
688 event = fanotify_alloc_error_event(group, fsid, data,
Gabriel Krisman Bertazi8a6ae642021-10-25 16:27:36 -0300689 data_type, &hash);
Amir Goldstein691d9762020-07-16 11:42:30 +0300690 } else if (name_event && (file_name || child)) {
Amir Goldstein7e8283a2020-07-16 11:42:29 +0300691 event = fanotify_alloc_name_event(id, fsid, file_name, child,
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200692 &hash, gfp);
Amir Goldsteind809daf2020-07-16 11:42:12 +0300693 } else if (fid_mode) {
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200694 event = fanotify_alloc_fid_event(id, fsid, &hash, gfp);
Jan Kara7088f352020-03-24 17:04:20 +0100695 } else {
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200696 event = fanotify_alloc_path_event(path, &hash, gfp);
Jan Kara7088f352020-03-24 17:04:20 +0100697 }
698
Amir Goldstein9c61f3b2020-03-30 10:55:28 +0300699 if (!event)
700 goto out;
701
Amir Goldsteind0a6a872018-10-04 00:25:38 +0300702 if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200703 pid = get_pid(task_pid(current));
Amir Goldsteind0a6a872018-10-04 00:25:38 +0300704 else
Amir Goldstein7e3e5c62021-03-04 12:48:24 +0200705 pid = get_pid(task_tgid(current));
706
707 /* Mix event info, FAN_ONDIR flag and pid into event merge key */
708 hash ^= hash_long((unsigned long)pid | ondir, FANOTIFY_EVENT_HASH_BITS);
709 fanotify_init_event(event, hash, mask);
710 event->pid = pid;
Jan Kara7088f352020-03-24 17:04:20 +0100711
Shakeel Buttd46eb14b2018-08-17 15:46:39 -0700712out:
Roman Gushchinb87d8ce2020-10-17 16:13:40 -0700713 set_active_memcg(old_memcg);
Jan Karaf0834412014-04-03 14:46:33 -0700714 return event;
715}
716
Amir Goldstein77115222019-01-10 19:04:37 +0200717/*
718 * Get cached fsid of the filesystem containing the object from any connector.
719 * All connectors are supposed to have the same fsid, but we do not verify that
720 * here.
721 */
722static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
723{
724 int type;
725 __kernel_fsid_t fsid = {};
726
727 fsnotify_foreach_obj_type(type) {
Jan Karab1da6a52019-04-24 18:39:57 +0200728 struct fsnotify_mark_connector *conn;
729
Amir Goldstein77115222019-01-10 19:04:37 +0200730 if (!fsnotify_iter_should_report_type(iter_info, type))
731 continue;
732
Jan Karab1da6a52019-04-24 18:39:57 +0200733 conn = READ_ONCE(iter_info->marks[type]->connector);
734 /* Mark is just getting destroyed or created? */
735 if (!conn)
736 continue;
Amir Goldsteinc285a2f2019-06-19 13:34:44 +0300737 if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_FSID))
738 continue;
739 /* Pairs with smp_wmb() in fsnotify_add_mark_list() */
740 smp_rmb();
Jan Karab1da6a52019-04-24 18:39:57 +0200741 fsid = conn->fsid;
Amir Goldstein77115222019-01-10 19:04:37 +0200742 if (WARN_ON_ONCE(!fsid.val[0] && !fsid.val[1]))
743 continue;
744 return fsid;
745 }
746
747 return fsid;
748}
749
Amir Goldstein94e00d22021-03-04 12:48:25 +0200750/*
751 * Add an event to hash table for faster merge.
752 */
753static void fanotify_insert_event(struct fsnotify_group *group,
754 struct fsnotify_event *fsn_event)
755{
756 struct fanotify_event *event = FANOTIFY_E(fsn_event);
757 unsigned int bucket = fanotify_event_hash_bucket(group, event);
758 struct hlist_head *hlist = &group->fanotify_data.merge_hash[bucket];
759
760 assert_spin_locked(&group->notification_lock);
761
Gabriel Krisman Bertazicc53b552021-10-25 16:27:19 -0300762 if (!fanotify_is_hashed_event(event->mask))
763 return;
764
Amir Goldstein94e00d22021-03-04 12:48:25 +0200765 pr_debug("%s: group=%p event=%p bucket=%u\n", __func__,
766 group, event, bucket);
767
768 hlist_add_head(&event->merge_list, hlist);
769}
770
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300771static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
772 const void *data, int data_type,
773 struct inode *dir,
Al Viroe43e9c32019-04-26 13:51:03 -0400774 const struct qstr *file_name, u32 cookie,
Jan Kara9385a842016-11-10 17:51:50 +0100775 struct fsnotify_iter_info *iter_info)
Jan Kara7053aee2014-01-21 15:48:14 -0800776{
777 int ret = 0;
Amir Goldstein33913992019-01-10 19:04:32 +0200778 struct fanotify_event *event;
Jan Kara7053aee2014-01-21 15:48:14 -0800779 struct fsnotify_event *fsn_event;
Amir Goldstein77115222019-01-10 19:04:37 +0200780 __kernel_fsid_t fsid = {};
Jan Kara7053aee2014-01-21 15:48:14 -0800781
782 BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
783 BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
Amir Goldstein235328d2019-01-10 19:04:43 +0200784 BUILD_BUG_ON(FAN_ATTRIB != FS_ATTRIB);
Jan Kara7053aee2014-01-21 15:48:14 -0800785 BUILD_BUG_ON(FAN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
786 BUILD_BUG_ON(FAN_CLOSE_WRITE != FS_CLOSE_WRITE);
787 BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
Amir Goldstein235328d2019-01-10 19:04:43 +0200788 BUILD_BUG_ON(FAN_MOVED_TO != FS_MOVED_TO);
789 BUILD_BUG_ON(FAN_MOVED_FROM != FS_MOVED_FROM);
790 BUILD_BUG_ON(FAN_CREATE != FS_CREATE);
791 BUILD_BUG_ON(FAN_DELETE != FS_DELETE);
792 BUILD_BUG_ON(FAN_DELETE_SELF != FS_DELETE_SELF);
793 BUILD_BUG_ON(FAN_MOVE_SELF != FS_MOVE_SELF);
Jan Kara7053aee2014-01-21 15:48:14 -0800794 BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
795 BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
796 BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
797 BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
798 BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
Matthew Bobrowski9b076f12018-11-08 14:07:14 +1100799 BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC);
Matthew Bobrowski66917a32018-11-08 14:12:44 +1100800 BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM);
Gabriel Krisman Bertazi8d11a4f2021-10-25 16:27:33 -0300801 BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR);
Jan Kara7053aee2014-01-21 15:48:14 -0800802
Amir Goldsteinf1793692020-05-27 15:54:55 +0300803 BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19);
Amir Goldsteinbdd5a462018-10-04 00:25:37 +0300804
Amir Goldstein83b535d2019-01-10 19:04:42 +0200805 mask = fanotify_group_event_mask(group, iter_info, mask, data,
Amir Goldstein83b7a592020-07-16 11:42:26 +0300806 data_type, dir);
Matthew Bobrowski2d10b232018-11-08 14:05:49 +1100807 if (!mask)
Jan Kara83c4c4b2014-01-21 15:48:15 -0800808 return 0;
809
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300810 pr_debug("%s: group=%p mask=%x\n", __func__, group, mask);
Jan Kara7053aee2014-01-21 15:48:14 -0800811
Miklos Szeredi6685df32017-10-30 21:14:56 +0100812 if (fanotify_is_perm_event(mask)) {
Miklos Szeredif37650f2017-10-30 21:14:56 +0100813 /*
814 * fsnotify_prepare_user_wait() fails if we race with mark
815 * deletion. Just let the operation pass in that case.
816 */
817 if (!fsnotify_prepare_user_wait(iter_info))
818 return 0;
819 }
Miklos Szeredif37650f2017-10-30 21:14:56 +0100820
Amir Goldsteind809daf2020-07-16 11:42:12 +0300821 if (FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS)) {
Amir Goldstein77115222019-01-10 19:04:37 +0200822 fsid = fanotify_get_fsid(iter_info);
Jan Karab1da6a52019-04-24 18:39:57 +0200823 /* Racing with mark destruction or creation? */
824 if (!fsid.val[0] && !fsid.val[1])
825 return 0;
826 }
Amir Goldstein77115222019-01-10 19:04:37 +0200827
Amir Goldsteinb54cecf2020-06-07 12:10:40 +0300828 event = fanotify_alloc_event(group, mask, data, data_type, dir,
Amir Goldsteincacfb952020-03-19 17:10:21 +0200829 file_name, &fsid);
Miklos Szeredif37650f2017-10-30 21:14:56 +0100830 ret = -ENOMEM;
Jan Kara7b1f6412018-02-21 15:07:52 +0100831 if (unlikely(!event)) {
832 /*
833 * We don't queue overflow events for permission events as
834 * there the access is denied and so no event is in fact lost.
835 */
836 if (!fanotify_is_perm_event(mask))
837 fsnotify_queue_overflow(group);
Miklos Szeredif37650f2017-10-30 21:14:56 +0100838 goto finish;
Jan Kara7b1f6412018-02-21 15:07:52 +0100839 }
Jan Kara7053aee2014-01-21 15:48:14 -0800840
841 fsn_event = &event->fse;
Gabriel Krisman Bertazi1ad03c32021-10-25 16:27:24 -0300842 ret = fsnotify_insert_event(group, fsn_event, fanotify_merge,
843 fanotify_insert_event);
Jan Kara83c0e1b2014-01-28 18:53:22 +0100844 if (ret) {
Jan Kara482ef062014-02-21 19:07:54 +0100845 /* Permission events shouldn't be merged */
Amir Goldstein23c9dee2018-10-04 00:25:35 +0300846 BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS);
Jan Kara7053aee2014-01-21 15:48:14 -0800847 /* Our event wasn't used in the end. Free it. */
848 fsnotify_destroy_event(group, fsn_event);
Jan Kara482ef062014-02-21 19:07:54 +0100849
Miklos Szeredif37650f2017-10-30 21:14:56 +0100850 ret = 0;
Miklos Szeredi6685df32017-10-30 21:14:56 +0100851 } else if (fanotify_is_perm_event(mask)) {
Jan Kara7088f352020-03-24 17:04:20 +0100852 ret = fanotify_get_response(group, FANOTIFY_PERM(event),
Jan Kara05f0e382016-11-10 17:45:16 +0100853 iter_info);
Jan Kara85816792014-01-28 21:38:06 +0100854 }
Miklos Szeredif37650f2017-10-30 21:14:56 +0100855finish:
Miklos Szeredi6685df32017-10-30 21:14:56 +0100856 if (fanotify_is_perm_event(mask))
Miklos Szeredif37650f2017-10-30 21:14:56 +0100857 fsnotify_finish_user_wait(iter_info);
Miklos Szeredi6685df32017-10-30 21:14:56 +0100858
Jan Kara7053aee2014-01-21 15:48:14 -0800859 return ret;
860}
861
Eric Paris4afeff82010-10-28 17:21:58 -0400862static void fanotify_free_group_priv(struct fsnotify_group *group)
863{
Amir Goldstein94e00d22021-03-04 12:48:25 +0200864 kfree(group->fanotify_data.merge_hash);
Amir Goldstein5b8fea62021-03-04 13:29:20 +0200865 if (group->fanotify_data.ucounts)
866 dec_ucount(group->fanotify_data.ucounts,
867 UCOUNT_FANOTIFY_GROUPS);
Gabriel Krisman Bertazi734a1a52021-10-25 16:27:34 -0300868
869 if (mempool_initialized(&group->fanotify_data.error_events_pool))
870 mempool_exit(&group->fanotify_data.error_events_pool);
Eric Paris4afeff82010-10-28 17:21:58 -0400871}
872
Jan Kara7088f352020-03-24 17:04:20 +0100873static void fanotify_free_path_event(struct fanotify_event *event)
874{
875 path_put(fanotify_event_path(event));
876 kmem_cache_free(fanotify_path_event_cachep, FANOTIFY_PE(event));
877}
878
879static void fanotify_free_perm_event(struct fanotify_event *event)
880{
881 path_put(fanotify_event_path(event));
882 kmem_cache_free(fanotify_perm_event_cachep, FANOTIFY_PERM(event));
883}
884
885static void fanotify_free_fid_event(struct fanotify_event *event)
886{
887 struct fanotify_fid_event *ffe = FANOTIFY_FE(event);
888
889 if (fanotify_fh_has_ext_buf(&ffe->object_fh))
890 kfree(fanotify_fh_ext_buf(&ffe->object_fh));
891 kmem_cache_free(fanotify_fid_event_cachep, ffe);
892}
893
Amir Goldsteincacfb952020-03-19 17:10:21 +0200894static void fanotify_free_name_event(struct fanotify_event *event)
895{
Amir Goldsteinf35c4152020-07-16 11:42:18 +0300896 kfree(FANOTIFY_NE(event));
Amir Goldsteincacfb952020-03-19 17:10:21 +0200897}
898
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300899static void fanotify_free_error_event(struct fsnotify_group *group,
900 struct fanotify_event *event)
901{
902 struct fanotify_error_event *fee = FANOTIFY_EE(event);
903
904 mempool_free(fee, &group->fanotify_data.error_events_pool);
905}
906
Gabriel Krisman Bertazi330ae772021-10-25 16:27:27 -0300907static void fanotify_free_event(struct fsnotify_group *group,
908 struct fsnotify_event *fsn_event)
Jan Kara7053aee2014-01-21 15:48:14 -0800909{
Amir Goldstein33913992019-01-10 19:04:32 +0200910 struct fanotify_event *event;
Jan Kara7053aee2014-01-21 15:48:14 -0800911
912 event = FANOTIFY_E(fsn_event);
Amir Goldsteind0a6a872018-10-04 00:25:38 +0300913 put_pid(event->pid);
Jan Kara7088f352020-03-24 17:04:20 +0100914 switch (event->type) {
915 case FANOTIFY_EVENT_TYPE_PATH:
916 fanotify_free_path_event(event);
917 break;
918 case FANOTIFY_EVENT_TYPE_PATH_PERM:
919 fanotify_free_perm_event(event);
920 break;
921 case FANOTIFY_EVENT_TYPE_FID:
922 fanotify_free_fid_event(event);
923 break;
Amir Goldsteincacfb952020-03-19 17:10:21 +0200924 case FANOTIFY_EVENT_TYPE_FID_NAME:
925 fanotify_free_name_event(event);
926 break;
Amir Goldsteinb8a6c3a2020-07-08 14:11:42 +0300927 case FANOTIFY_EVENT_TYPE_OVERFLOW:
928 kfree(event);
929 break;
Gabriel Krisman Bertazi83e9acb2021-10-25 16:27:35 -0300930 case FANOTIFY_EVENT_TYPE_FS_ERROR:
931 fanotify_free_error_event(group, event);
932 break;
Jan Kara7088f352020-03-24 17:04:20 +0100933 default:
934 WARN_ON_ONCE(1);
Jan Karaf0834412014-04-03 14:46:33 -0700935 }
Jan Kara7053aee2014-01-21 15:48:14 -0800936}
937
Amir Goldstein5b8fea62021-03-04 13:29:20 +0200938static void fanotify_freeing_mark(struct fsnotify_mark *mark,
939 struct fsnotify_group *group)
940{
941 if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS))
942 dec_ucount(group->fanotify_data.ucounts, UCOUNT_FANOTIFY_MARKS);
943}
944
Jan Kara054c6362016-12-21 18:06:12 +0100945static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
946{
947 kmem_cache_free(fanotify_mark_cache, fsn_mark);
948}
949
Eric Parisff0b16a2009-12-17 21:24:25 -0500950const struct fsnotify_ops fanotify_fsnotify_ops = {
951 .handle_event = fanotify_handle_event,
Eric Paris4afeff82010-10-28 17:21:58 -0400952 .free_group_priv = fanotify_free_group_priv,
Jan Kara7053aee2014-01-21 15:48:14 -0800953 .free_event = fanotify_free_event,
Amir Goldstein5b8fea62021-03-04 13:29:20 +0200954 .freeing_mark = fanotify_freeing_mark,
Jan Kara054c6362016-12-21 18:06:12 +0100955 .free_mark = fanotify_free_mark,
Eric Parisff0b16a2009-12-17 21:24:25 -0500956};