Re: [PATCH] pidfd: change pidfd_send_signal() to respect PIDFD_THREAD

4 messages, 3 authors, 2024-02-09 · open the first message on its own page

Re: [PATCH] pidfd: change pidfd_send_signal() to respect PIDFD_THREAD

From: Eric W. Biederman <hidden>
Date: 2024-02-08 16:10:02

Oleg Nesterov [off-list ref] writes:
Turn kill_pid_info() into kill_pid_info_type(), this allows to pass any
pid_type to group_send_sig_info(), despite its name it should work fine
even if type = PIDTYPE_PID.

Change pidfd_send_signal() to use PIDTYPE_PID or PIDTYPE_TGID depending
on PIDFD_THREAD.

While at it kill another TODO comment in pidfd_show_fdinfo(). As Christian
expains fdinfo reports f_flags, userspace can already detect PIDFD_THREAD.
I have a question here.

Why is this based on group_send_sig_info instead of send_sig_info?

AKA why does this look like sys_kill instead of sys_tgkill?

In particular I am asking are the intended semantics that the signal is
sent to a single thread in a thread group and placed in the per thread
queue, or is the signal sent to the entire thread group and placed
in the thread group signal queue?

Does the type parameter handle that decision for us now?  If so
perhaps we should cleanup the helpers so that this easier to
see when reading the code.

Because honestly right now using group_send_sig_info when
the intended target of the signal is not the entire thread
group is very confusing when reading your change.

Eric
quoted hunk
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 kernel/fork.c   |  2 --
 kernel/signal.c | 18 ++++++++++++------
 2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/kernel/fork.c b/kernel/fork.c
index cd61ca87d0e6..47b565598063 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2051,8 +2051,6 @@ static void pidfd_show_fdinfo(struct seq_file *m, struct file *f)
 
 	seq_put_decimal_ll(m, "Pid:\t", nr);
 
-	/* TODO: report PIDFD_THREAD */
-
 #ifdef CONFIG_PID_NS
 	seq_put_decimal_ll(m, "\nNSpid:\t", nr);
 	if (nr > 0) {
diff --git a/kernel/signal.c b/kernel/signal.c
index c3fac06937e2..e3edcd784e45 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -47,6 +47,7 @@
 #include <linux/cgroup.h>
 #include <linux/audit.h>
 #include <linux/sysctl.h>
+#include <uapi/linux/pidfd.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
@@ -1478,7 +1479,8 @@ int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp)
 	return ret;
 }
 
-int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
+static int kill_pid_info_type(int sig, struct kernel_siginfo *info,
+				struct pid *pid, enum pid_type type)
 {
 	int error = -ESRCH;
 	struct task_struct *p;
@@ -1487,11 +1489,10 @@ int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
 		rcu_read_lock();
 		p = pid_task(pid, PIDTYPE_PID);
 		if (p)
-			error = group_send_sig_info(sig, info, p, PIDTYPE_TGID);
+			error = group_send_sig_info(sig, info, p, type);
 		rcu_read_unlock();
 		if (likely(!p || error != -ESRCH))
 			return error;
-
 		/*
 		 * The task was unhashed in between, try again.  If it
 		 * is dead, pid_task() will return NULL, if we race with
@@ -1500,6 +1501,11 @@ int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
 	}
 }
 
+int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
+{
+	return kill_pid_info_type(sig, info, pid, PIDTYPE_TGID);
+}
+
 static int kill_proc_info(int sig, struct kernel_siginfo *info, pid_t pid)
 {
 	int error;
@@ -3890,6 +3896,7 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
 	struct fd f;
 	struct pid *pid;
 	kernel_siginfo_t kinfo;
+	enum pid_type type;
 
 	/* Enforce flags be set to 0 until we add an extension. */
 	if (flags)
@@ -3928,9 +3935,8 @@ SYSCALL_DEFINE4(pidfd_send_signal, int, pidfd, int, sig,
 		prepare_kill_siginfo(sig, &kinfo);
 	}
 
-	/* TODO: respect PIDFD_THREAD */
-	ret = kill_pid_info(sig, &kinfo, pid);
-
+	type = (f.file->f_flags & PIDFD_THREAD) ? PIDTYPE_PID : PIDTYPE_TGID;
+	ret = kill_pid_info_type(sig, &kinfo, pid, type);
 err:
 	fdput(f);
 	return ret;

Re: [PATCH] pidfd: change pidfd_send_signal() to respect PIDFD_THREAD

From: Oleg Nesterov <oleg@redhat.com>
Date: 2024-02-08 15:58:54

On 02/08, Eric W. Biederman wrote:
Oleg Nesterov [off-list ref] writes:
quoted
Turn kill_pid_info() into kill_pid_info_type(), this allows to pass any
pid_type to group_send_sig_info(), despite its name it should work fine
even if type = PIDTYPE_PID.

Change pidfd_send_signal() to use PIDTYPE_PID or PIDTYPE_TGID depending
on PIDFD_THREAD.

While at it kill another TODO comment in pidfd_show_fdinfo(). As Christian
expains fdinfo reports f_flags, userspace can already detect PIDFD_THREAD.
I have a question here.

Why is this based on group_send_sig_info instead of send_sig_info?
Well. send_sig_info() accepts "struct task_struct *", not "struct pid *",
it doesn't do check_kill_permission(), and it doesn't handle the possible
race with mt-exec.
In particular I am asking are the intended semantics that the signal is
sent to a single thread in a thread group and placed in the per thread
queue, or is the signal sent to the entire thread group and placed
in the thread group signal queue?
This depends on PIDFD_THREAD. If it is set then the signal goes to
the per thread queue.
Because honestly right now using group_send_sig_info when
the intended target of the signal is not the entire thread
group is very confusing when reading your change.
Agreed, so perhaps it makes sense to rename it later. See

	despite its name it should work fine even if type = PIDTYPE_PID.

in the changelog above.

Oleg.

Re: [PATCH] pidfd: change pidfd_send_signal() to respect PIDFD_THREAD

From: Christian Brauner <brauner@kernel.org>
Date: 2024-02-09 09:26:12

On Thu, Feb 08, 2024 at 04:57:31PM +0100, Oleg Nesterov wrote:
On 02/08, Eric W. Biederman wrote:
quoted
Oleg Nesterov [off-list ref] writes:
quoted
Turn kill_pid_info() into kill_pid_info_type(), this allows to pass any
pid_type to group_send_sig_info(), despite its name it should work fine
even if type = PIDTYPE_PID.

Change pidfd_send_signal() to use PIDTYPE_PID or PIDTYPE_TGID depending
on PIDFD_THREAD.

While at it kill another TODO comment in pidfd_show_fdinfo(). As Christian
expains fdinfo reports f_flags, userspace can already detect PIDFD_THREAD.
I have a question here.

Why is this based on group_send_sig_info instead of send_sig_info?
Well. send_sig_info() accepts "struct task_struct *", not "struct pid *",
it doesn't do check_kill_permission(), and it doesn't handle the possible
race with mt-exec.
quoted
In particular I am asking are the intended semantics that the signal is
sent to a single thread in a thread group and placed in the per thread
queue, or is the signal sent to the entire thread group and placed
in the thread group signal queue?
This depends on PIDFD_THREAD. If it is set then the signal goes to
the per thread queue.
quoted
Because honestly right now using group_send_sig_info when
the intended target of the signal is not the entire thread
group is very confusing when reading your change.
Agreed, so perhaps it makes sense to rename it later. See
Agreed. The function seems misnamed and incorrectly documented. It just
seems that it's never been used with PIDTYPE_PID but it's perfectly
capable of doing that. So maybe just put a patch on top renaming it to
send_sig_info_type() and remove the old comment. But I can live without
renaming it for now as well.

Re: [PATCH] pidfd: change pidfd_send_signal() to respect PIDFD_THREAD

From: Oleg Nesterov <oleg@redhat.com>
Date: 2024-02-09 10:55:15

On 02/09, Christian Brauner wrote:
On Thu, Feb 08, 2024 at 04:57:31PM +0100, Oleg Nesterov wrote:
quoted
On 02/08, Eric W. Biederman wrote:
quoted
Because honestly right now using group_send_sig_info when
the intended target of the signal is not the entire thread
group is very confusing when reading your change.
Agreed, so perhaps it makes sense to rename it later. See
Agreed. The function seems misnamed and incorrectly documented. It just
seems that it's never been used with PIDTYPE_PID but it's perfectly
capable of doing that. So maybe just put a patch on top renaming it to
send_sig_info_type() and remove the old comment. But I can live without
renaming it for now as well.
OK, I'll update the comment, please see below.

It should probably say more about the case when type > PIDTYPE_TGID,
but this is "offtopic" for this patch.

Oleg.
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1437,7 +1437,8 @@ void lockdep_assert_task_sighand_held(struct task_struct *task)
 #endif
 
 /*
- * send signal info to all the members of a group
+ * send signal info to all the members of a thread group or to the
+ * individual thread if type == PIDTYPE_PID.
  */
 int group_send_sig_info(int sig, struct kernel_siginfo *info,
 			struct task_struct *p, enum pid_type type)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help