File Index
Files and directories
Sign in
FILE

coredump_socket_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/coredump/coredump_socket_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2
  3#include <sys/stat.h>
  4#include <sys/epoll.h>
  5#include <sys/socket.h>
  6#include <sys/un.h>
  7
  8#include "coredump_test.h"
  9
 10FIXTURE_SETUP(coredump)
 11{
 12	FILE *file;
 13	int ret;
 14
 15	self->pid_coredump_server = -ESRCH;
 16	self->fd_tmpfs_detached = -1;
 17	file = fopen("/proc/sys/kernel/core_pattern", "r");
 18	ASSERT_NE(NULL, file);
 19
 20	ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file);
 21	ASSERT_TRUE(ret || feof(file));
 22	ASSERT_LT(ret, sizeof(self->original_core_pattern));
 23
 24	self->original_core_pattern[ret] = '\0';
 25	self->fd_tmpfs_detached = create_detached_tmpfs();
 26	ASSERT_GE(self->fd_tmpfs_detached, 0);
 27
 28	ret = fclose(file);
 29	ASSERT_EQ(0, ret);
 30}
 31
 32FIXTURE_TEARDOWN(coredump)
 33{
 34	const char *reason;
 35	FILE *file;
 36	int ret, status;
 37
 38	if (self->pid_coredump_server > 0) {
 39		kill(self->pid_coredump_server, SIGTERM);
 40		waitpid(self->pid_coredump_server, &status, 0);
 41	}
 42	unlink("/tmp/coredump.file");
 43	unlink("/tmp/coredump.socket");
 44
 45	file = fopen("/proc/sys/kernel/core_pattern", "w");
 46	if (!file) {
 47		reason = "Unable to open core_pattern";
 48		goto fail;
 49	}
 50
 51	ret = fprintf(file, "%s", self->original_core_pattern);
 52	if (ret < 0) {
 53		reason = "Unable to write to core_pattern";
 54		goto fail;
 55	}
 56
 57	ret = fclose(file);
 58	if (ret) {
 59		reason = "Unable to close core_pattern";
 60		goto fail;
 61	}
 62
 63	if (self->fd_tmpfs_detached >= 0) {
 64		ret = close(self->fd_tmpfs_detached);
 65		if (ret < 0) {
 66			reason = "Unable to close detached tmpfs";
 67			goto fail;
 68		}
 69		self->fd_tmpfs_detached = -1;
 70	}
 71
 72	return;
 73fail:
 74	/* This should never happen */
 75	fprintf(stderr, "Failed to cleanup coredump test: %s\n", reason);
 76}
 77
 78TEST_F(coredump, socket)
 79{
 80	int pidfd, ret, status;
 81	pid_t pid, pid_coredump_server;
 82	struct stat st;
 83	struct pidfd_info info = {};
 84	int ipc_sockets[2];
 85	char c;
 86
 87	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
 88
 89	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
 90	ASSERT_EQ(ret, 0);
 91
 92	pid_coredump_server = fork();
 93	ASSERT_GE(pid_coredump_server, 0);
 94	if (pid_coredump_server == 0) {
 95		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
 96		int exit_code = EXIT_FAILURE;
 97
 98		close(ipc_sockets[0]);
 99
100		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
101		if (fd_server < 0) {
102			fprintf(stderr, "socket test: create_and_listen_unix_socket failed: %m\n");
103			goto out;
104		}
105
106		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
107			fprintf(stderr, "socket test: write_nointr to ipc socket failed: %m\n");
108			goto out;
109		}
110
111		close(ipc_sockets[1]);
112
113		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
114		if (fd_coredump < 0) {
115			fprintf(stderr, "socket test: accept4 failed: %m\n");
116			goto out;
117		}
118
119		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
120		if (fd_peer_pidfd < 0) {
121			fprintf(stderr, "socket test: get_peer_pidfd failed\n");
122			goto out;
123		}
124
125		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
126			fprintf(stderr, "socket test: get_pidfd_info failed\n");
127			goto out;
128		}
129
130		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
131			fprintf(stderr, "socket test: PIDFD_INFO_COREDUMP not set in mask\n");
132			goto out;
133		}
134
135		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
136			fprintf(stderr, "socket test: PIDFD_COREDUMPED not set in coredump_mask\n");
137			goto out;
138		}
139
140		fd_core_file = creat("/tmp/coredump.file", 0644);
141		if (fd_core_file < 0) {
142			fprintf(stderr, "socket test: creat coredump file failed: %m\n");
143			goto out;
144		}
145
146		for (;;) {
147			char buffer[4096];
148			ssize_t bytes_read, bytes_write;
149
150			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
151			if (bytes_read < 0) {
152				fprintf(stderr, "socket test: read from coredump socket failed: %m\n");
153				goto out;
154			}
155
156			if (bytes_read == 0)
157				break;
158
159			bytes_write = write(fd_core_file, buffer, bytes_read);
160			if (bytes_read != bytes_write) {
161				if (bytes_write < 0 && errno == ENOSPC)
162					continue;
163				fprintf(stderr, "socket test: write to core file failed (read=%zd, write=%zd): %m\n", bytes_read, bytes_write);
164				goto out;
165			}
166		}
167
168		exit_code = EXIT_SUCCESS;
169		fprintf(stderr, "socket test: completed successfully\n");
170out:
171		if (fd_core_file >= 0)
172			close(fd_core_file);
173		if (fd_peer_pidfd >= 0)
174			close(fd_peer_pidfd);
175		if (fd_coredump >= 0)
176			close(fd_coredump);
177		if (fd_server >= 0)
178			close(fd_server);
179		_exit(exit_code);
180	}
181	self->pid_coredump_server = pid_coredump_server;
182
183	EXPECT_EQ(close(ipc_sockets[1]), 0);
184	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
185	EXPECT_EQ(close(ipc_sockets[0]), 0);
186
187	pid = fork();
188	ASSERT_GE(pid, 0);
189	if (pid == 0)
190		crashing_child();
191
192	pidfd = sys_pidfd_open(pid, 0);
193	ASSERT_GE(pidfd, 0);
194
195	waitpid(pid, &status, 0);
196	ASSERT_TRUE(WIFSIGNALED(status));
197	ASSERT_TRUE(WCOREDUMP(status));
198
199	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
200	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
201	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
202
203	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
204
205	ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
206	ASSERT_GT(st.st_size, 0);
207}
208
209TEST_F(coredump, socket_detect_userspace_client)
210{
211	int pidfd, ret, status;
212	pid_t pid, pid_coredump_server;
213	struct stat st;
214	struct pidfd_info info = {
215		.mask = PIDFD_INFO_COREDUMP,
216	};
217	int ipc_sockets[2];
218	char c;
219
220	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
221
222	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
223	ASSERT_EQ(ret, 0);
224
225	pid_coredump_server = fork();
226	ASSERT_GE(pid_coredump_server, 0);
227	if (pid_coredump_server == 0) {
228		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
229		int exit_code = EXIT_FAILURE;
230
231		close(ipc_sockets[0]);
232
233		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
234		if (fd_server < 0) {
235			fprintf(stderr, "socket_detect_userspace_client: create_and_listen_unix_socket failed: %m\n");
236			goto out;
237		}
238
239		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
240			fprintf(stderr, "socket_detect_userspace_client: write_nointr to ipc socket failed: %m\n");
241			goto out;
242		}
243
244		close(ipc_sockets[1]);
245
246		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
247		if (fd_coredump < 0) {
248			fprintf(stderr, "socket_detect_userspace_client: accept4 failed: %m\n");
249			goto out;
250		}
251
252		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
253		if (fd_peer_pidfd < 0) {
254			fprintf(stderr, "socket_detect_userspace_client: get_peer_pidfd failed\n");
255			goto out;
256		}
257
258		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
259			fprintf(stderr, "socket_detect_userspace_client: get_pidfd_info failed\n");
260			goto out;
261		}
262
263		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
264			fprintf(stderr, "socket_detect_userspace_client: PIDFD_INFO_COREDUMP not set in mask\n");
265			goto out;
266		}
267
268		if (info.coredump_mask & PIDFD_COREDUMPED) {
269			fprintf(stderr, "socket_detect_userspace_client: PIDFD_COREDUMPED incorrectly set (should be userspace client)\n");
270			goto out;
271		}
272
273		exit_code = EXIT_SUCCESS;
274		fprintf(stderr, "socket_detect_userspace_client: completed successfully\n");
275out:
276		if (fd_peer_pidfd >= 0)
277			close(fd_peer_pidfd);
278		if (fd_coredump >= 0)
279			close(fd_coredump);
280		if (fd_server >= 0)
281			close(fd_server);
282		_exit(exit_code);
283	}
284	self->pid_coredump_server = pid_coredump_server;
285
286	EXPECT_EQ(close(ipc_sockets[1]), 0);
287	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
288	EXPECT_EQ(close(ipc_sockets[0]), 0);
289
290	pid = fork();
291	ASSERT_GE(pid, 0);
292	if (pid == 0) {
293		int fd_socket;
294		ssize_t ret;
295		const struct sockaddr_un coredump_sk = {
296			.sun_family = AF_UNIX,
297			.sun_path = "/tmp/coredump.socket",
298		};
299		size_t coredump_sk_len =
300			offsetof(struct sockaddr_un, sun_path) +
301			sizeof("/tmp/coredump.socket");
302
303		fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
304		if (fd_socket < 0) {
305			fprintf(stderr, "socket_detect_userspace_client (client): socket failed: %m\n");
306			_exit(EXIT_FAILURE);
307		}
308
309		ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
310		if (ret < 0) {
311			fprintf(stderr, "socket_detect_userspace_client (client): connect failed: %m\n");
312			_exit(EXIT_FAILURE);
313		}
314
315		close(fd_socket);
316		pause();
317		fprintf(stderr, "socket_detect_userspace_client (client): completed successfully\n");
318		_exit(EXIT_SUCCESS);
319	}
320
321	pidfd = sys_pidfd_open(pid, 0);
322	ASSERT_GE(pidfd, 0);
323
324	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
325	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
326	ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0);
327
328	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
329
330	ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
331	ASSERT_EQ(close(pidfd), 0);
332
333	waitpid(pid, &status, 0);
334	ASSERT_TRUE(WIFSIGNALED(status));
335	ASSERT_EQ(WTERMSIG(status), SIGKILL);
336
337	ASSERT_NE(stat("/tmp/coredump.file", &st), 0);
338	ASSERT_EQ(errno, ENOENT);
339}
340
341TEST_F(coredump, socket_enoent)
342{
343	int pidfd, status;
344	pid_t pid;
345
346	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
347
348	pid = fork();
349	ASSERT_GE(pid, 0);
350	if (pid == 0)
351		crashing_child();
352
353	pidfd = sys_pidfd_open(pid, 0);
354	ASSERT_GE(pidfd, 0);
355
356	waitpid(pid, &status, 0);
357	ASSERT_TRUE(WIFSIGNALED(status));
358	ASSERT_FALSE(WCOREDUMP(status));
359}
360
361TEST_F(coredump, socket_no_listener)
362{
363	int pidfd, ret, status;
364	pid_t pid, pid_coredump_server;
365	int ipc_sockets[2];
366	char c;
367	const struct sockaddr_un coredump_sk = {
368		.sun_family = AF_UNIX,
369		.sun_path = "/tmp/coredump.socket",
370	};
371	size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) +
372				 sizeof("/tmp/coredump.socket");
373
374	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
375
376	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
377	ASSERT_EQ(ret, 0);
378
379	pid_coredump_server = fork();
380	ASSERT_GE(pid_coredump_server, 0);
381	if (pid_coredump_server == 0) {
382		int fd_server = -1;
383		int exit_code = EXIT_FAILURE;
384
385		close(ipc_sockets[0]);
386
387		fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
388		if (fd_server < 0) {
389			fprintf(stderr, "socket_no_listener: socket failed: %m\n");
390			goto out;
391		}
392
393		ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
394		if (ret < 0) {
395			fprintf(stderr, "socket_no_listener: bind failed: %m\n");
396			goto out;
397		}
398
399		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
400			fprintf(stderr, "socket_no_listener: write_nointr to ipc socket failed: %m\n");
401			goto out;
402		}
403
404		exit_code = EXIT_SUCCESS;
405		fprintf(stderr, "socket_no_listener: completed successfully\n");
406out:
407		if (fd_server >= 0)
408			close(fd_server);
409		close(ipc_sockets[1]);
410		_exit(exit_code);
411	}
412	self->pid_coredump_server = pid_coredump_server;
413
414	EXPECT_EQ(close(ipc_sockets[1]), 0);
415	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
416	EXPECT_EQ(close(ipc_sockets[0]), 0);
417
418	pid = fork();
419	ASSERT_GE(pid, 0);
420	if (pid == 0)
421		crashing_child();
422
423	pidfd = sys_pidfd_open(pid, 0);
424	ASSERT_GE(pidfd, 0);
425
426	waitpid(pid, &status, 0);
427	ASSERT_TRUE(WIFSIGNALED(status));
428	ASSERT_FALSE(WCOREDUMP(status));
429
430	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
431}
432
433/*
434 * Test: PIDFD_INFO_COREDUMP_SIGNAL via simple socket coredump
435 *
436 * Verify that when using simple socket-based coredump (@ pattern),
437 * the coredump_signal field is correctly exposed as SIGSEGV.
438 */
439TEST_F(coredump, socket_coredump_signal_sigsegv)
440{
441	int pidfd, ret, status;
442	pid_t pid, pid_coredump_server;
443	struct pidfd_info info = {};
444	int ipc_sockets[2];
445	char c;
446
447	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
448
449	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
450	ASSERT_EQ(ret, 0);
451
452	pid_coredump_server = fork();
453	ASSERT_GE(pid_coredump_server, 0);
454	if (pid_coredump_server == 0) {
455		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
456		int exit_code = EXIT_FAILURE;
457
458		close(ipc_sockets[0]);
459
460		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
461		if (fd_server < 0) {
462			fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
463			goto out;
464		}
465
466		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
467			fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
468			goto out;
469		}
470
471		close(ipc_sockets[1]);
472
473		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
474		if (fd_coredump < 0) {
475			fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
476			goto out;
477		}
478
479		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
480		if (fd_peer_pidfd < 0) {
481			fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
482			goto out;
483		}
484
485		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
486			fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
487			goto out;
488		}
489
490		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
491			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
492			goto out;
493		}
494
495		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
496			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
497			goto out;
498		}
499
500		/* Verify coredump_signal is available and correct */
501		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
502			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
503			goto out;
504		}
505
506		if (info.coredump_signal != SIGSEGV) {
507			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
508				info.coredump_signal, SIGSEGV);
509			goto out;
510		}
511
512		fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
513		if (fd_core_file < 0) {
514			fprintf(stderr, "socket_coredump_signal_sigsegv: open_coredump_tmpfile failed: %m\n");
515			goto out;
516		}
517
518		for (;;) {
519			char buffer[4096];
520			ssize_t bytes_read, bytes_write;
521
522			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
523			if (bytes_read < 0) {
524				fprintf(stderr, "socket_coredump_signal_sigsegv: read from coredump socket failed: %m\n");
525				goto out;
526			}
527
528			if (bytes_read == 0)
529				break;
530
531			bytes_write = write(fd_core_file, buffer, bytes_read);
532			if (bytes_read != bytes_write) {
533				fprintf(stderr, "socket_coredump_signal_sigsegv: write to core file failed (read=%zd, write=%zd): %m\n",
534					bytes_read, bytes_write);
535				goto out;
536			}
537		}
538
539		exit_code = EXIT_SUCCESS;
540		fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
541out:
542		if (fd_core_file >= 0)
543			close(fd_core_file);
544		if (fd_peer_pidfd >= 0)
545			close(fd_peer_pidfd);
546		if (fd_coredump >= 0)
547			close(fd_coredump);
548		if (fd_server >= 0)
549			close(fd_server);
550		_exit(exit_code);
551	}
552	self->pid_coredump_server = pid_coredump_server;
553
554	EXPECT_EQ(close(ipc_sockets[1]), 0);
555	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
556	EXPECT_EQ(close(ipc_sockets[0]), 0);
557
558	pid = fork();
559	ASSERT_GE(pid, 0);
560	if (pid == 0)
561		crashing_child();
562
563	pidfd = sys_pidfd_open(pid, 0);
564	ASSERT_GE(pidfd, 0);
565
566	waitpid(pid, &status, 0);
567	ASSERT_TRUE(WIFSIGNALED(status));
568	ASSERT_EQ(WTERMSIG(status), SIGSEGV);
569	ASSERT_TRUE(WCOREDUMP(status));
570
571	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
572	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
573	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
574	ASSERT_EQ(info.coredump_signal, SIGSEGV);
575
576	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
577}
578
579/*
580 * Test: PIDFD_INFO_COREDUMP_SIGNAL via simple socket coredump with SIGABRT
581 *
582 * Verify that when using simple socket-based coredump (@ pattern),
583 * the coredump_signal field is correctly exposed as SIGABRT.
584 */
585TEST_F(coredump, socket_coredump_signal_sigabrt)
586{
587	int pidfd, ret, status;
588	pid_t pid, pid_coredump_server;
589	struct pidfd_info info = {};
590	int ipc_sockets[2];
591	char c;
592
593	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
594
595	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
596	ASSERT_EQ(ret, 0);
597
598	pid_coredump_server = fork();
599	ASSERT_GE(pid_coredump_server, 0);
600	if (pid_coredump_server == 0) {
601		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
602		int exit_code = EXIT_FAILURE;
603
604		close(ipc_sockets[0]);
605
606		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
607		if (fd_server < 0) {
608			fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
609			goto out;
610		}
611
612		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
613			fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
614			goto out;
615		}
616
617		close(ipc_sockets[1]);
618
619		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
620		if (fd_coredump < 0) {
621			fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
622			goto out;
623		}
624
625		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
626		if (fd_peer_pidfd < 0) {
627			fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
628			goto out;
629		}
630
631		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
632			fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
633			goto out;
634		}
635
636		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
637			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
638			goto out;
639		}
640
641		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
642			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
643			goto out;
644		}
645
646		/* Verify coredump_signal is available and correct */
647		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
648			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
649			goto out;
650		}
651
652		if (info.coredump_signal != SIGABRT) {
653			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
654				info.coredump_signal, SIGABRT);
655			goto out;
656		}
657
658		fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
659		if (fd_core_file < 0) {
660			fprintf(stderr, "socket_coredump_signal_sigabrt: open_coredump_tmpfile failed: %m\n");
661			goto out;
662		}
663
664		for (;;) {
665			char buffer[4096];
666			ssize_t bytes_read, bytes_write;
667
668			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
669			if (bytes_read < 0) {
670				fprintf(stderr, "socket_coredump_signal_sigabrt: read from coredump socket failed: %m\n");
671				goto out;
672			}
673
674			if (bytes_read == 0)
675				break;
676
677			bytes_write = write(fd_core_file, buffer, bytes_read);
678			if (bytes_read != bytes_write) {
679				fprintf(stderr, "socket_coredump_signal_sigabrt: write to core file failed (read=%zd, write=%zd): %m\n",
680					bytes_read, bytes_write);
681				goto out;
682			}
683		}
684
685		exit_code = EXIT_SUCCESS;
686		fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
687out:
688		if (fd_core_file >= 0)
689			close(fd_core_file);
690		if (fd_peer_pidfd >= 0)
691			close(fd_peer_pidfd);
692		if (fd_coredump >= 0)
693			close(fd_coredump);
694		if (fd_server >= 0)
695			close(fd_server);
696		_exit(exit_code);
697	}
698	self->pid_coredump_server = pid_coredump_server;
699
700	EXPECT_EQ(close(ipc_sockets[1]), 0);
701	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
702	EXPECT_EQ(close(ipc_sockets[0]), 0);
703
704	pid = fork();
705	ASSERT_GE(pid, 0);
706	if (pid == 0)
707		abort();
708
709	pidfd = sys_pidfd_open(pid, 0);
710	ASSERT_GE(pidfd, 0);
711
712	waitpid(pid, &status, 0);
713	ASSERT_TRUE(WIFSIGNALED(status));
714	ASSERT_EQ(WTERMSIG(status), SIGABRT);
715	ASSERT_TRUE(WCOREDUMP(status));
716
717	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
718	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
719	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
720	ASSERT_EQ(info.coredump_signal, SIGABRT);
721
722	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
723}
724
725TEST_F(coredump, socket_invalid_paths)
726{
727	ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket"));
728	ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket"));
729	ASSERT_FALSE(set_core_pattern("@../coredump.socket"));
730	ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/.."));
731	ASSERT_FALSE(set_core_pattern("@.."));
732
733	ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket"));
734	ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket"));
735	ASSERT_FALSE(set_core_pattern("@@../coredump.socket"));
736	ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/.."));
737	ASSERT_FALSE(set_core_pattern("@@.."));
738
739	ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket"));
740}
741
742TEST_HARNESS_MAIN
~/ Read-only file preview.