Skip to content

Commit f08d0c3

Browse files
ljskernelbrauner
authored andcommitted
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>
1 parent 2014c95 commit f08d0c3

3 files changed

Lines changed: 106 additions & 47 deletions

File tree

include/uapi/linux/pidfd.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,30 @@
2323

2424
#define PIDFD_INFO_SIZE_VER0 64 /* sizeof first published struct */
2525

26+
/*
27+
* The concept of process and threads in userland and the kernel is a confusing
28+
* one - within the kernel every thread is a 'task' with its own individual PID,
29+
* however from userland's point of view threads are grouped by a single PID,
30+
* which is that of the 'thread group leader', typically the first thread
31+
* spawned.
32+
*
33+
* To cut the Gideon knot, for internal kernel usage, we refer to
34+
* PIDFD_SELF_THREAD to refer to the current thread (or task from a kernel
35+
* perspective), and PIDFD_SELF_THREAD_GROUP to refer to the current thread
36+
* group leader...
37+
*/
38+
#define PIDFD_SELF_THREAD -10000 /* Current thread. */
39+
#define PIDFD_SELF_THREAD_GROUP -20000 /* Current thread group leader. */
40+
41+
/*
42+
* ...and for userland we make life simpler - PIDFD_SELF refers to the current
43+
* thread, PIDFD_SELF_PROCESS refers to the process thread group leader.
44+
*
45+
* For nearly all practical uses, a user will want to use PIDFD_SELF.
46+
*/
47+
#define PIDFD_SELF PIDFD_SELF_THREAD
48+
#define PIDFD_SELF_PROCESS PIDFD_SELF_THREAD_GROUP
49+
2650
struct pidfd_info {
2751
/*
2852
* This mask is similar to the request_mask in statx(2).

kernel/pid.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,15 +564,29 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags)
564564
*/
565565
struct task_struct *pidfd_get_task(int pidfd, unsigned int *flags)
566566
{
567-
unsigned int f_flags;
567+
unsigned int f_flags = 0;
568568
struct pid *pid;
569569
struct task_struct *task;
570+
enum pid_type type;
570571

571-
pid = pidfd_get_pid(pidfd, &f_flags);
572-
if (IS_ERR(pid))
573-
return ERR_CAST(pid);
572+
switch (pidfd) {
573+
case PIDFD_SELF_THREAD:
574+
type = PIDTYPE_PID;
575+
pid = get_task_pid(current, type);
576+
break;
577+
case PIDFD_SELF_THREAD_GROUP:
578+
type = PIDTYPE_TGID;
579+
pid = get_task_pid(current, type);
580+
break;
581+
default:
582+
pid = pidfd_get_pid(pidfd, &f_flags);
583+
if (IS_ERR(pid))
584+
return ERR_CAST(pid);
585+
type = PIDTYPE_TGID;
586+
break;
587+
}
574588

575-
task = get_pid_task(pid, PIDTYPE_TGID);
589+
task = get_pid_task(pid, type);
576590
put_pid(pid);
577591
if (!task)
578592
return ERR_PTR(-ESRCH);

kernel/signal.c

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4009,6 +4009,47 @@ static struct pid *pidfd_to_pid(const struct file *file)
40094009
(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \
40104010
PIDFD_SIGNAL_PROCESS_GROUP)
40114011

4012+
static int do_pidfd_send_signal(struct pid *pid, int sig, enum pid_type type,
4013+
siginfo_t __user *info, unsigned int flags)
4014+
{
4015+
kernel_siginfo_t kinfo;
4016+
4017+
switch (flags) {
4018+
case PIDFD_SIGNAL_THREAD:
4019+
type = PIDTYPE_PID;
4020+
break;
4021+
case PIDFD_SIGNAL_THREAD_GROUP:
4022+
type = PIDTYPE_TGID;
4023+
break;
4024+
case PIDFD_SIGNAL_PROCESS_GROUP:
4025+
type = PIDTYPE_PGID;
4026+
break;
4027+
}
4028+
4029+
if (info) {
4030+
int ret;
4031+
4032+
ret = copy_siginfo_from_user_any(&kinfo, info);
4033+
if (unlikely(ret))
4034+
return ret;
4035+
4036+
if (unlikely(sig != kinfo.si_signo))
4037+
return -EINVAL;
4038+
4039+
/* Only allow sending arbitrary signals to yourself. */
4040+
if ((task_pid(current) != pid || type > PIDTYPE_TGID) &&
4041+
(kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL))
4042+
return -EPERM;
4043+
} else {
4044+
prepare_kill_siginfo(sig, &kinfo, type);
4045+
}
4046+
4047+
if (type == PIDTYPE_PGID)
4048+
return kill_pgrp_info(sig, &kinfo, pid);
4049+
4050+
return kill_pid_info_type(sig, &kinfo, pid, type);
4051+
}
4052+
40124053
/**
40134054
* sys_pidfd_send_signal - Signal a process through a pidfd
40144055
* @pidfd: file descriptor of the process
@@ -4026,9 +4067,7 @@ static struct pid *pidfd_to_pid(const struct file *file)
40264067
SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
40274068
siginfo_t __user *, info, unsigned int, flags)
40284069
{
4029-
int ret;
40304070
struct pid *pid;
4031-
kernel_siginfo_t kinfo;
40324071
enum pid_type type;
40334072

40344073
/* Enforce flags be set to 0 until we add an extension. */
@@ -4039,57 +4078,39 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
40394078
if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
40404079
return -EINVAL;
40414080

4042-
CLASS(fd, f)(pidfd);
4043-
if (fd_empty(f))
4044-
return -EBADF;
4081+
switch (pidfd) {
4082+
case PIDFD_SELF_THREAD:
4083+
pid = get_task_pid(current, PIDTYPE_PID);
4084+
type = PIDTYPE_PID;
4085+
break;
4086+
case PIDFD_SELF_THREAD_GROUP:
4087+
pid = get_task_pid(current, PIDTYPE_TGID);
4088+
type = PIDTYPE_TGID;
4089+
break;
4090+
default: {
4091+
CLASS(fd, f)(pidfd);
4092+
if (fd_empty(f))
4093+
return -EBADF;
40454094

4046-
/* Is this a pidfd? */
4047-
pid = pidfd_to_pid(fd_file(f));
4048-
if (IS_ERR(pid))
4049-
return PTR_ERR(pid);
4095+
/* Is this a pidfd? */
4096+
pid = pidfd_to_pid(fd_file(f));
4097+
if (IS_ERR(pid))
4098+
return PTR_ERR(pid);
40504099

4051-
if (!access_pidfd_pidns(pid))
4052-
return -EINVAL;
4100+
if (!access_pidfd_pidns(pid))
4101+
return -EINVAL;
40534102

4054-
switch (flags) {
4055-
case 0:
40564103
/* Infer scope from the type of pidfd. */
40574104
if (fd_file(f)->f_flags & PIDFD_THREAD)
40584105
type = PIDTYPE_PID;
40594106
else
40604107
type = PIDTYPE_TGID;
4061-
break;
4062-
case PIDFD_SIGNAL_THREAD:
4063-
type = PIDTYPE_PID;
4064-
break;
4065-
case PIDFD_SIGNAL_THREAD_GROUP:
4066-
type = PIDTYPE_TGID;
4067-
break;
4068-
case PIDFD_SIGNAL_PROCESS_GROUP:
4069-
type = PIDTYPE_PGID;
4070-
break;
4071-
}
40724108

4073-
if (info) {
4074-
ret = copy_siginfo_from_user_any(&kinfo, info);
4075-
if (unlikely(ret))
4076-
return ret;
4077-
4078-
if (unlikely(sig != kinfo.si_signo))
4079-
return -EINVAL;
4080-
4081-
/* Only allow sending arbitrary signals to yourself. */
4082-
if ((task_pid(current) != pid || type > PIDTYPE_TGID) &&
4083-
(kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL))
4084-
return -EPERM;
4085-
} else {
4086-
prepare_kill_siginfo(sig, &kinfo, type);
4109+
return do_pidfd_send_signal(pid, sig, type, info, flags);
4110+
}
40874111
}
40884112

4089-
if (type == PIDTYPE_PGID)
4090-
return kill_pgrp_info(sig, &kinfo, pid);
4091-
else
4092-
return kill_pid_info_type(sig, &kinfo, pid, type);
4113+
return do_pidfd_send_signal(pid, sig, type, info, flags);
40934114
}
40944115

40954116
static int

0 commit comments

Comments
 (0)