|
17 | 17 | #include <linux/compat.h>
|
18 | 18 | #include <linux/sched/signal.h>
|
19 | 19 | #include <linux/memcontrol.h>
|
| 20 | +#include <linux/statfs.h> |
| 21 | +#include <linux/exportfs.h> |
20 | 22 |
|
21 | 23 | #include <asm/ioctls.h>
|
22 | 24 |
|
@@ -768,6 +770,10 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
768 | 770 | return -EINVAL;
|
769 | 771 | }
|
770 | 772 |
|
| 773 | + if ((flags & FAN_REPORT_FID) && |
| 774 | + (flags & FANOTIFY_CLASS_BITS) != FAN_CLASS_NOTIF) |
| 775 | + return -EINVAL; |
| 776 | + |
771 | 777 | user = get_current_user();
|
772 | 778 | if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) {
|
773 | 779 | free_uid(user);
|
@@ -854,6 +860,52 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
|
854 | 860 | return fd;
|
855 | 861 | }
|
856 | 862 |
|
| 863 | +/* Check if filesystem can encode a unique fid */ |
| 864 | +static int fanotify_test_fid(struct path *path) |
| 865 | +{ |
| 866 | + struct kstatfs stat, root_stat; |
| 867 | + struct path root = { |
| 868 | + .mnt = path->mnt, |
| 869 | + .dentry = path->dentry->d_sb->s_root, |
| 870 | + }; |
| 871 | + int err; |
| 872 | + |
| 873 | + /* |
| 874 | + * Make sure path is not in filesystem with zero fsid (e.g. tmpfs). |
| 875 | + */ |
| 876 | + err = vfs_statfs(path, &stat); |
| 877 | + if (err) |
| 878 | + return err; |
| 879 | + |
| 880 | + if (!stat.f_fsid.val[0] && !stat.f_fsid.val[1]) |
| 881 | + return -ENODEV; |
| 882 | + |
| 883 | + /* |
| 884 | + * Make sure path is not inside a filesystem subvolume (e.g. btrfs) |
| 885 | + * which uses a different fsid than sb root. |
| 886 | + */ |
| 887 | + err = vfs_statfs(&root, &root_stat); |
| 888 | + if (err) |
| 889 | + return err; |
| 890 | + |
| 891 | + if (root_stat.f_fsid.val[0] != stat.f_fsid.val[0] || |
| 892 | + root_stat.f_fsid.val[1] != stat.f_fsid.val[1]) |
| 893 | + return -EXDEV; |
| 894 | + |
| 895 | + /* |
| 896 | + * We need to make sure that the file system supports at least |
| 897 | + * encoding a file handle so user can use name_to_handle_at() to |
| 898 | + * compare fid returned with event to the file handle of watched |
| 899 | + * objects. However, name_to_handle_at() requires that the |
| 900 | + * filesystem also supports decoding file handles. |
| 901 | + */ |
| 902 | + if (!path->dentry->d_sb->s_export_op || |
| 903 | + !path->dentry->d_sb->s_export_op->fh_to_dentry) |
| 904 | + return -EOPNOTSUPP; |
| 905 | + |
| 906 | + return 0; |
| 907 | +} |
| 908 | + |
857 | 909 | static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
858 | 910 | int dfd, const char __user *pathname)
|
859 | 911 | {
|
@@ -939,6 +991,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
939 | 991 | if (ret)
|
940 | 992 | goto fput_and_out;
|
941 | 993 |
|
| 994 | + if (FAN_GROUP_FLAG(group, FAN_REPORT_FID)) { |
| 995 | + ret = fanotify_test_fid(&path); |
| 996 | + if (ret) |
| 997 | + goto path_put_and_out; |
| 998 | + } |
| 999 | + |
942 | 1000 | /* inode held in place by reference to path; group by fget on fd */
|
943 | 1001 | if (mark_type == FAN_MARK_INODE)
|
944 | 1002 | inode = path.dentry->d_inode;
|
@@ -967,6 +1025,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
|
967 | 1025 | ret = -EINVAL;
|
968 | 1026 | }
|
969 | 1027 |
|
| 1028 | +path_put_and_out: |
970 | 1029 | path_put(&path);
|
971 | 1030 | fput_and_out:
|
972 | 1031 | fdput(f);
|
@@ -1003,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
|
1003 | 1062 | */
|
1004 | 1063 | static int __init fanotify_user_setup(void)
|
1005 | 1064 | {
|
1006 |
| - BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 7); |
| 1065 | + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 8); |
1007 | 1066 | BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9);
|
1008 | 1067 |
|
1009 | 1068 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
|
|
0 commit comments