xref: /linux/tools/testing/selftests/coredump/coredump_socket_test.c (revision 7aaa4915cb699378db1fa2a5c763ebea2caa35da)
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 
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 
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 
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 
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 
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 
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  * Also check that the coredump_code field is correctly exposed
439  * as SEGV_MAPERR.
440  */
441 TEST_F(coredump, socket_coredump_signal_sigsegv)
442 {
443 	int pidfd, ret, status;
444 	pid_t pid, pid_coredump_server;
445 	struct pidfd_info info = {};
446 	int ipc_sockets[2];
447 	char c;
448 
449 	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
450 
451 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
452 	ASSERT_EQ(ret, 0);
453 
454 	pid_coredump_server = fork();
455 	ASSERT_GE(pid_coredump_server, 0);
456 	if (pid_coredump_server == 0) {
457 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
458 		int exit_code = EXIT_FAILURE;
459 
460 		close(ipc_sockets[0]);
461 
462 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
463 		if (fd_server < 0) {
464 			fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
465 			goto out;
466 		}
467 
468 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
469 			fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
470 			goto out;
471 		}
472 
473 		close(ipc_sockets[1]);
474 
475 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
476 		if (fd_coredump < 0) {
477 			fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
478 			goto out;
479 		}
480 
481 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
482 		if (fd_peer_pidfd < 0) {
483 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
484 			goto out;
485 		}
486 
487 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
488 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
489 			goto out;
490 		}
491 
492 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
493 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
494 			goto out;
495 		}
496 
497 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
498 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
499 			goto out;
500 		}
501 
502 		/* Verify coredump_signal is available and correct */
503 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
504 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
505 			goto out;
506 		}
507 
508 		if (info.coredump_signal != SIGSEGV) {
509 			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
510 				info.coredump_signal, SIGSEGV);
511 			goto out;
512 		}
513 
514 		/* Verify coredump_code is available and correct */
515 		if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
516 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
517 			goto out;
518 		}
519 
520 		if (info.coredump_code != SEGV_MAPERR) {
521 			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_code=%d, expected SEGV_MAPERR=%d\n",
522 				info.coredump_code, SEGV_MAPERR);
523 			goto out;
524 		}
525 
526 		fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
527 		if (fd_core_file < 0) {
528 			fprintf(stderr, "socket_coredump_signal_sigsegv: open_coredump_tmpfile failed: %m\n");
529 			goto out;
530 		}
531 
532 		for (;;) {
533 			char buffer[4096];
534 			ssize_t bytes_read, bytes_write;
535 
536 			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
537 			if (bytes_read < 0) {
538 				fprintf(stderr, "socket_coredump_signal_sigsegv: read from coredump socket failed: %m\n");
539 				goto out;
540 			}
541 
542 			if (bytes_read == 0)
543 				break;
544 
545 			bytes_write = write(fd_core_file, buffer, bytes_read);
546 			if (bytes_read != bytes_write) {
547 				fprintf(stderr, "socket_coredump_signal_sigsegv: write to core file failed (read=%zd, write=%zd): %m\n",
548 					bytes_read, bytes_write);
549 				goto out;
550 			}
551 		}
552 
553 		exit_code = EXIT_SUCCESS;
554 		fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
555 out:
556 		if (fd_core_file >= 0)
557 			close(fd_core_file);
558 		if (fd_peer_pidfd >= 0)
559 			close(fd_peer_pidfd);
560 		if (fd_coredump >= 0)
561 			close(fd_coredump);
562 		if (fd_server >= 0)
563 			close(fd_server);
564 		_exit(exit_code);
565 	}
566 	self->pid_coredump_server = pid_coredump_server;
567 
568 	EXPECT_EQ(close(ipc_sockets[1]), 0);
569 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
570 	EXPECT_EQ(close(ipc_sockets[0]), 0);
571 
572 	pid = fork();
573 	ASSERT_GE(pid, 0);
574 	if (pid == 0)
575 		crashing_child();
576 
577 	pidfd = sys_pidfd_open(pid, 0);
578 	ASSERT_GE(pidfd, 0);
579 
580 	waitpid(pid, &status, 0);
581 	ASSERT_TRUE(WIFSIGNALED(status));
582 	ASSERT_EQ(WTERMSIG(status), SIGSEGV);
583 	ASSERT_TRUE(WCOREDUMP(status));
584 
585 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
586 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
587 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
588 	ASSERT_EQ(info.coredump_signal, SIGSEGV);
589 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
590 	ASSERT_EQ(info.coredump_code, SEGV_MAPERR);
591 
592 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
593 }
594 
595 /*
596  * Test: PIDFD_INFO_COREDUMP_SIGNAL via simple socket coredump with SIGABRT
597  *
598  * Verify that when using simple socket-based coredump (@ pattern),
599  * the coredump_signal field is correctly exposed as SIGABRT.
600  * Also check that the coredump_code field is correctly exposed
601  * as SI_TKILL.
602  */
603 TEST_F(coredump, socket_coredump_signal_sigabrt)
604 {
605 	int pidfd, ret, status;
606 	pid_t pid, pid_coredump_server;
607 	struct pidfd_info info = {};
608 	int ipc_sockets[2];
609 	char c;
610 
611 	ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
612 
613 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
614 	ASSERT_EQ(ret, 0);
615 
616 	pid_coredump_server = fork();
617 	ASSERT_GE(pid_coredump_server, 0);
618 	if (pid_coredump_server == 0) {
619 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
620 		int exit_code = EXIT_FAILURE;
621 
622 		close(ipc_sockets[0]);
623 
624 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
625 		if (fd_server < 0) {
626 			fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
627 			goto out;
628 		}
629 
630 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
631 			fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
632 			goto out;
633 		}
634 
635 		close(ipc_sockets[1]);
636 
637 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
638 		if (fd_coredump < 0) {
639 			fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
640 			goto out;
641 		}
642 
643 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
644 		if (fd_peer_pidfd < 0) {
645 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
646 			goto out;
647 		}
648 
649 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
650 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
651 			goto out;
652 		}
653 
654 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
655 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
656 			goto out;
657 		}
658 
659 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
660 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
661 			goto out;
662 		}
663 
664 		/* Verify coredump_signal is available and correct */
665 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
666 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
667 			goto out;
668 		}
669 
670 		if (info.coredump_signal != SIGABRT) {
671 			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
672 				info.coredump_signal, SIGABRT);
673 			goto out;
674 		}
675 
676 		/* Verify coredump_code is available and correct */
677 		if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
678 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
679 			goto out;
680 		}
681 
682 		if (info.coredump_code != SI_TKILL) {
683 			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_code=%d, expected SI_TKILL=%d\n",
684 				info.coredump_code, SI_TKILL);
685 			goto out;
686 		}
687 
688 		fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
689 		if (fd_core_file < 0) {
690 			fprintf(stderr, "socket_coredump_signal_sigabrt: open_coredump_tmpfile failed: %m\n");
691 			goto out;
692 		}
693 
694 		for (;;) {
695 			char buffer[4096];
696 			ssize_t bytes_read, bytes_write;
697 
698 			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
699 			if (bytes_read < 0) {
700 				fprintf(stderr, "socket_coredump_signal_sigabrt: read from coredump socket failed: %m\n");
701 				goto out;
702 			}
703 
704 			if (bytes_read == 0)
705 				break;
706 
707 			bytes_write = write(fd_core_file, buffer, bytes_read);
708 			if (bytes_read != bytes_write) {
709 				fprintf(stderr, "socket_coredump_signal_sigabrt: write to core file failed (read=%zd, write=%zd): %m\n",
710 					bytes_read, bytes_write);
711 				goto out;
712 			}
713 		}
714 
715 		exit_code = EXIT_SUCCESS;
716 		fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
717 out:
718 		if (fd_core_file >= 0)
719 			close(fd_core_file);
720 		if (fd_peer_pidfd >= 0)
721 			close(fd_peer_pidfd);
722 		if (fd_coredump >= 0)
723 			close(fd_coredump);
724 		if (fd_server >= 0)
725 			close(fd_server);
726 		_exit(exit_code);
727 	}
728 	self->pid_coredump_server = pid_coredump_server;
729 
730 	EXPECT_EQ(close(ipc_sockets[1]), 0);
731 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
732 	EXPECT_EQ(close(ipc_sockets[0]), 0);
733 
734 	pid = fork();
735 	ASSERT_GE(pid, 0);
736 	if (pid == 0)
737 		abort();
738 
739 	pidfd = sys_pidfd_open(pid, 0);
740 	ASSERT_GE(pidfd, 0);
741 
742 	waitpid(pid, &status, 0);
743 	ASSERT_TRUE(WIFSIGNALED(status));
744 	ASSERT_EQ(WTERMSIG(status), SIGABRT);
745 	ASSERT_TRUE(WCOREDUMP(status));
746 
747 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
748 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
749 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
750 	ASSERT_EQ(info.coredump_signal, SIGABRT);
751 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
752 	ASSERT_EQ(info.coredump_code, SI_TKILL);
753 
754 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
755 }
756 
757 TEST_F(coredump, socket_invalid_paths)
758 {
759 	ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket"));
760 	ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket"));
761 	ASSERT_FALSE(set_core_pattern("@../coredump.socket"));
762 	ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/.."));
763 	ASSERT_FALSE(set_core_pattern("@.."));
764 
765 	ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket"));
766 	ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket"));
767 	ASSERT_FALSE(set_core_pattern("@@../coredump.socket"));
768 	ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/.."));
769 	ASSERT_FALSE(set_core_pattern("@@.."));
770 
771 	ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket"));
772 }
773 
774 TEST_HARNESS_MAIN
775