From: Christian Brauner <brauner@kernel.org>
To: Kuniyuki Iwashima <kuniyu@amazon.com>,
linux-fsdevel@vger.kernel.org, Jann Horn <jannh@google.com>
Cc: "Eric Dumazet" <edumazet@google.com>,
"Oleg Nesterov" <oleg@redhat.com>,
"David S. Miller" <davem@davemloft.net>,
"Alexander Viro" <viro@zeniv.linux.org.uk>,
"Daan De Meyer" <daan.j.demeyer@gmail.com>,
"David Rheinsberg" <david@readahead.eu>,
"Jakub Kicinski" <kuba@kernel.org>, "Jan Kara" <jack@suse.cz>,
"Lennart Poettering" <lennart@poettering.net>,
"Luca Boccassi" <bluca@debian.org>, "Mike Yuan" <me@yhndnzj.com>,
"Paolo Abeni" <pabeni@redhat.com>,
"Simon Horman" <horms@kernel.org>,
"Zbigniew Jędrzejewski-Szmek" <zbyszek@in.waw.pl>,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
"Christian Brauner" <brauner@kernel.org>,
"Alexander Mikhalitsyn" <alexander@mihalicyn.com>
Subject: [PATCH v4 11/11] selftests/coredump: add tests for AF_UNIX coredumps
Date: Wed, 07 May 2025 18:13:44 +0200 [thread overview]
Message-ID: <20250507-work-coredump-socket-v4-11-af0ef317b2d0@kernel.org> (raw)
In-Reply-To: <20250507-work-coredump-socket-v4-0-af0ef317b2d0@kernel.org>
Add a simple test for generating coredumps via AF_UNIX sockets.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
tools/testing/selftests/coredump/stackdump_test.c | 273 +++++++++++++++++++++-
1 file changed, 272 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/coredump/stackdump_test.c b/tools/testing/selftests/coredump/stackdump_test.c
index fe3c728cd6be..a86f4ba0a367 100644
--- a/tools/testing/selftests/coredump/stackdump_test.c
+++ b/tools/testing/selftests/coredump/stackdump_test.c
@@ -5,10 +5,15 @@
#include <linux/limits.h>
#include <pthread.h>
#include <string.h>
+#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
#include "../kselftest_harness.h"
+#include "../pidfd/pidfd.h"
#define STACKDUMP_FILE "stack_values"
#define STACKDUMP_SCRIPT "stackdump"
@@ -35,6 +40,7 @@ static void crashing_child(void)
FIXTURE(coredump)
{
char original_core_pattern[256];
+ pid_t pid_coredump_server;
};
FIXTURE_SETUP(coredump)
@@ -44,6 +50,7 @@ FIXTURE_SETUP(coredump)
char *dir;
int ret;
+ self->pid_coredump_server = -ESRCH;
file = fopen("/proc/sys/kernel/core_pattern", "r");
ASSERT_NE(NULL, file);
@@ -61,10 +68,15 @@ FIXTURE_TEARDOWN(coredump)
{
const char *reason;
FILE *file;
- int ret;
+ int ret, status;
unlink(STACKDUMP_FILE);
+ if (self->pid_coredump_server > 0) {
+ kill(self->pid_coredump_server, SIGTERM);
+ waitpid(self->pid_coredump_server, &status, 0);
+ }
+
file = fopen("/proc/sys/kernel/core_pattern", "w");
if (!file) {
reason = "Unable to open core_pattern";
@@ -154,4 +166,263 @@ TEST_F_TIMEOUT(coredump, stackdump, 120)
fclose(file);
}
+TEST_F(coredump, socket)
+{
+ int fd, pidfd, ret, status;
+ FILE *file;
+ pid_t pid, pid_coredump_server;
+ struct stat st;
+ char core_file[PATH_MAX];
+ struct pidfd_info info = {};
+ int ipc_sockets[2];
+ char c;
+
+ ASSERT_EQ(unshare(CLONE_NEWNS), 0);
+ ASSERT_EQ(mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL), 0);
+ ASSERT_EQ(mount(NULL, "/tmp", "tmpfs", 0, NULL), 0);
+
+ file = fopen("/proc/sys/kernel/core_pattern", "w");
+ ASSERT_NE(NULL, file);
+
+ ret = fprintf(file, "@linuxafsk/coredump.socket");
+ ASSERT_EQ(ret, strlen("@linuxafsk/coredump.socket"));
+ ASSERT_EQ(fclose(file), 0);
+
+ ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
+ ASSERT_EQ(ret, 0);
+
+ pid_coredump_server = fork();
+ ASSERT_GE(pid_coredump_server, 0);
+ if (pid_coredump_server == 0) {
+ int fd_socket, fd_coredump, fd_peer_pidfd, fd_core_file;
+ __u64 peer_cookie;
+ socklen_t fd_peer_pidfd_len, peer_cookie_len;
+ static const struct sockaddr_un coredump_sk = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0linuxafsk/coredump.socket",
+ };
+ static const size_t coredump_sk_len =
+ offsetof(struct sockaddr_un, sun_path) +
+ sizeof("linuxafsk/coredump.socket"); /* +1 for leading NUL */
+
+ close(ipc_sockets[0]);
+
+ fd_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd_socket < 0)
+ _exit(EXIT_FAILURE);
+
+ ret = bind(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to bind coredump socket\n");
+ close(fd_socket);
+ close(ipc_sockets[1]);
+ _exit(EXIT_FAILURE);
+ }
+
+ ret = listen(fd_socket, 1);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to listen on coredump socket\n");
+ close(fd_socket);
+ close(ipc_sockets[1]);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
+ close(fd_socket);
+ close(ipc_sockets[1]);
+ _exit(EXIT_FAILURE);
+ }
+
+ close(ipc_sockets[1]);
+
+ fd_coredump = accept4(fd_socket, NULL, NULL, SOCK_CLOEXEC);
+ if (fd_coredump < 0) {
+ fprintf(stderr, "Failed to accept coredump socket connection\n");
+ close(fd_socket);
+ _exit(EXIT_FAILURE);
+ }
+
+ peer_cookie_len = sizeof(peer_cookie);
+ ret = getsockopt(fd_coredump, SOL_SOCKET, SO_COOKIE,
+ &peer_cookie, &peer_cookie_len);
+ if (ret < 0) {
+ fprintf(stderr, "%m - Failed to retrieve cookie for coredump socket connection\n");
+ close(fd_coredump);
+ close(fd_socket);
+ _exit(EXIT_FAILURE);
+ }
+
+ fd_peer_pidfd_len = sizeof(fd_peer_pidfd);
+ ret = getsockopt(fd_coredump, SOL_SOCKET, SO_PEERPIDFD,
+ &fd_peer_pidfd, &fd_peer_pidfd_len);
+ if (ret < 0) {
+ fprintf(stderr, "%m - Failed to retrieve peer pidfd for coredump socket connection\n");
+ close(fd_coredump);
+ close(fd_socket);
+ _exit(EXIT_FAILURE);
+ }
+
+ memset(&info, 0, sizeof(info));
+ info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
+ ret = ioctl(fd_peer_pidfd, PIDFD_GET_INFO, &info);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to retrieve pidfd info from peer pidfd for coredump socket connection\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (!(info.mask & PIDFD_INFO_COREDUMP)) {
+ fprintf(stderr, "Missing coredump information from coredumping task\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
+ fprintf(stderr, "Received connection from non-coredumping task\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (!info.coredump_cookie) {
+ fprintf(stderr, "Missing coredump cookie\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (info.coredump_cookie != peer_cookie) {
+ fprintf(stderr, "Mismatching coredump cookies\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ fd_core_file = creat("/tmp/coredump.file", 0644);
+ if (fd_core_file < 0) {
+ fprintf(stderr, "Failed to create coredump file\n");
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ _exit(EXIT_FAILURE);
+ }
+
+ for (;;) {
+ char buffer[4096];
+ ssize_t bytes_read, bytes_write;
+
+ bytes_read = read(fd_coredump, buffer, sizeof(buffer));
+ if (bytes_read < 0) {
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ close(fd_core_file);
+ _exit(EXIT_FAILURE);
+ }
+
+ if (bytes_read == 0)
+ break;
+
+ bytes_write = write(fd_core_file, buffer, bytes_read);
+ if (bytes_read != bytes_write) {
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ close(fd_core_file);
+ _exit(EXIT_FAILURE);
+ }
+ }
+
+ close(fd_coredump);
+ close(fd_socket);
+ close(fd_peer_pidfd);
+ close(fd_core_file);
+ _exit(EXIT_SUCCESS);
+ }
+ self->pid_coredump_server = pid_coredump_server;
+
+ EXPECT_EQ(close(ipc_sockets[1]), 0);
+ ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
+ EXPECT_EQ(close(ipc_sockets[0]), 0);
+
+ pid = fork();
+ ASSERT_GE(pid, 0);
+ if (pid == 0)
+ crashing_child();
+
+ pidfd = sys_pidfd_open(pid, 0);
+ ASSERT_GE(pidfd, 0);
+
+ waitpid(pid, &status, 0);
+ ASSERT_TRUE(WIFSIGNALED(status));
+ ASSERT_TRUE(WCOREDUMP(status));
+
+ info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
+ ASSERT_EQ(ioctl(pidfd, PIDFD_GET_INFO, &info), 0);
+ ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
+ ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
+
+ waitpid(pid_coredump_server, &status, 0);
+ self->pid_coredump_server = -ESRCH;
+ ASSERT_TRUE(WIFEXITED(status));
+ ASSERT_EQ(WEXITSTATUS(status), 0);
+
+ ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
+ ASSERT_GT(st.st_size, 0);
+ /*
+ * We should somehow validate the produced core file.
+ * For now just allow for visual inspection
+ */
+ system("file /tmp/coredump.file");
+}
+
+TEST_F(coredump, socket_econnrefused)
+{
+ int fd_socket;
+ static const struct sockaddr_un linuxafsk = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0linuxafsk/",
+ };
+ static const size_t linuxafsk_len =
+ offsetof(struct sockaddr_un, sun_path) +
+ sizeof("linuxafsk/"); /* +1 for leading NUL */
+
+ fd_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_GT(fd_socket, 0);
+
+ ASSERT_NE(bind(fd_socket, (const struct sockaddr *)&linuxafsk, linuxafsk_len), 0);
+ ASSERT_EQ(errno, ECONNREFUSED);
+ EXPECT_EQ(close(fd_socket), 0);
+}
+
+TEST_F(coredump, socket_econnrefused_privilege)
+{
+ int fd_socket;
+ static const struct sockaddr_un linuxafsk = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0linuxafsk/nope",
+ };
+ static const size_t linuxafsk_len =
+ offsetof(struct sockaddr_un, sun_path) +
+ sizeof("linuxafsk/nope"); /* +1 for leading NUL */
+
+ ASSERT_EQ(seteuid(1234), 0);
+
+ fd_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_GT(fd_socket, 0);
+
+ ASSERT_NE(bind(fd_socket, (const struct sockaddr *)&linuxafsk, linuxafsk_len), 0);
+ ASSERT_EQ(errno, ECONNREFUSED);
+ EXPECT_EQ(close(fd_socket), 0);
+
+ ASSERT_EQ(seteuid(0), 0);
+}
+
TEST_HARNESS_MAIN
--
2.47.2
prev parent reply other threads:[~2025-05-07 16:14 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-07 16:13 [PATCH v4 00/11] coredump: add coredump socket Christian Brauner
2025-05-07 16:13 ` [PATCH v4 01/11] coredump: massage format_corname() Christian Brauner
2025-05-07 16:13 ` [PATCH v4 02/11] coredump: massage do_coredump() Christian Brauner
2025-05-07 16:13 ` [PATCH v4 03/11] coredump: reflow dump helpers a little Christian Brauner
2025-05-07 16:13 ` [PATCH v4 04/11] net: reserve prefix Christian Brauner
2025-05-07 22:45 ` Kuniyuki Iwashima
2025-05-08 6:16 ` Christian Brauner
2025-05-08 21:47 ` Kuniyuki Iwashima
2025-05-09 5:54 ` Christian Brauner
2025-05-09 8:07 ` Daniel Borkmann
2025-05-07 16:13 ` [PATCH v4 05/11] coredump: add coredump socket Christian Brauner
2025-05-07 16:13 ` [PATCH v4 06/11] coredump: validate socket name as it is written Christian Brauner
2025-05-07 16:13 ` [PATCH v4 07/11] coredump: show supported coredump modes Christian Brauner
2025-05-07 16:13 ` [PATCH v4 08/11] pidfs, coredump: add PIDFD_INFO_COREDUMP Christian Brauner
2025-05-07 16:13 ` [PATCH v4 09/11] pidfs, coredump: allow to verify coredump connection Christian Brauner
2025-05-07 18:34 ` Mickaël Salaün
2025-05-07 16:13 ` [PATCH v4 10/11] selftests/pidfd: add PIDFD_INFO_COREDUMP infrastructure Christian Brauner
2025-05-07 16:13 ` Christian Brauner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250507-work-coredump-socket-v4-11-af0ef317b2d0@kernel.org \
--to=brauner@kernel.org \
--cc=alexander@mihalicyn.com \
--cc=bluca@debian.org \
--cc=daan.j.demeyer@gmail.com \
--cc=davem@davemloft.net \
--cc=david@readahead.eu \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jack@suse.cz \
--cc=jannh@google.com \
--cc=kuba@kernel.org \
--cc=kuniyu@amazon.com \
--cc=lennart@poettering.net \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=me@yhndnzj.com \
--cc=netdev@vger.kernel.org \
--cc=oleg@redhat.com \
--cc=pabeni@redhat.com \
--cc=viro@zeniv.linux.org.uk \
--cc=zbyszek@in.waw.pl \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.