xref: /linux/tools/testing/selftests/coredump/coredump_socket_test.c (revision 212c4053a1502e5117d8cbbbd1c15579ce1839bb)
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 
FIXTURE_SETUP(coredump)10 FIXTURE_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 
FIXTURE_TEARDOWN(coredump)32 FIXTURE_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;
73 fail:
74 	/* This should never happen */
75 	fprintf(stderr, "Failed to cleanup coredump test: %s\n", reason);
76 }
77 
TEST_F(coredump,socket)78 TEST_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");
170 out:
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 
TEST_F(coredump,socket_detect_userspace_client)209 TEST_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");
275 out:
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 
TEST_F(coredump,socket_enoent)341 TEST_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 
TEST_F(coredump,socket_no_listener)361 TEST_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");
406 out:
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  */
TEST_F(coredump,socket_coredump_signal_sigsegv)439 TEST_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");
541 out:
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  */
TEST_F(coredump,socket_coredump_signal_sigabrt)585 TEST_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");
687 out:
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 
TEST_F(coredump,socket_invalid_paths)725 TEST_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 
742 TEST_HARNESS_MAIN
743