BACKPORT: 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> (cherry picked from commit f08d0c3a71114bb36d1722506d926bd497182781) [surenb: trivial merge conflict in pidfd.h, adjusted pidfd_send_signal() code for differences between 6.12 and upstream] Bug: 402449065 Change-Id: I98e7c16b20ffe04b95248d8ae865c10c1150d058 Signed-off-by: Suren Baghdasaryan <surenb@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
b00dca6fb7
commit
1734a4ad6b
@@ -29,4 +29,28 @@
|
|||||||
#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9)
|
#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9)
|
||||||
#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10)
|
#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
#endif /* _UAPI_LINUX_PIDFD_H */
|
#endif /* _UAPI_LINUX_PIDFD_H */
|
||||||
|
|||||||
+19
-5
@@ -569,15 +569,29 @@ EXPORT_SYMBOL_GPL(pidfd_get_pid);
|
|||||||
*/
|
*/
|
||||||
struct task_struct *pidfd_get_task(int pidfd, 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 pid *pid;
|
||||||
struct task_struct *task;
|
struct task_struct *task;
|
||||||
|
enum pid_type type;
|
||||||
|
|
||||||
pid = pidfd_get_pid(pidfd, &f_flags);
|
switch (pidfd) {
|
||||||
if (IS_ERR(pid))
|
case PIDFD_SELF_THREAD:
|
||||||
return ERR_CAST(pid);
|
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);
|
put_pid(pid);
|
||||||
if (!task)
|
if (!task)
|
||||||
return ERR_PTR(-ESRCH);
|
return ERR_PTR(-ESRCH);
|
||||||
|
|||||||
+71
-50
@@ -3907,6 +3907,47 @@ static struct pid *pidfd_to_pid(const struct file *file)
|
|||||||
(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \
|
(PIDFD_SIGNAL_THREAD | PIDFD_SIGNAL_THREAD_GROUP | \
|
||||||
PIDFD_SIGNAL_PROCESS_GROUP)
|
PIDFD_SIGNAL_PROCESS_GROUP)
|
||||||
|
|
||||||
|
static int do_pidfd_send_signal(struct pid *pid, int sig, enum pid_type type,
|
||||||
|
siginfo_t __user *info, unsigned int flags)
|
||||||
|
{
|
||||||
|
kernel_siginfo_t kinfo;
|
||||||
|
|
||||||
|
switch (flags) {
|
||||||
|
case PIDFD_SIGNAL_THREAD:
|
||||||
|
type = PIDTYPE_PID;
|
||||||
|
break;
|
||||||
|
case PIDFD_SIGNAL_THREAD_GROUP:
|
||||||
|
type = PIDTYPE_TGID;
|
||||||
|
break;
|
||||||
|
case PIDFD_SIGNAL_PROCESS_GROUP:
|
||||||
|
type = PIDTYPE_PGID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = copy_siginfo_from_user_any(&kinfo, info);
|
||||||
|
if (unlikely(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (unlikely(sig != kinfo.si_signo))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Only allow sending arbitrary signals to yourself. */
|
||||||
|
if ((task_pid(current) != pid || type > PIDTYPE_TGID) &&
|
||||||
|
(kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL))
|
||||||
|
return -EPERM;
|
||||||
|
} else {
|
||||||
|
prepare_kill_siginfo(sig, &kinfo, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == PIDTYPE_PGID)
|
||||||
|
return kill_pgrp_info(sig, &kinfo, pid);
|
||||||
|
|
||||||
|
return kill_pid_info_type(sig, &kinfo, pid, type);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sys_pidfd_send_signal - Signal a process through a pidfd
|
* sys_pidfd_send_signal - Signal a process through a pidfd
|
||||||
* @pidfd: file descriptor of the process
|
* @pidfd: file descriptor of the process
|
||||||
@@ -3927,7 +3968,6 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
|
|||||||
int ret;
|
int ret;
|
||||||
struct fd f;
|
struct fd f;
|
||||||
struct pid *pid;
|
struct pid *pid;
|
||||||
kernel_siginfo_t kinfo;
|
|
||||||
enum pid_type type;
|
enum pid_type type;
|
||||||
|
|
||||||
/* Enforce flags be set to 0 until we add an extension. */
|
/* Enforce flags be set to 0 until we add an extension. */
|
||||||
@@ -3938,65 +3978,46 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
|
|||||||
if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
|
if (hweight32(flags & PIDFD_SEND_SIGNAL_FLAGS) > 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
f = fdget(pidfd);
|
switch (pidfd) {
|
||||||
if (!fd_file(f))
|
case PIDFD_SELF_THREAD:
|
||||||
return -EBADF;
|
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: {
|
||||||
|
f = fdget(pidfd);
|
||||||
|
if (!fd_file(f))
|
||||||
|
return -EBADF;
|
||||||
|
|
||||||
/* Is this a pidfd? */
|
/* Is this a pidfd? */
|
||||||
pid = pidfd_to_pid(fd_file(f));
|
pid = pidfd_to_pid(fd_file(f));
|
||||||
if (IS_ERR(pid)) {
|
if (IS_ERR(pid)) {
|
||||||
ret = PTR_ERR(pid);
|
ret = PTR_ERR(pid);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = -EINVAL;
|
if (!access_pidfd_pidns(pid)) {
|
||||||
if (!access_pidfd_pidns(pid))
|
ret = -EINVAL;
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
switch (flags) {
|
|
||||||
case 0:
|
|
||||||
/* Infer scope from the type of pidfd. */
|
/* Infer scope from the type of pidfd. */
|
||||||
if (fd_file(f)->f_flags & PIDFD_THREAD)
|
if (fd_file(f)->f_flags & PIDFD_THREAD)
|
||||||
type = PIDTYPE_PID;
|
type = PIDTYPE_PID;
|
||||||
else
|
else
|
||||||
type = PIDTYPE_TGID;
|
type = PIDTYPE_TGID;
|
||||||
break;
|
|
||||||
case PIDFD_SIGNAL_THREAD:
|
|
||||||
type = PIDTYPE_PID;
|
|
||||||
break;
|
|
||||||
case PIDFD_SIGNAL_THREAD_GROUP:
|
|
||||||
type = PIDTYPE_TGID;
|
|
||||||
break;
|
|
||||||
case PIDFD_SIGNAL_PROCESS_GROUP:
|
|
||||||
type = PIDTYPE_PGID;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info) {
|
ret = do_pidfd_send_signal(pid, sig, type, info, flags);
|
||||||
ret = copy_siginfo_from_user_any(&kinfo, info);
|
|
||||||
if (unlikely(ret))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
ret = -EINVAL;
|
|
||||||
if (unlikely(sig != kinfo.si_signo))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
/* Only allow sending arbitrary signals to yourself. */
|
|
||||||
ret = -EPERM;
|
|
||||||
if ((task_pid(current) != pid || type > PIDTYPE_TGID) &&
|
|
||||||
(kinfo.si_code >= 0 || kinfo.si_code == SI_TKILL))
|
|
||||||
goto err;
|
|
||||||
} else {
|
|
||||||
prepare_kill_siginfo(sig, &kinfo, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == PIDTYPE_PGID)
|
|
||||||
ret = kill_pgrp_info(sig, &kinfo, pid);
|
|
||||||
else
|
|
||||||
ret = kill_pid_info_type(sig, &kinfo, pid, type);
|
|
||||||
err:
|
err:
|
||||||
fdput(f);
|
fdput(f);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return do_pidfd_send_signal(pid, sig, type, info, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
Reference in New Issue
Block a user