mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
fanotify: allow reporting pidfds for reaped tasks
Fanotify used to refuse to report pidfds for reaped tasks by applying a pid_has_task() check before calling pidfd_prepare(). This prevented userspace from obtaining information about the task. Register the event pid with pidfs when creating the fanotify event if pidfd reporting was requested, so pidfd_prepare() can later create a pidfd for the reaped task. Suggested-by: Christian Brauner <brauner@kernel.org> Link: https://lore.kernel.org/linux-fsdevel/20260528-schmuckvoll-heilen-garen-be77b4208671@brauner/ Signed-off-by: AnonymeMeow <anonymemeow@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org> Link: https://patch.msgid.link/20260607003343.425939-3-anonymemeow@gmail.com Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/statfs.h>
|
||||
#include <linux/stringhash.h>
|
||||
#include <linux/pidfs.h>
|
||||
|
||||
#include "fanotify.h"
|
||||
|
||||
@@ -839,6 +840,15 @@ static struct fanotify_event *fanotify_alloc_event(
|
||||
/* Whoever is interested in the event, pays for the allocation. */
|
||||
old_memcg = set_active_memcg(group->memcg);
|
||||
|
||||
if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
|
||||
pid = task_pid(current);
|
||||
else
|
||||
pid = task_tgid(current);
|
||||
|
||||
if (FAN_GROUP_FLAG(group, FAN_REPORT_PIDFD) &&
|
||||
pidfs_register_pid_gfp(pid, gfp))
|
||||
goto out;
|
||||
|
||||
if (fanotify_is_perm_event(mask)) {
|
||||
event = fanotify_alloc_perm_event(data, data_type, gfp);
|
||||
} else if (fanotify_is_error_event(mask)) {
|
||||
@@ -860,15 +870,10 @@ static struct fanotify_event *fanotify_alloc_event(
|
||||
if (!event)
|
||||
goto out;
|
||||
|
||||
if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
|
||||
pid = get_pid(task_pid(current));
|
||||
else
|
||||
pid = get_pid(task_tgid(current));
|
||||
|
||||
/* Mix event info, FAN_ONDIR flag and pid into event merge key */
|
||||
hash ^= hash_long((unsigned long)pid | ondir, FANOTIFY_EVENT_HASH_BITS);
|
||||
fanotify_init_event(event, hash, mask);
|
||||
event->pid = pid;
|
||||
event->pid = get_pid(pid);
|
||||
|
||||
out:
|
||||
set_active_memcg(old_memcg);
|
||||
|
||||
@@ -904,20 +904,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
||||
metadata.fd = fd >= 0 ? fd : FAN_NOFD;
|
||||
|
||||
if (pidfd_mode) {
|
||||
unsigned int tid_mode = FAN_GROUP_FLAG(group, FAN_REPORT_TID);
|
||||
enum pid_type pidtype = tid_mode ? PIDTYPE_PID : PIDTYPE_TGID;
|
||||
unsigned int pidfd_flags = tid_mode ? PIDFD_THREAD : 0;
|
||||
unsigned int pidfd_flags = PIDFD_STALE;
|
||||
|
||||
/*
|
||||
* The pid_has_task() check for an event->pid is performed
|
||||
* preemptively in an attempt to catch out cases where the event
|
||||
* listener reads events after the event generating task has
|
||||
* already terminated. Depending on flag FAN_REPORT_FD_ERROR,
|
||||
* report either -ESRCH or FAN_NOPIDFD to the event listener in
|
||||
* those cases with all other pidfd creation errors reported as
|
||||
* the error code itself or as FAN_EPIDFD.
|
||||
*/
|
||||
if (metadata.pid && pid_has_task(event->pid, pidtype))
|
||||
if (FAN_GROUP_FLAG(group, FAN_REPORT_TID))
|
||||
pidfd_flags |= PIDFD_THREAD;
|
||||
|
||||
if (metadata.pid)
|
||||
pidfd = pidfd_prepare(event->pid, pidfd_flags, &pidfd_file);
|
||||
|
||||
if (!FAN_GROUP_FLAG(group, FAN_REPORT_FD_ERROR) && pidfd < 0)
|
||||
|
||||
10
fs/pidfs.c
10
fs/pidfs.c
@@ -991,14 +991,16 @@ static void pidfs_put_data(void *data)
|
||||
}
|
||||
|
||||
/**
|
||||
* pidfs_register_pid - register a struct pid in pidfs
|
||||
* pidfs_register_pid_gfp - register a struct pid in pidfs with custom GFP
|
||||
* flags
|
||||
* @pid: pid to pin
|
||||
* @gfp: GFP flags for memory allocation
|
||||
*
|
||||
* Register a struct pid in pidfs.
|
||||
* Register a struct pid in pidfs with custom GFP flags.
|
||||
*
|
||||
* Return: On success zero, on error a negative error code is returned.
|
||||
*/
|
||||
int pidfs_register_pid(struct pid *pid)
|
||||
int pidfs_register_pid_gfp(struct pid *pid, gfp_t gfp)
|
||||
{
|
||||
struct pidfs_attr *new_attr __free(kfree) = NULL;
|
||||
struct pidfs_attr *attr;
|
||||
@@ -1014,7 +1016,7 @@ int pidfs_register_pid(struct pid *pid)
|
||||
if (attr)
|
||||
return 0;
|
||||
|
||||
new_attr = kmem_cache_zalloc(pidfs_attr_cachep, GFP_KERNEL);
|
||||
new_attr = kmem_cache_zalloc(pidfs_attr_cachep, gfp);
|
||||
if (!new_attr)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#ifndef _LINUX_PID_FS_H
|
||||
#define _LINUX_PID_FS_H
|
||||
|
||||
#include <linux/gfp_types.h>
|
||||
|
||||
struct coredump_params;
|
||||
|
||||
struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags);
|
||||
@@ -14,7 +16,21 @@ void pidfs_exit(struct task_struct *tsk);
|
||||
void pidfs_coredump(const struct coredump_params *cprm);
|
||||
#endif
|
||||
extern const struct dentry_operations pidfs_dentry_operations;
|
||||
int pidfs_register_pid(struct pid *pid);
|
||||
int pidfs_register_pid_gfp(struct pid *pid, gfp_t gfp);
|
||||
|
||||
/**
|
||||
* pidfs_register_pid - register a struct pid in pidfs
|
||||
* @pid: pid to pin
|
||||
*
|
||||
* Register a struct pid in pidfs.
|
||||
*
|
||||
* Return: On success zero, on error a negative error code is returned.
|
||||
*/
|
||||
static inline int pidfs_register_pid(struct pid *pid)
|
||||
{
|
||||
return pidfs_register_pid_gfp(pid, GFP_KERNEL);
|
||||
}
|
||||
|
||||
void pidfs_free_pid(struct pid *pid);
|
||||
|
||||
#endif /* _LINUX_PID_FS_H */
|
||||
|
||||
Reference in New Issue
Block a user