| .. | .. |
|---|
| 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); |
|---|