summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-19 20:32:52 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-19 20:32:52 -1000
commita6656aefd328d544420ecec121fc898b7f067827 (patch)
tree6f4cb7925f060fb49f8a2345849a2dbb7a38fe37 /include/linux
parent2a49d49159b76f6dd587131b3765d3458cc3aa01 (diff)
parent96bd708bdab49bea550070d935198ad4f2028a73 (diff)
Merge tag 'vfs-7.4-rc1.shared.net-next.pidfd' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull pidfd updates from Christian Brauner: "This adds thread specific pidfds to af_unix sockets. SO_PASSPIDFD and SO_PEERPIDFD hand out a pidfd for the thread-group leader. A coredump server on the coredump socket can't get a handle on the thread that took the signal and is writing the dump, and anything doing per-thread authentication has the same problem. The sending and the connecting thread are recorded in addition to the thread-group leader and sk_peer_pid becomes an array indexed by pid type. SO_PASSPIDFD_THREAD works like SO_PASSPIDFD but delivers an SCM_PIDFD_THREAD cmsg for the sending thread. Both options are independent so a receiver can ask for both. On SOCK_STREAM sockets recvmsg() only stops merging data at a thread boundary when the receiver asked for a thread pidfd. SO_PEERPIDFD_THREAD returns a pidfd for the thread that called connect(), listen() or socketpair(). pidfs records the coredump on the dumping thread's struct pid too so its pidfd reports it like the leader's does. Selftests for af_unix and the coredump socket are included" * tag 'vfs-7.4-rc1.shared.net-next.pidfd' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: selftests/coredump: check the dumping thread's pidfd pidfs: record the coredump on the dumping thread's pid too selftests/net: SO_PEERPIDFD_THREAD net: add SO_PEERPIDFD_THREAD to get a thread-specific pidfd af_unix: record the pid of the connecting thread net: turn sk_peer_pid into an array indexed by pid type selftests/net: SO_PASSPIDFD_THREAD net: add SO_PASSPIDFD_THREAD to get a thread-specific SCM_PIDFD af_unix: record the pid of the sending thread pid: add helpers to operate on a struct pid array
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/coredump.h4
-rw-r--r--include/linux/pid.h53
-rw-r--r--include/linux/pid_types.h8
-rw-r--r--include/linux/pidfs.h5
-rw-r--r--include/linux/sched/signal.h18
-rw-r--r--include/linux/socket.h9
6 files changed, 92 insertions, 5 deletions
diff --git a/include/linux/coredump.h b/include/linux/coredump.h
index 74af57b9406b..8e857770dd21 100644
--- a/include/linux/coredump.h
+++ b/include/linux/coredump.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/fs.h>
+#include <linux/pid_types.h>
#include <linux/sched/coredump.h>
#include <uapi/linux/coredump.h>
#include <asm/siginfo.h>
@@ -51,7 +52,8 @@ struct coredump_params {
int vma_count;
size_t vma_data_size;
struct core_vma_metadata *vma_meta;
- struct pid *pid;
+ /* Dumping thread and its thread-group leader by pid type. */
+ DECLARE_PIDS(pid, PIDTYPE_TGID);
};
extern unsigned int core_file_note_size_limit;
diff --git a/include/linux/pid.h b/include/linux/pid.h
index a0458c713e4e..185bf0cde2d1 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -2,6 +2,9 @@
#ifndef _LINUX_PID_H
#define _LINUX_PID_H
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/minmax.h>
#include <linux/pid_types.h>
#include <linux/rculist.h>
#include <linux/rcupdate.h>
@@ -92,6 +95,56 @@ static inline struct pid *get_pid(struct pid *pid)
}
extern void put_pid(struct pid *pid);
+
+/*
+ * Helpers for arrays of struct pid indexed by pid type declared with
+ * DECLARE_PIDS(). The array covers PIDTYPE_PID up to the pid type it
+ * was declared with and the helpers take that bound from the array.
+ */
+static inline void __get_pids(struct pid **dst, struct pid *const *src,
+ enum pid_type last)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++)
+ dst[type] = get_pid(src[type]);
+}
+
+static inline void __put_pids(struct pid **pids, enum pid_type last)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++) {
+ put_pid(pids[type]);
+ pids[type] = NULL;
+ }
+}
+
+static inline void __swap_pids(struct pid **a, struct pid **b,
+ enum pid_type last)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++)
+ swap(a[type], b[type]);
+}
+
+static inline bool __pids_equal(struct pid *const *a, struct pid *const *b,
+ enum pid_type last)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++)
+ if (a[type] != b[type])
+ return false;
+ return true;
+}
+
+/* The last pid type an array declared with DECLARE_PIDS() covers. */
+#define pids_last(pids) \
+ ((enum pid_type)(ARRAY_SIZE(pids) - 1 + \
+ BUILD_BUG_ON_ZERO(ARRAY_SIZE(pids) > PIDTYPE_MAX)))
+
+#define __pids_last2(a, b) \
+ (pids_last(a) + BUILD_BUG_ON_ZERO(ARRAY_SIZE(a) != ARRAY_SIZE(b)))
+
+#define get_pids(dst, src) __get_pids(dst, src, __pids_last2(dst, src))
+#define put_pids(pids) __put_pids(pids, pids_last(pids))
+#define swap_pids(a, b) __swap_pids(a, b, __pids_last2(a, b))
+#define pids_equal(a, b) __pids_equal(a, b, __pids_last2(a, b))
+
extern struct task_struct *pid_task(struct pid *pid, enum pid_type);
static inline bool pid_has_task(struct pid *pid, enum pid_type type)
{
diff --git a/include/linux/pid_types.h b/include/linux/pid_types.h
index c2aee1d91dcf..3302690a2a28 100644
--- a/include/linux/pid_types.h
+++ b/include/linux/pid_types.h
@@ -2,6 +2,8 @@
#ifndef _LINUX_PID_TYPES_H
#define _LINUX_PID_TYPES_H
+#include <linux/build_bug.h>
+
enum pid_type {
PIDTYPE_PID,
PIDTYPE_TGID,
@@ -10,6 +12,12 @@ enum pid_type {
PIDTYPE_MAX,
};
+struct pid;
+
+/* An array of struct pid indexed by pid type, PIDTYPE_PID up to @last. */
+#define DECLARE_PIDS(name, last) \
+ struct pid *name[(last) + 1 + BUILD_BUG_ON_ZERO((last) >= PIDTYPE_MAX)]
+
struct pid_namespace;
extern struct pid_namespace init_pid_ns;
diff --git a/include/linux/pidfs.h b/include/linux/pidfs.h
index 0abf7da9ab23..3c1e82f1a369 100644
--- a/include/linux/pidfs.h
+++ b/include/linux/pidfs.h
@@ -3,6 +3,7 @@
#define _LINUX_PID_FS_H
#include <linux/gfp_types.h>
+#include <linux/pid.h>
struct coredump_params;
@@ -32,5 +33,9 @@ static inline int pidfs_register_pid(struct pid *pid)
}
void pidfs_free_pid(struct pid *pid);
+int __pidfs_register_pids(struct pid *const *pids, enum pid_type last);
+
+/* Register the pids of an array declared with DECLARE_PIDS(). */
+#define pidfs_register_pids(pids) __pidfs_register_pids(pids, pids_last(pids))
#endif /* _LINUX_PID_FS_H */
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
index bfb84f025b67..f65d97fe199c 100644
--- a/include/linux/sched/signal.h
+++ b/include/linux/sched/signal.h
@@ -697,6 +697,24 @@ struct pid *task_pid_type(struct task_struct *task, enum pid_type type)
return pid;
}
+/* Fill @pids with the pid types of @task up to @last, without references. */
+static inline void __task_pids(struct pid **pids, enum pid_type last,
+ struct task_struct *task)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++)
+ pids[type] = task_pid_type(task, type);
+}
+
+static inline void __get_task_pids(struct pid **pids, enum pid_type last,
+ struct task_struct *task)
+{
+ for (enum pid_type type = PIDTYPE_PID; type <= last; type++)
+ pids[type] = get_pid(task_pid_type(task, type));
+}
+
+#define task_pids(pids, task) __task_pids(pids, pids_last(pids), task)
+#define get_task_pids(pids, task) __get_task_pids(pids, pids_last(pids), task)
+
static inline struct pid *task_tgid(struct task_struct *task)
{
return task->signal->pids[PIDTYPE_TGID];
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 5a5eb1250103..b17fdb7d38a7 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -189,10 +189,11 @@ static inline size_t msg_data_left(const struct msghdr *msg)
/* "Socket"-level control message types: */
-#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
-#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
-#define SCM_SECURITY 0x03 /* rw: security label */
-#define SCM_PIDFD 0x04 /* ro: pidfd (int) */
+#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */
+#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */
+#define SCM_SECURITY 0x03 /* rw: security label */
+#define SCM_PIDFD 0x04 /* ro: pidfd (int) */
+#define SCM_PIDFD_THREAD 0x05 /* ro: thread pidfd (int) */
struct ucred {
__u32 pid;