]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fanotify: convert fanotify_init() to FD_PREPARE()
authorChristian Brauner <brauner@kernel.org>
Sun, 23 Nov 2025 16:33:26 +0000 (17:33 +0100)
committerChristian Brauner <brauner@kernel.org>
Fri, 28 Nov 2025 11:42:31 +0000 (12:42 +0100)
Christian Brauner <brauner@kernel.org> says:

The fix sent in [1] was squashed into this commit.

Link: https://lore.kernel.org/20251127201618.2115275-1-kuniyu@google.com
Reported-by: syzbot+321168dfa622eda99689@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/lkml/6928b121.a70a0220.d98e3.0110.GAE@google.com
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20251123-work-fd-prepare-v4-8-b6efa1706cfd@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/notify/fanotify/fanotify_user.c

index 1dadda82cae51e31318c988d26bd5e5e3a87cf33..d0b9b984002feb001dd186a8dc039cb47ba32f89 100644 (file)
@@ -1597,16 +1597,20 @@ static struct hlist_head *fanotify_alloc_merge_hash(void)
        return hash;
 }
 
+DEFINE_CLASS(fsnotify_group,
+            struct fsnotify_group *,
+            if (!IS_ERR_OR_NULL(_T)) fsnotify_destroy_group(_T),
+            fsnotify_alloc_group(ops, flags),
+            const struct fsnotify_ops *ops, int flags)
+
 /* fanotify syscalls */
 SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 {
        struct user_namespace *user_ns = current_user_ns();
-       struct fsnotify_group *group;
        int f_flags, fd;
        unsigned int fid_mode = flags & FANOTIFY_FID_BITS;
        unsigned int class = flags & FANOTIFY_CLASS_BITS;
        unsigned int internal_flags = 0;
-       struct file *file;
 
        pr_debug("%s: flags=%x event_f_flags=%x\n",
                 __func__, flags, event_f_flags);
@@ -1690,36 +1694,29 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        if (flags & FAN_NONBLOCK)
                f_flags |= O_NONBLOCK;
 
-       /* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
-       group = fsnotify_alloc_group(&fanotify_fsnotify_ops,
+       CLASS(fsnotify_group, group)(&fanotify_fsnotify_ops,
                                     FSNOTIFY_GROUP_USER);
-       if (IS_ERR(group)) {
+       /* fsnotify_alloc_group takes a ref.  Dropped in fanotify_release */
+       if (IS_ERR(group))
                return PTR_ERR(group);
-       }
 
        /* Enforce groups limits per user in all containing user ns */
        group->fanotify_data.ucounts = inc_ucount(user_ns, current_euid(),
                                                  UCOUNT_FANOTIFY_GROUPS);
-       if (!group->fanotify_data.ucounts) {
-               fd = -EMFILE;
-               goto out_destroy_group;
-       }
+       if (!group->fanotify_data.ucounts)
+               return -EMFILE;
 
        group->fanotify_data.flags = flags | internal_flags;
        group->memcg = get_mem_cgroup_from_mm(current->mm);
        group->user_ns = get_user_ns(user_ns);
 
        group->fanotify_data.merge_hash = fanotify_alloc_merge_hash();
-       if (!group->fanotify_data.merge_hash) {
-               fd = -ENOMEM;
-               goto out_destroy_group;
-       }
+       if (!group->fanotify_data.merge_hash)
+               return -ENOMEM;
 
        group->overflow_event = fanotify_alloc_overflow_event();
-       if (unlikely(!group->overflow_event)) {
-               fd = -ENOMEM;
-               goto out_destroy_group;
-       }
+       if (unlikely(!group->overflow_event))
+               return -ENOMEM;
 
        if (force_o_largefile())
                event_f_flags |= O_LARGEFILE;
@@ -1738,8 +1735,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
                group->priority = FSNOTIFY_PRIO_PRE_CONTENT;
                break;
        default:
-               fd = -EINVAL;
-               goto out_destroy_group;
+               return -EINVAL;
        }
 
        BUILD_BUG_ON(!(FANOTIFY_ADMIN_INIT_FLAGS & FAN_UNLIMITED_QUEUE));
@@ -1750,27 +1746,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
        }
 
        if (flags & FAN_ENABLE_AUDIT) {
-               fd = -EPERM;
                if (!capable(CAP_AUDIT_WRITE))
-                       goto out_destroy_group;
-       }
-
-       fd = get_unused_fd_flags(f_flags);
-       if (fd < 0)
-               goto out_destroy_group;
-
-       file = anon_inode_getfile_fmode("[fanotify]", &fanotify_fops, group,
-                                       f_flags, FMODE_NONOTIFY);
-       if (IS_ERR(file)) {
-               put_unused_fd(fd);
-               fd = PTR_ERR(file);
-               goto out_destroy_group;
+                       return -EPERM;
        }
-       fd_install(fd, file);
-       return fd;
 
-out_destroy_group:
-       fsnotify_destroy_group(group);
+       fd = FD_ADD(f_flags,
+                   anon_inode_getfile_fmode("[fanotify]", &fanotify_fops,
+                                            group, f_flags, FMODE_NONOTIFY));
+       if (fd >= 0)
+               retain_and_null_ptr(group);
        return fd;
 }