.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * fs/inotify_user.c - inotify support for userspace |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * |
---|
11 | 12 | * Copyright (C) 2009 Eric Paris <Red Hat Inc> |
---|
12 | 13 | * inotify was largely rewriten to make use of the fsnotify infrastructure |
---|
13 | | - * |
---|
14 | | - * This program is free software; you can redistribute it and/or modify it |
---|
15 | | - * under the terms of the GNU General Public License as published by the |
---|
16 | | - * Free Software Foundation; either version 2, or (at your option) any |
---|
17 | | - * later version. |
---|
18 | | - * |
---|
19 | | - * This program is distributed in the hope that it will be useful, but |
---|
20 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
21 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
22 | | - * General Public License for more details. |
---|
23 | 14 | */ |
---|
24 | 15 | |
---|
25 | 16 | #include <linux/file.h> |
---|
.. | .. |
---|
39 | 30 | #include <linux/poll.h> |
---|
40 | 31 | #include <linux/wait.h> |
---|
41 | 32 | #include <linux/memcontrol.h> |
---|
| 33 | +#include <linux/security.h> |
---|
42 | 34 | |
---|
43 | 35 | #include "inotify.h" |
---|
44 | 36 | #include "../fdinfo.h" |
---|
.. | .. |
---|
54 | 46 | |
---|
55 | 47 | #include <linux/sysctl.h> |
---|
56 | 48 | |
---|
57 | | -static int zero; |
---|
58 | | - |
---|
59 | 49 | struct ctl_table inotify_table[] = { |
---|
60 | 50 | { |
---|
61 | 51 | .procname = "max_user_instances", |
---|
.. | .. |
---|
63 | 53 | .maxlen = sizeof(int), |
---|
64 | 54 | .mode = 0644, |
---|
65 | 55 | .proc_handler = proc_dointvec_minmax, |
---|
66 | | - .extra1 = &zero, |
---|
| 56 | + .extra1 = SYSCTL_ZERO, |
---|
67 | 57 | }, |
---|
68 | 58 | { |
---|
69 | 59 | .procname = "max_user_watches", |
---|
.. | .. |
---|
71 | 61 | .maxlen = sizeof(int), |
---|
72 | 62 | .mode = 0644, |
---|
73 | 63 | .proc_handler = proc_dointvec_minmax, |
---|
74 | | - .extra1 = &zero, |
---|
| 64 | + .extra1 = SYSCTL_ZERO, |
---|
75 | 65 | }, |
---|
76 | 66 | { |
---|
77 | 67 | .procname = "max_queued_events", |
---|
.. | .. |
---|
79 | 69 | .maxlen = sizeof(int), |
---|
80 | 70 | .mode = 0644, |
---|
81 | 71 | .proc_handler = proc_dointvec_minmax, |
---|
82 | | - .extra1 = &zero |
---|
| 72 | + .extra1 = SYSCTL_ZERO |
---|
83 | 73 | }, |
---|
84 | 74 | { } |
---|
85 | 75 | }; |
---|
86 | 76 | #endif /* CONFIG_SYSCTL */ |
---|
87 | 77 | |
---|
88 | | -static inline __u32 inotify_arg_to_mask(u32 arg) |
---|
| 78 | +static inline __u32 inotify_arg_to_mask(struct inode *inode, u32 arg) |
---|
89 | 79 | { |
---|
90 | 80 | __u32 mask; |
---|
91 | 81 | |
---|
92 | 82 | /* |
---|
93 | | - * everything should accept their own ignored, cares about children, |
---|
94 | | - * and should receive events when the inode is unmounted |
---|
| 83 | + * Everything should accept their own ignored and should receive events |
---|
| 84 | + * when the inode is unmounted. All directories care about children. |
---|
95 | 85 | */ |
---|
96 | | - mask = (FS_IN_IGNORED | FS_EVENT_ON_CHILD | FS_UNMOUNT); |
---|
| 86 | + mask = (FS_IN_IGNORED | FS_UNMOUNT); |
---|
| 87 | + if (S_ISDIR(inode->i_mode)) |
---|
| 88 | + mask |= FS_EVENT_ON_CHILD; |
---|
97 | 89 | |
---|
98 | 90 | /* mask off the flags used to open the fd */ |
---|
99 | | - mask |= (arg & (IN_ALL_EVENTS | IN_ONESHOT | IN_EXCL_UNLINK)); |
---|
| 91 | + mask |= (arg & INOTIFY_USER_MASK); |
---|
100 | 92 | |
---|
101 | 93 | return mask; |
---|
102 | 94 | } |
---|
.. | .. |
---|
189 | 181 | */ |
---|
190 | 182 | pad_name_len = round_event_name_len(fsn_event); |
---|
191 | 183 | inotify_event.len = pad_name_len; |
---|
192 | | - inotify_event.mask = inotify_mask_to_arg(fsn_event->mask); |
---|
| 184 | + inotify_event.mask = inotify_mask_to_arg(event->mask); |
---|
193 | 185 | inotify_event.wd = event->wd; |
---|
194 | 186 | inotify_event.cookie = event->sync_cookie; |
---|
195 | 187 | |
---|
.. | .. |
---|
342 | 334 | /* |
---|
343 | 335 | * find_inode - resolve a user-given path to a specific inode |
---|
344 | 336 | */ |
---|
345 | | -static int inotify_find_inode(const char __user *dirname, struct path *path, unsigned flags) |
---|
| 337 | +static int inotify_find_inode(const char __user *dirname, struct path *path, |
---|
| 338 | + unsigned int flags, __u64 mask) |
---|
346 | 339 | { |
---|
347 | 340 | int error; |
---|
348 | 341 | |
---|
.. | .. |
---|
350 | 343 | if (error) |
---|
351 | 344 | return error; |
---|
352 | 345 | /* you can only watch an inode if you have read permissions on it */ |
---|
353 | | - error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ); |
---|
| 346 | + error = inode_permission(path->dentry->d_inode, MAY_READ); |
---|
| 347 | + if (error) { |
---|
| 348 | + path_put(path); |
---|
| 349 | + return error; |
---|
| 350 | + } |
---|
| 351 | + error = security_path_notify(path, mask, |
---|
| 352 | + FSNOTIFY_OBJ_TYPE_INODE); |
---|
354 | 353 | if (error) |
---|
355 | 354 | path_put(path); |
---|
| 355 | + |
---|
356 | 356 | return error; |
---|
357 | 357 | } |
---|
358 | 358 | |
---|
.. | .. |
---|
486 | 486 | struct fsnotify_group *group) |
---|
487 | 487 | { |
---|
488 | 488 | struct inotify_inode_mark *i_mark; |
---|
489 | | - struct fsnotify_iter_info iter_info = { }; |
---|
490 | | - |
---|
491 | | - fsnotify_iter_set_report_type_mark(&iter_info, FSNOTIFY_OBJ_TYPE_INODE, |
---|
492 | | - fsn_mark); |
---|
493 | 489 | |
---|
494 | 490 | /* Queue ignore event for the watch */ |
---|
495 | | - inotify_handle_event(group, NULL, FS_IN_IGNORED, NULL, |
---|
496 | | - FSNOTIFY_EVENT_NONE, NULL, 0, &iter_info); |
---|
| 491 | + inotify_handle_inode_event(fsn_mark, FS_IN_IGNORED, NULL, NULL, NULL, |
---|
| 492 | + 0); |
---|
497 | 493 | |
---|
498 | 494 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); |
---|
499 | 495 | /* remove this mark from the idr */ |
---|
.. | .. |
---|
514 | 510 | int create = (arg & IN_MASK_CREATE); |
---|
515 | 511 | int ret; |
---|
516 | 512 | |
---|
517 | | - mask = inotify_arg_to_mask(arg); |
---|
| 513 | + mask = inotify_arg_to_mask(inode, arg); |
---|
518 | 514 | |
---|
519 | 515 | fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); |
---|
520 | 516 | if (!fsn_mark) |
---|
.. | .. |
---|
567 | 563 | struct idr *idr = &group->inotify_data.idr; |
---|
568 | 564 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; |
---|
569 | 565 | |
---|
570 | | - mask = inotify_arg_to_mask(arg); |
---|
| 566 | + mask = inotify_arg_to_mask(inode, arg); |
---|
571 | 567 | |
---|
572 | 568 | tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); |
---|
573 | 569 | if (unlikely(!tmp_i_mark)) |
---|
.. | .. |
---|
637 | 633 | return ERR_PTR(-ENOMEM); |
---|
638 | 634 | } |
---|
639 | 635 | group->overflow_event = &oevent->fse; |
---|
640 | | - fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW); |
---|
| 636 | + fsnotify_init_event(group->overflow_event, 0); |
---|
| 637 | + oevent->mask = FS_Q_OVERFLOW; |
---|
641 | 638 | oevent->wd = -1; |
---|
642 | 639 | oevent->sync_cookie = 0; |
---|
643 | 640 | oevent->name_len = 0; |
---|
.. | .. |
---|
745 | 742 | if (mask & IN_ONLYDIR) |
---|
746 | 743 | flags |= LOOKUP_DIRECTORY; |
---|
747 | 744 | |
---|
748 | | - ret = inotify_find_inode(pathname, &path, flags); |
---|
| 745 | + ret = inotify_find_inode(pathname, &path, flags, |
---|
| 746 | + (mask & IN_ALL_EVENTS)); |
---|
749 | 747 | if (ret) |
---|
750 | 748 | goto fput_and_out; |
---|
751 | 749 | |
---|
.. | .. |
---|
776 | 774 | struct fsnotify_group *group; |
---|
777 | 775 | struct inotify_inode_mark *i_mark; |
---|
778 | 776 | struct fd f; |
---|
779 | | - int ret = 0; |
---|
| 777 | + int ret = -EINVAL; |
---|
780 | 778 | |
---|
781 | 779 | f = fdget(fd); |
---|
782 | 780 | if (unlikely(!f.file)) |
---|
783 | 781 | return -EBADF; |
---|
784 | 782 | |
---|
785 | 783 | /* verify that this is indeed an inotify instance */ |
---|
786 | | - ret = -EINVAL; |
---|
787 | 784 | if (unlikely(f.file->f_op != &inotify_fops)) |
---|
788 | 785 | goto out; |
---|
789 | 786 | |
---|
790 | 787 | group = f.file->private_data; |
---|
791 | 788 | |
---|
792 | | - ret = -EINVAL; |
---|
793 | 789 | i_mark = inotify_idr_find(group, wd); |
---|
794 | 790 | if (unlikely(!i_mark)) |
---|
795 | 791 | goto out; |
---|
.. | .. |
---|
832 | 828 | BUILD_BUG_ON(IN_ISDIR != FS_ISDIR); |
---|
833 | 829 | BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); |
---|
834 | 830 | |
---|
835 | | - BUG_ON(hweight32(ALL_INOTIFY_BITS) != 22); |
---|
| 831 | + BUILD_BUG_ON(HWEIGHT32(ALL_INOTIFY_BITS) != 22); |
---|
836 | 832 | |
---|
837 | 833 | inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, |
---|
838 | 834 | SLAB_PANIC|SLAB_ACCOUNT); |
---|