pidfd: add PIDFD_SELF* sentinels to refer to own thread/process

It is useful to be able to utilise the pidfd mechanism to reference the
current thread or process (from a userland point of view - thread group
leader from the kernel's point of view).

Therefore introduce PIDFD_SELF_THREAD to refer to the current thread, and
PIDFD_SELF_THREAD_GROUP to refer to the current thread group leader.

For convenience and to avoid confusion from userland's perspective we alias
these:

* PIDFD_SELF is an alias for PIDFD_SELF_THREAD - This is nearly always what
  the user will want to use, as they would find it surprising if for
  instance fd's were unshared()'d and they wanted to invoke pidfd_getfd()
  and that failed.

* PIDFD_SELF_PROCESS is an alias for PIDFD_SELF_THREAD_GROUP - Most users
  have no concept of thread groups or what a thread group leader is, and
  from userland's perspective and nomenclature this is what userland
  considers to be a process.

We adjust pidfd_get_task() and the pidfd_send_signal() system call with
specific handling for this, implementing this functionality for
process_madvise(), process_mrelease() (albeit, using it here wouldn't
really make sense) and pidfd_send_signal().

Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Link: https://lore.kernel.org/r/24315a16a3d01a548dd45c7515f7d51c767e954e.1738268370.git.lorenzo.stoakes@oracle.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Lorenzo Stoakes 2025-01-30 20:40:26 +00:00 committed by Christian Brauner
parent 2014c95afe
commit f08d0c3a71
No known key found for this signature in database
GPG Key ID: 91C61BC06578DCA2
3 changed files with 112 additions and 53 deletions

View File

@ -23,6 +23,30 @@
#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */
/*
* The concept of process and threads in userland and the kernel is a confusing
* one - within the kernel every thread is a 'task' with its own individual PID,
* however from userland's point of view threads are grouped by a single PID,
* which is that of the 'thread group leader', typically the first thread
* spawned.
*
* To cut the Gideon knot, for internal kernel usage, we refer to
* PIDFD_SELF_THREAD to refer to the current thread (or task from a kernel
* perspective), and PIDFD_SELF_THREAD_GROUP to refer to the current thread
* group leader...
*/
#define PIDFD_SELF_THREAD -10000 /* Current thread. */
#define PIDFD_SELF_THREAD_GROUP -20000 /* Current thread group leader. */
/*
* ...and for userland we make life simpler - PIDFD_SELF refers to the current
* thread, PIDFD_SELF_PROCESS refers to the process thread group leader.
*
* For nearly all practical uses, a user will want to use PIDFD_SELF.
*/
#define PIDFD_SELF PIDFD_SELF_THREAD
#define PIDFD_SELF_PROCESS PIDFD_SELF_THREAD_GROUP
struct pidfd_info {
/*
* This mask is similar to the request_mask in statx(2).

View File

@ -564,15 +564,29 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags)
*/
struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
{
unsigned int f_flags;
unsigned int f_flags = 0;
struct pid *pid;
struct task_struct *task;
enum pid_type type;
pid = pidfd_get_pid(pidfd, &f_flags);
if (IS_ERR(pid))
return ERR_CAST(pid);
switch (pidfd) {
case PIDFD_SELF_THREAD:
type = PIDTYPE_PID;
pid = get_task_pid(current, type);
break;
case PIDFD_SELF_THREAD_GROUP:
type = PIDTYPE_TGID;
pid = get_task_pid(current, type);
break;
default:
pid = pidfd_get_pid(pidfd, &f_flags);
if (IS_ERR(pid))
return ERR_CAST(pid);
type = PIDTYPE_TGID;
break;
}
task = get_pid_task(pid, PIDTYPE_TGID);
task = get_pid_task(pid, type);
put_pid(pid);
if (!task)
return ERR_PTR(-ESRCH);

View File

@ -4009,56 +4009,12 @@ static struct pid *pidfd_to_pid(const struct file *file)
(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \
PIDFD_SIGNAL_PROCESS_GROUP)
/**
* sys_pidfd_send_signal - Signal a process through a pidfd
* @pidfd: file descriptor of the process
* @sig: signal to send
* @info: signal info
* @flags: future flags
*
* Send the signal to the thread group or to the individual thread depending
* on PIDFD_THREAD.
* In the future extension to @flags may be used to override the default scope
* of @pidfd.
*
* Return: 0 on success, negative errno on failure
*/
SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
siginfo_t __user *, info, unsigned int, flags)
static int do_pidfd_send_signal(struct pid *pid, int sig, enum pid_type type,
siginfo_t __user *info, unsigned int flags)
{
int ret;
struct pid *pid;
kernel_siginfo_t kinfo;
enum pid_type type;
/* Enforce flags be set to 0 until we add an extension. */
if (flags & ~PIDFD_SEND_SIGNAL_FLAGS)
return -EINVAL;
/* Ensure that only a single signal scope determining flag is set. */
if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
return -EINVAL;
CLASS(fd, f)(pidfd);
if (fd_empty(f))
return -EBADF;
/* Is this a pidfd? */
pid = pidfd_to_pid(fd_file(f));
if (IS_ERR(pid))
return PTR_ERR(pid);
if (!access_pidfd_pidns(pid))
return -EINVAL;
switch (flags) {
case 0:
/* Infer scope from the type of pidfd. */
if (fd_file(f)->f_flags & PIDFD_THREAD)
type = PIDTYPE_PID;
else
type = PIDTYPE_TGID;
break;
case PIDFD_SIGNAL_THREAD:
type = PIDTYPE_PID;
break;
@ -4071,6 +4027,8 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
}
if (info) {
int ret;
ret = copy_siginfo_from_user_any(&kinfo, info);
if (unlikely(ret))
return ret;
@ -4088,8 +4046,71 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
if (type == PIDTYPE_PGID)
return kill_pgrp_info(sig, &kinfo, pid);
else
return kill_pid_info_type(sig, &kinfo, pid, type);
return kill_pid_info_type(sig, &kinfo, pid, type);
}
/**
* sys_pidfd_send_signal - Signal a process through a pidfd
* @pidfd: file descriptor of the process
* @sig: signal to send
* @info: signal info
* @flags: future flags
*
* Send the signal to the thread group or to the individual thread depending
* on PIDFD_THREAD.
* In the future extension to @flags may be used to override the default scope
* of @pidfd.
*
* Return: 0 on success, negative errno on failure
*/
SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
siginfo_t __user *, info, unsigned int, flags)
{
struct pid *pid;
enum pid_type type;
/* Enforce flags be set to 0 until we add an extension. */
if (flags & ~PIDFD_SEND_SIGNAL_FLAGS)
return -EINVAL;
/* Ensure that only a single signal scope determining flag is set. */
if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
return -EINVAL;
switch (pidfd) {
case PIDFD_SELF_THREAD:
pid = get_task_pid(current, PIDTYPE_PID);
type = PIDTYPE_PID;
break;
case PIDFD_SELF_THREAD_GROUP:
pid = get_task_pid(current, PIDTYPE_TGID);
type = PIDTYPE_TGID;
break;
default: {
CLASS(fd, f)(pidfd);
if (fd_empty(f))
return -EBADF;
/* Is this a pidfd? */
pid = pidfd_to_pid(fd_file(f));
if (IS_ERR(pid))
return PTR_ERR(pid);
if (!access_pidfd_pidns(pid))
return -EINVAL;
/* Infer scope from the type of pidfd. */
if (fd_file(f)->f_flags & PIDFD_THREAD)
type = PIDTYPE_PID;
else
type = PIDTYPE_TGID;
return do_pidfd_send_signal(pid, sig, type, info, flags);
}
}
return do_pidfd_send_signal(pid, sig, type, info, flags);
}
static int