fanotify: convert fanotify_init() to FD_PREPARE()

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 [1]
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>
This commit is contained in:
Christian Brauner
2025-11-23 17:33:26 +01:00
parent 05885f4165
commit 7129098f4f

View 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;
return -EPERM;
}
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;
}
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;
}