[PATCH 08/10] selftests/net: SO_PEERPIDFD_THREAD
From: Christian Brauner <brauner@kernel.org>
Date: 2026-08-31 11:21:56
Also in:
linux-fsdevel, lkml
Subsystem:
kernel selftest framework, networking [general], networking [unix sockets], the rest · Maintainers:
Shuah Khan, Shuah Khan, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Kuniyuki Iwashima, Linus Torvalds
Add tests for SO_PEERPIDFD_THREAD. Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org> --- tools/testing/selftests/net/af_unix/scm_pidfd.c | 97 +++++++++++++++++++++++++ 1 file changed, 97 insertions(+)
diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c
index 019c48e1cdcd..bbbd5e7b4fa7 100644
--- a/tools/testing/selftests/net/af_unix/scm_pidfd.c
+++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c@@ -32,6 +32,10 @@ #define SO_PASSPIDFD_THREAD 86 #endif +#ifndef SO_PEERPIDFD_THREAD +#define SO_PEERPIDFD_THREAD 87 +#endif + #define CHILD_EXIT_CODE_OK 123 static void child_die()
@@ -822,4 +826,97 @@ TEST(scm_pidfd_thread_creds) EXPECT_EQ(ids.pid, info.tgid); } +static void *peer_connect_thread(void *arg) +{ + struct sock_addr *sa = arg; + struct thread_ids ids = { + .pid = getpid(), + .tid = gettid(), + }; + int fd; + char sync; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return (void *)1; + + if (connect(fd, (struct sockaddr *)&sa->listen_addr, sa->addrlen)) + return (void *)1; + + if (send(fd, &ids, sizeof(ids), 0) != sizeof(ids)) + return (void *)1; + + /* stay alive until the server has looked at our pidfd */ + if (read(fd, &sync, 1) != 1) + return (void *)1; + + close(fd); + return NULL; +} + +static int peer_pidfd_info(int fd, int optname, struct pidfd_info *info) +{ + int pidfd; + socklen_t len = sizeof(pidfd); + + if (getsockopt(fd, SOL_SOCKET, optname, &pidfd, &len)) { + log_err("getsockopt(SO_PEERPIDFD*)"); + return -1; + } + + info->mask = PIDFD_INFO_PID; + if (ioctl(pidfd, PIDFD_GET_INFO, info)) { + log_err("ioctl(PIDFD_GET_INFO)"); + close(pidfd); + return -1; + } + + close(pidfd); + return 0; +} + +/* SO_PEERPIDFD_THREAD returns a pidfd for the peer's connecting thread. */ +TEST(so_peerpidfd_thread) +{ + struct sock_addr sa; + struct thread_ids ids; + struct pidfd_info info; + pthread_t thread; + void *tret; + int server, cfd; + + server = socket(AF_UNIX, SOCK_STREAM, 0); + ASSERT_LE(0, server); + + fill_sockaddr(&sa, true); + ASSERT_EQ(0, bind(server, (struct sockaddr *)&sa.listen_addr, sa.addrlen)); + ASSERT_EQ(0, listen(server, 1)); + + ASSERT_EQ(0, pthread_create(&thread, NULL, peer_connect_thread, &sa)); + + cfd = accept(server, NULL, NULL); + ASSERT_LE(0, cfd); + + ASSERT_EQ(sizeof(ids), recv(cfd, &ids, sizeof(ids), MSG_WAITALL)); + ASSERT_NE(ids.pid, ids.tid); + + /* SO_PEERPIDFD refers to the peer's thread-group. */ + ASSERT_EQ(0, peer_pidfd_info(cfd, SO_PEERPIDFD, &info)); + EXPECT_EQ(ids.pid, info.pid); + EXPECT_EQ(ids.pid, info.tgid); + + /* SO_PEERPIDFD_THREAD refers to the connecting thread. */ + ASSERT_EQ(0, peer_pidfd_info(cfd, SO_PEERPIDFD_THREAD, &info)); + EXPECT_EQ(ids.tid, info.pid); + EXPECT_EQ(ids.pid, info.tgid); + + /* release the connecting thread */ + ASSERT_EQ(1, write(cfd, "x", 1)); + ASSERT_EQ(0, pthread_join(thread, &tret)); + ASSERT_EQ(NULL, tret); + + close(cfd); + close(server); +} + TEST_HARNESS_MAIN
--
2.53.0