xref: /linux/tools/testing/selftests/coredump/coredump_socket_protocol_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 
10 #define NUM_CRASHING_COREDUMPS 5
11 
FIXTURE_SETUP(coredump)12 FIXTURE_SETUP(coredump)
13 {
14 	FILE *file;
15 	int ret;
16 
17 	self->pid_coredump_server = -ESRCH;
18 	self->fd_tmpfs_detached = -1;
19 	file = fopen("/proc/sys/kernel/core_pattern", "r");
20 	ASSERT_NE(NULL, file);
21 
22 	ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file);
23 	ASSERT_TRUE(ret || feof(file));
24 	ASSERT_LT(ret, sizeof(self->original_core_pattern));
25 
26 	self->original_core_pattern[ret] = '\0';
27 	self->fd_tmpfs_detached = create_detached_tmpfs();
28 	ASSERT_GE(self->fd_tmpfs_detached, 0);
29 
30 	ret = fclose(file);
31 	ASSERT_EQ(0, ret);
32 }
33 
FIXTURE_TEARDOWN(coredump)34 FIXTURE_TEARDOWN(coredump)
35 {
36 	const char *reason;
37 	FILE *file;
38 	int ret, status;
39 
40 	if (self->pid_coredump_server > 0) {
41 		kill(self->pid_coredump_server, SIGTERM);
42 		waitpid(self->pid_coredump_server, &status, 0);
43 	}
44 	unlink("/tmp/coredump.file");
45 	unlink("/tmp/coredump.socket");
46 
47 	file = fopen("/proc/sys/kernel/core_pattern", "w");
48 	if (!file) {
49 		reason = "Unable to open core_pattern";
50 		goto fail;
51 	}
52 
53 	ret = fprintf(file, "%s", self->original_core_pattern);
54 	if (ret < 0) {
55 		reason = "Unable to write to core_pattern";
56 		goto fail;
57 	}
58 
59 	ret = fclose(file);
60 	if (ret) {
61 		reason = "Unable to close core_pattern";
62 		goto fail;
63 	}
64 
65 	if (self->fd_tmpfs_detached >= 0) {
66 		ret = close(self->fd_tmpfs_detached);
67 		if (ret < 0) {
68 			reason = "Unable to close detached tmpfs";
69 			goto fail;
70 		}
71 		self->fd_tmpfs_detached = -1;
72 	}
73 
74 	return;
75 fail:
76 	/* This should never happen */
77 	fprintf(stderr, "Failed to cleanup coredump test: %s\n", reason);
78 }
79 
TEST_F(coredump,socket_request_kernel)80 TEST_F(coredump, socket_request_kernel)
81 {
82 	int pidfd, ret, status;
83 	pid_t pid, pid_coredump_server;
84 	struct stat st;
85 	struct pidfd_info info = {};
86 	int ipc_sockets[2];
87 	char c;
88 
89 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
90 
91 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
92 	ASSERT_EQ(ret, 0);
93 
94 	pid_coredump_server = fork();
95 	ASSERT_GE(pid_coredump_server, 0);
96 	if (pid_coredump_server == 0) {
97 		struct coredump_req req = {};
98 		int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1;
99 		int exit_code = EXIT_FAILURE;
100 
101 		close(ipc_sockets[0]);
102 
103 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
104 		if (fd_server < 0) {
105 			fprintf(stderr, "socket_request_kernel: create_and_listen_unix_socket failed: %m\n");
106 			goto out;
107 		}
108 
109 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
110 			fprintf(stderr, "socket_request_kernel: write_nointr to ipc socket failed: %m\n");
111 			goto out;
112 		}
113 
114 		close(ipc_sockets[1]);
115 
116 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
117 		if (fd_coredump < 0) {
118 			fprintf(stderr, "socket_request_kernel: accept4 failed: %m\n");
119 			goto out;
120 		}
121 
122 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
123 		if (fd_peer_pidfd < 0) {
124 			fprintf(stderr, "socket_request_kernel: get_peer_pidfd failed\n");
125 			goto out;
126 		}
127 
128 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
129 			fprintf(stderr, "socket_request_kernel: get_pidfd_info failed\n");
130 			goto out;
131 		}
132 
133 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
134 			fprintf(stderr, "socket_request_kernel: PIDFD_INFO_COREDUMP not set in mask\n");
135 			goto out;
136 		}
137 
138 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
139 			fprintf(stderr, "socket_request_kernel: PIDFD_COREDUMPED not set in coredump_mask\n");
140 			goto out;
141 		}
142 
143 		fd_core_file = creat("/tmp/coredump.file", 0644);
144 		if (fd_core_file < 0) {
145 			fprintf(stderr, "socket_request_kernel: creat coredump file failed: %m\n");
146 			goto out;
147 		}
148 
149 		if (!read_coredump_req(fd_coredump, &req)) {
150 			fprintf(stderr, "socket_request_kernel: read_coredump_req failed\n");
151 			goto out;
152 		}
153 
154 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
155 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
156 					COREDUMP_REJECT | COREDUMP_WAIT)) {
157 			fprintf(stderr, "socket_request_kernel: check_coredump_req failed\n");
158 			goto out;
159 		}
160 
161 		if (!send_coredump_ack(fd_coredump, &req,
162 				       COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
163 			fprintf(stderr, "socket_request_kernel: send_coredump_ack failed\n");
164 			goto out;
165 		}
166 
167 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
168 			fprintf(stderr, "socket_request_kernel: read_marker COREDUMP_MARK_REQACK failed\n");
169 			goto out;
170 		}
171 
172 		for (;;) {
173 			char buffer[4096];
174 			ssize_t bytes_read, bytes_write;
175 
176 			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
177 			if (bytes_read < 0) {
178 				fprintf(stderr, "socket_request_kernel: read from coredump socket failed: %m\n");
179 				goto out;
180 			}
181 
182 			if (bytes_read == 0)
183 				break;
184 
185 			bytes_write = write(fd_core_file, buffer, bytes_read);
186 			if (bytes_read != bytes_write) {
187 				if (bytes_write < 0 && errno == ENOSPC)
188 					continue;
189 				fprintf(stderr, "socket_request_kernel: write to core file failed (read=%zd, write=%zd): %m\n",
190 					bytes_read, bytes_write);
191 				goto out;
192 			}
193 		}
194 
195 		exit_code = EXIT_SUCCESS;
196 		fprintf(stderr, "socket_request_kernel: completed successfully\n");
197 out:
198 		if (fd_core_file >= 0)
199 			close(fd_core_file);
200 		if (fd_peer_pidfd >= 0)
201 			close(fd_peer_pidfd);
202 		if (fd_coredump >= 0)
203 			close(fd_coredump);
204 		if (fd_server >= 0)
205 			close(fd_server);
206 		_exit(exit_code);
207 	}
208 	self->pid_coredump_server = pid_coredump_server;
209 
210 	EXPECT_EQ(close(ipc_sockets[1]), 0);
211 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
212 	EXPECT_EQ(close(ipc_sockets[0]), 0);
213 
214 	pid = fork();
215 	ASSERT_GE(pid, 0);
216 	if (pid == 0)
217 		crashing_child();
218 
219 	pidfd = sys_pidfd_open(pid, 0);
220 	ASSERT_GE(pidfd, 0);
221 
222 	waitpid(pid, &status, 0);
223 	ASSERT_TRUE(WIFSIGNALED(status));
224 	ASSERT_TRUE(WCOREDUMP(status));
225 
226 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
227 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
228 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
229 
230 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
231 
232 	ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
233 	ASSERT_GT(st.st_size, 0);
234 	system("file /tmp/coredump.file");
235 }
236 
TEST_F(coredump,socket_request_userspace)237 TEST_F(coredump, socket_request_userspace)
238 {
239 	int pidfd, ret, status;
240 	pid_t pid, pid_coredump_server;
241 	struct pidfd_info info = {};
242 	int ipc_sockets[2];
243 	char c;
244 
245 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
246 
247 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
248 	ASSERT_EQ(ret, 0);
249 
250 	pid_coredump_server = fork();
251 	ASSERT_GE(pid_coredump_server, 0);
252 	if (pid_coredump_server == 0) {
253 		struct coredump_req req = {};
254 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
255 		int exit_code = EXIT_FAILURE;
256 
257 		close(ipc_sockets[0]);
258 
259 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
260 		if (fd_server < 0) {
261 			fprintf(stderr, "socket_request_userspace: create_and_listen_unix_socket failed: %m\n");
262 			goto out;
263 		}
264 
265 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
266 			fprintf(stderr, "socket_request_userspace: write_nointr to ipc socket failed: %m\n");
267 			goto out;
268 		}
269 
270 		close(ipc_sockets[1]);
271 
272 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
273 		if (fd_coredump < 0) {
274 			fprintf(stderr, "socket_request_userspace: accept4 failed: %m\n");
275 			goto out;
276 		}
277 
278 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
279 		if (fd_peer_pidfd < 0) {
280 			fprintf(stderr, "socket_request_userspace: get_peer_pidfd failed\n");
281 			goto out;
282 		}
283 
284 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
285 			fprintf(stderr, "socket_request_userspace: get_pidfd_info failed\n");
286 			goto out;
287 		}
288 
289 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
290 			fprintf(stderr, "socket_request_userspace: PIDFD_INFO_COREDUMP not set in mask\n");
291 			goto out;
292 		}
293 
294 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
295 			fprintf(stderr, "socket_request_userspace: PIDFD_COREDUMPED not set in coredump_mask\n");
296 			goto out;
297 		}
298 
299 		if (!read_coredump_req(fd_coredump, &req)) {
300 			fprintf(stderr, "socket_request_userspace: read_coredump_req failed\n");
301 			goto out;
302 		}
303 
304 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
305 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
306 					COREDUMP_REJECT | COREDUMP_WAIT)) {
307 			fprintf(stderr, "socket_request_userspace: check_coredump_req failed\n");
308 			goto out;
309 		}
310 
311 		if (!send_coredump_ack(fd_coredump, &req,
312 				       COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) {
313 			fprintf(stderr, "socket_request_userspace: send_coredump_ack failed\n");
314 			goto out;
315 		}
316 
317 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
318 			fprintf(stderr, "socket_request_userspace: read_marker COREDUMP_MARK_REQACK failed\n");
319 			goto out;
320 		}
321 
322 		for (;;) {
323 			char buffer[4096];
324 			ssize_t bytes_read;
325 
326 			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
327 			if (bytes_read > 0) {
328 				fprintf(stderr, "socket_request_userspace: unexpected data received (expected no coredump data)\n");
329 				goto out;
330 			}
331 
332 			if (bytes_read < 0) {
333 				fprintf(stderr, "socket_request_userspace: read from coredump socket failed: %m\n");
334 				goto out;
335 			}
336 
337 			if (bytes_read == 0)
338 				break;
339 		}
340 
341 		exit_code = EXIT_SUCCESS;
342 		fprintf(stderr, "socket_request_userspace: completed successfully\n");
343 out:
344 		if (fd_peer_pidfd >= 0)
345 			close(fd_peer_pidfd);
346 		if (fd_coredump >= 0)
347 			close(fd_coredump);
348 		if (fd_server >= 0)
349 			close(fd_server);
350 		_exit(exit_code);
351 	}
352 	self->pid_coredump_server = pid_coredump_server;
353 
354 	EXPECT_EQ(close(ipc_sockets[1]), 0);
355 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
356 	EXPECT_EQ(close(ipc_sockets[0]), 0);
357 
358 	pid = fork();
359 	ASSERT_GE(pid, 0);
360 	if (pid == 0)
361 		crashing_child();
362 
363 	pidfd = sys_pidfd_open(pid, 0);
364 	ASSERT_GE(pidfd, 0);
365 
366 	waitpid(pid, &status, 0);
367 	ASSERT_TRUE(WIFSIGNALED(status));
368 	ASSERT_TRUE(WCOREDUMP(status));
369 
370 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
371 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
372 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
373 
374 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
375 }
376 
TEST_F(coredump,socket_request_reject)377 TEST_F(coredump, socket_request_reject)
378 {
379 	int pidfd, ret, status;
380 	pid_t pid, pid_coredump_server;
381 	struct pidfd_info info = {};
382 	int ipc_sockets[2];
383 	char c;
384 
385 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
386 
387 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
388 	ASSERT_EQ(ret, 0);
389 
390 	pid_coredump_server = fork();
391 	ASSERT_GE(pid_coredump_server, 0);
392 	if (pid_coredump_server == 0) {
393 		struct coredump_req req = {};
394 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
395 		int exit_code = EXIT_FAILURE;
396 
397 		close(ipc_sockets[0]);
398 
399 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
400 		if (fd_server < 0) {
401 			fprintf(stderr, "socket_request_reject: create_and_listen_unix_socket failed: %m\n");
402 			goto out;
403 		}
404 
405 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
406 			fprintf(stderr, "socket_request_reject: write_nointr to ipc socket failed: %m\n");
407 			goto out;
408 		}
409 
410 		close(ipc_sockets[1]);
411 
412 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
413 		if (fd_coredump < 0) {
414 			fprintf(stderr, "socket_request_reject: accept4 failed: %m\n");
415 			goto out;
416 		}
417 
418 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
419 		if (fd_peer_pidfd < 0) {
420 			fprintf(stderr, "socket_request_reject: get_peer_pidfd failed\n");
421 			goto out;
422 		}
423 
424 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
425 			fprintf(stderr, "socket_request_reject: get_pidfd_info failed\n");
426 			goto out;
427 		}
428 
429 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
430 			fprintf(stderr, "socket_request_reject: PIDFD_INFO_COREDUMP not set in mask\n");
431 			goto out;
432 		}
433 
434 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
435 			fprintf(stderr, "socket_request_reject: PIDFD_COREDUMPED not set in coredump_mask\n");
436 			goto out;
437 		}
438 
439 		if (!read_coredump_req(fd_coredump, &req)) {
440 			fprintf(stderr, "socket_request_reject: read_coredump_req failed\n");
441 			goto out;
442 		}
443 
444 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
445 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
446 					COREDUMP_REJECT | COREDUMP_WAIT)) {
447 			fprintf(stderr, "socket_request_reject: check_coredump_req failed\n");
448 			goto out;
449 		}
450 
451 		if (!send_coredump_ack(fd_coredump, &req,
452 				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
453 			fprintf(stderr, "socket_request_reject: send_coredump_ack failed\n");
454 			goto out;
455 		}
456 
457 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
458 			fprintf(stderr, "socket_request_reject: read_marker COREDUMP_MARK_REQACK failed\n");
459 			goto out;
460 		}
461 
462 		for (;;) {
463 			char buffer[4096];
464 			ssize_t bytes_read;
465 
466 			bytes_read = read(fd_coredump, buffer, sizeof(buffer));
467 			if (bytes_read > 0) {
468 				fprintf(stderr, "socket_request_reject: unexpected data received (expected no coredump data for REJECT)\n");
469 				goto out;
470 			}
471 
472 			if (bytes_read < 0) {
473 				fprintf(stderr, "socket_request_reject: read from coredump socket failed: %m\n");
474 				goto out;
475 			}
476 
477 			if (bytes_read == 0)
478 				break;
479 		}
480 
481 		exit_code = EXIT_SUCCESS;
482 		fprintf(stderr, "socket_request_reject: completed successfully\n");
483 out:
484 		if (fd_peer_pidfd >= 0)
485 			close(fd_peer_pidfd);
486 		if (fd_coredump >= 0)
487 			close(fd_coredump);
488 		if (fd_server >= 0)
489 			close(fd_server);
490 		_exit(exit_code);
491 	}
492 	self->pid_coredump_server = pid_coredump_server;
493 
494 	EXPECT_EQ(close(ipc_sockets[1]), 0);
495 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
496 	EXPECT_EQ(close(ipc_sockets[0]), 0);
497 
498 	pid = fork();
499 	ASSERT_GE(pid, 0);
500 	if (pid == 0)
501 		crashing_child();
502 
503 	pidfd = sys_pidfd_open(pid, 0);
504 	ASSERT_GE(pidfd, 0);
505 
506 	waitpid(pid, &status, 0);
507 	ASSERT_TRUE(WIFSIGNALED(status));
508 	ASSERT_FALSE(WCOREDUMP(status));
509 
510 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
511 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
512 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
513 
514 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
515 }
516 
TEST_F(coredump,socket_request_invalid_flag_combination)517 TEST_F(coredump, socket_request_invalid_flag_combination)
518 {
519 	int pidfd, ret, status;
520 	pid_t pid, pid_coredump_server;
521 	struct pidfd_info info = {};
522 	int ipc_sockets[2];
523 	char c;
524 
525 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
526 
527 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
528 	ASSERT_EQ(ret, 0);
529 
530 	pid_coredump_server = fork();
531 	ASSERT_GE(pid_coredump_server, 0);
532 	if (pid_coredump_server == 0) {
533 		struct coredump_req req = {};
534 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
535 		int exit_code = EXIT_FAILURE;
536 
537 		close(ipc_sockets[0]);
538 
539 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
540 		if (fd_server < 0) {
541 			fprintf(stderr, "socket_request_invalid_flag_combination: create_and_listen_unix_socket failed: %m\n");
542 			goto out;
543 		}
544 
545 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
546 			fprintf(stderr, "socket_request_invalid_flag_combination: write_nointr to ipc socket failed: %m\n");
547 			goto out;
548 		}
549 
550 		close(ipc_sockets[1]);
551 
552 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
553 		if (fd_coredump < 0) {
554 			fprintf(stderr, "socket_request_invalid_flag_combination: accept4 failed: %m\n");
555 			goto out;
556 		}
557 
558 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
559 		if (fd_peer_pidfd < 0) {
560 			fprintf(stderr, "socket_request_invalid_flag_combination: get_peer_pidfd failed\n");
561 			goto out;
562 		}
563 
564 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
565 			fprintf(stderr, "socket_request_invalid_flag_combination: get_pidfd_info failed\n");
566 			goto out;
567 		}
568 
569 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
570 			fprintf(stderr, "socket_request_invalid_flag_combination: PIDFD_INFO_COREDUMP not set in mask\n");
571 			goto out;
572 		}
573 
574 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
575 			fprintf(stderr, "socket_request_invalid_flag_combination: PIDFD_COREDUMPED not set in coredump_mask\n");
576 			goto out;
577 		}
578 
579 		if (!read_coredump_req(fd_coredump, &req)) {
580 			fprintf(stderr, "socket_request_invalid_flag_combination: read_coredump_req failed\n");
581 			goto out;
582 		}
583 
584 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
585 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
586 					COREDUMP_REJECT | COREDUMP_WAIT)) {
587 			fprintf(stderr, "socket_request_invalid_flag_combination: check_coredump_req failed\n");
588 			goto out;
589 		}
590 
591 		if (!send_coredump_ack(fd_coredump, &req,
592 				       COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
593 			fprintf(stderr, "socket_request_invalid_flag_combination: send_coredump_ack failed\n");
594 			goto out;
595 		}
596 
597 		if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) {
598 			fprintf(stderr, "socket_request_invalid_flag_combination: read_marker COREDUMP_MARK_CONFLICTING failed\n");
599 			goto out;
600 		}
601 
602 		exit_code = EXIT_SUCCESS;
603 		fprintf(stderr, "socket_request_invalid_flag_combination: completed successfully\n");
604 out:
605 		if (fd_peer_pidfd >= 0)
606 			close(fd_peer_pidfd);
607 		if (fd_coredump >= 0)
608 			close(fd_coredump);
609 		if (fd_server >= 0)
610 			close(fd_server);
611 		_exit(exit_code);
612 	}
613 	self->pid_coredump_server = pid_coredump_server;
614 
615 	EXPECT_EQ(close(ipc_sockets[1]), 0);
616 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
617 	EXPECT_EQ(close(ipc_sockets[0]), 0);
618 
619 	pid = fork();
620 	ASSERT_GE(pid, 0);
621 	if (pid == 0)
622 		crashing_child();
623 
624 	pidfd = sys_pidfd_open(pid, 0);
625 	ASSERT_GE(pidfd, 0);
626 
627 	waitpid(pid, &status, 0);
628 	ASSERT_TRUE(WIFSIGNALED(status));
629 	ASSERT_FALSE(WCOREDUMP(status));
630 
631 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
632 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
633 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
634 
635 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
636 }
637 
TEST_F(coredump,socket_request_unknown_flag)638 TEST_F(coredump, socket_request_unknown_flag)
639 {
640 	int pidfd, ret, status;
641 	pid_t pid, pid_coredump_server;
642 	struct pidfd_info info = {};
643 	int ipc_sockets[2];
644 	char c;
645 
646 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
647 
648 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
649 	ASSERT_EQ(ret, 0);
650 
651 	pid_coredump_server = fork();
652 	ASSERT_GE(pid_coredump_server, 0);
653 	if (pid_coredump_server == 0) {
654 		struct coredump_req req = {};
655 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
656 		int exit_code = EXIT_FAILURE;
657 
658 		close(ipc_sockets[0]);
659 
660 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
661 		if (fd_server < 0) {
662 			fprintf(stderr, "socket_request_unknown_flag: create_and_listen_unix_socket failed: %m\n");
663 			goto out;
664 		}
665 
666 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
667 			fprintf(stderr, "socket_request_unknown_flag: write_nointr to ipc socket failed: %m\n");
668 			goto out;
669 		}
670 
671 		close(ipc_sockets[1]);
672 
673 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
674 		if (fd_coredump < 0) {
675 			fprintf(stderr, "socket_request_unknown_flag: accept4 failed: %m\n");
676 			goto out;
677 		}
678 
679 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
680 		if (fd_peer_pidfd < 0) {
681 			fprintf(stderr, "socket_request_unknown_flag: get_peer_pidfd failed\n");
682 			goto out;
683 		}
684 
685 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
686 			fprintf(stderr, "socket_request_unknown_flag: get_pidfd_info failed\n");
687 			goto out;
688 		}
689 
690 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
691 			fprintf(stderr, "socket_request_unknown_flag: PIDFD_INFO_COREDUMP not set in mask\n");
692 			goto out;
693 		}
694 
695 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
696 			fprintf(stderr, "socket_request_unknown_flag: PIDFD_COREDUMPED not set in coredump_mask\n");
697 			goto out;
698 		}
699 
700 		if (!read_coredump_req(fd_coredump, &req)) {
701 			fprintf(stderr, "socket_request_unknown_flag: read_coredump_req failed\n");
702 			goto out;
703 		}
704 
705 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
706 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
707 					COREDUMP_REJECT | COREDUMP_WAIT)) {
708 			fprintf(stderr, "socket_request_unknown_flag: check_coredump_req failed\n");
709 			goto out;
710 		}
711 
712 		if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) {
713 			fprintf(stderr, "socket_request_unknown_flag: send_coredump_ack failed\n");
714 			goto out;
715 		}
716 
717 		if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) {
718 			fprintf(stderr, "socket_request_unknown_flag: read_marker COREDUMP_MARK_UNSUPPORTED failed\n");
719 			goto out;
720 		}
721 
722 		exit_code = EXIT_SUCCESS;
723 		fprintf(stderr, "socket_request_unknown_flag: completed successfully\n");
724 out:
725 		if (fd_peer_pidfd >= 0)
726 			close(fd_peer_pidfd);
727 		if (fd_coredump >= 0)
728 			close(fd_coredump);
729 		if (fd_server >= 0)
730 			close(fd_server);
731 		_exit(exit_code);
732 	}
733 	self->pid_coredump_server = pid_coredump_server;
734 
735 	EXPECT_EQ(close(ipc_sockets[1]), 0);
736 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
737 	EXPECT_EQ(close(ipc_sockets[0]), 0);
738 
739 	pid = fork();
740 	ASSERT_GE(pid, 0);
741 	if (pid == 0)
742 		crashing_child();
743 
744 	pidfd = sys_pidfd_open(pid, 0);
745 	ASSERT_GE(pidfd, 0);
746 
747 	waitpid(pid, &status, 0);
748 	ASSERT_TRUE(WIFSIGNALED(status));
749 	ASSERT_FALSE(WCOREDUMP(status));
750 
751 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
752 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
753 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
754 
755 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
756 }
757 
TEST_F(coredump,socket_request_invalid_size_small)758 TEST_F(coredump, socket_request_invalid_size_small)
759 {
760 	int pidfd, ret, status;
761 	pid_t pid, pid_coredump_server;
762 	struct pidfd_info info = {};
763 	int ipc_sockets[2];
764 	char c;
765 
766 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
767 
768 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
769 	ASSERT_EQ(ret, 0);
770 
771 	pid_coredump_server = fork();
772 	ASSERT_GE(pid_coredump_server, 0);
773 	if (pid_coredump_server == 0) {
774 		struct coredump_req req = {};
775 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
776 		int exit_code = EXIT_FAILURE;
777 
778 		close(ipc_sockets[0]);
779 
780 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
781 		if (fd_server < 0) {
782 			fprintf(stderr, "socket_request_invalid_size_small: create_and_listen_unix_socket failed: %m\n");
783 			goto out;
784 		}
785 
786 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
787 			fprintf(stderr, "socket_request_invalid_size_small: write_nointr to ipc socket failed: %m\n");
788 			goto out;
789 		}
790 
791 		close(ipc_sockets[1]);
792 
793 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
794 		if (fd_coredump < 0) {
795 			fprintf(stderr, "socket_request_invalid_size_small: accept4 failed: %m\n");
796 			goto out;
797 		}
798 
799 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
800 		if (fd_peer_pidfd < 0) {
801 			fprintf(stderr, "socket_request_invalid_size_small: get_peer_pidfd failed\n");
802 			goto out;
803 		}
804 
805 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
806 			fprintf(stderr, "socket_request_invalid_size_small: get_pidfd_info failed\n");
807 			goto out;
808 		}
809 
810 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
811 			fprintf(stderr, "socket_request_invalid_size_small: PIDFD_INFO_COREDUMP not set in mask\n");
812 			goto out;
813 		}
814 
815 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
816 			fprintf(stderr, "socket_request_invalid_size_small: PIDFD_COREDUMPED not set in coredump_mask\n");
817 			goto out;
818 		}
819 
820 		if (!read_coredump_req(fd_coredump, &req)) {
821 			fprintf(stderr, "socket_request_invalid_size_small: read_coredump_req failed\n");
822 			goto out;
823 		}
824 
825 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
826 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
827 					COREDUMP_REJECT | COREDUMP_WAIT)) {
828 			fprintf(stderr, "socket_request_invalid_size_small: check_coredump_req failed\n");
829 			goto out;
830 		}
831 
832 		if (!send_coredump_ack(fd_coredump, &req,
833 				       COREDUMP_REJECT | COREDUMP_WAIT,
834 				       COREDUMP_ACK_SIZE_VER0 / 2)) {
835 			fprintf(stderr, "socket_request_invalid_size_small: send_coredump_ack failed\n");
836 			goto out;
837 		}
838 
839 		if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) {
840 			fprintf(stderr, "socket_request_invalid_size_small: read_marker COREDUMP_MARK_MINSIZE failed\n");
841 			goto out;
842 		}
843 
844 		exit_code = EXIT_SUCCESS;
845 		fprintf(stderr, "socket_request_invalid_size_small: completed successfully\n");
846 out:
847 		if (fd_peer_pidfd >= 0)
848 			close(fd_peer_pidfd);
849 		if (fd_coredump >= 0)
850 			close(fd_coredump);
851 		if (fd_server >= 0)
852 			close(fd_server);
853 		_exit(exit_code);
854 	}
855 	self->pid_coredump_server = pid_coredump_server;
856 
857 	EXPECT_EQ(close(ipc_sockets[1]), 0);
858 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
859 	EXPECT_EQ(close(ipc_sockets[0]), 0);
860 
861 	pid = fork();
862 	ASSERT_GE(pid, 0);
863 	if (pid == 0)
864 		crashing_child();
865 
866 	pidfd = sys_pidfd_open(pid, 0);
867 	ASSERT_GE(pidfd, 0);
868 
869 	waitpid(pid, &status, 0);
870 	ASSERT_TRUE(WIFSIGNALED(status));
871 	ASSERT_FALSE(WCOREDUMP(status));
872 
873 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
874 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
875 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
876 
877 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
878 }
879 
TEST_F(coredump,socket_request_invalid_size_large)880 TEST_F(coredump, socket_request_invalid_size_large)
881 {
882 	int pidfd, ret, status;
883 	pid_t pid, pid_coredump_server;
884 	struct pidfd_info info = {};
885 	int ipc_sockets[2];
886 	char c;
887 
888 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
889 
890 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
891 	ASSERT_EQ(ret, 0);
892 
893 	pid_coredump_server = fork();
894 	ASSERT_GE(pid_coredump_server, 0);
895 	if (pid_coredump_server == 0) {
896 		struct coredump_req req = {};
897 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
898 		int exit_code = EXIT_FAILURE;
899 
900 		close(ipc_sockets[0]);
901 
902 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
903 		if (fd_server < 0) {
904 			fprintf(stderr, "socket_request_invalid_size_large: create_and_listen_unix_socket failed: %m\n");
905 			goto out;
906 		}
907 
908 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
909 			fprintf(stderr, "socket_request_invalid_size_large: write_nointr to ipc socket failed: %m\n");
910 			goto out;
911 		}
912 
913 		close(ipc_sockets[1]);
914 
915 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
916 		if (fd_coredump < 0) {
917 			fprintf(stderr, "socket_request_invalid_size_large: accept4 failed: %m\n");
918 			goto out;
919 		}
920 
921 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
922 		if (fd_peer_pidfd < 0) {
923 			fprintf(stderr, "socket_request_invalid_size_large: get_peer_pidfd failed\n");
924 			goto out;
925 		}
926 
927 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
928 			fprintf(stderr, "socket_request_invalid_size_large: get_pidfd_info failed\n");
929 			goto out;
930 		}
931 
932 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
933 			fprintf(stderr, "socket_request_invalid_size_large: PIDFD_INFO_COREDUMP not set in mask\n");
934 			goto out;
935 		}
936 
937 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
938 			fprintf(stderr, "socket_request_invalid_size_large: PIDFD_COREDUMPED not set in coredump_mask\n");
939 			goto out;
940 		}
941 
942 		if (!read_coredump_req(fd_coredump, &req)) {
943 			fprintf(stderr, "socket_request_invalid_size_large: read_coredump_req failed\n");
944 			goto out;
945 		}
946 
947 		if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
948 					COREDUMP_KERNEL | COREDUMP_USERSPACE |
949 					COREDUMP_REJECT | COREDUMP_WAIT)) {
950 			fprintf(stderr, "socket_request_invalid_size_large: check_coredump_req failed\n");
951 			goto out;
952 		}
953 
954 		if (!send_coredump_ack(fd_coredump, &req,
955 				       COREDUMP_REJECT | COREDUMP_WAIT,
956 				       COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) {
957 			fprintf(stderr, "socket_request_invalid_size_large: send_coredump_ack failed\n");
958 			goto out;
959 		}
960 
961 		if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) {
962 			fprintf(stderr, "socket_request_invalid_size_large: read_marker COREDUMP_MARK_MAXSIZE failed\n");
963 			goto out;
964 		}
965 
966 		exit_code = EXIT_SUCCESS;
967 		fprintf(stderr, "socket_request_invalid_size_large: completed successfully\n");
968 out:
969 		if (fd_peer_pidfd >= 0)
970 			close(fd_peer_pidfd);
971 		if (fd_coredump >= 0)
972 			close(fd_coredump);
973 		if (fd_server >= 0)
974 			close(fd_server);
975 		_exit(exit_code);
976 	}
977 	self->pid_coredump_server = pid_coredump_server;
978 
979 	EXPECT_EQ(close(ipc_sockets[1]), 0);
980 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
981 	EXPECT_EQ(close(ipc_sockets[0]), 0);
982 
983 	pid = fork();
984 	ASSERT_GE(pid, 0);
985 	if (pid == 0)
986 		crashing_child();
987 
988 	pidfd = sys_pidfd_open(pid, 0);
989 	ASSERT_GE(pidfd, 0);
990 
991 	waitpid(pid, &status, 0);
992 	ASSERT_TRUE(WIFSIGNALED(status));
993 	ASSERT_FALSE(WCOREDUMP(status));
994 
995 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
996 	ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
997 	ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
998 
999 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1000 }
1001 
1002 /*
1003  * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGSEGV
1004  *
1005  * Verify that when using socket-based coredump protocol,
1006  * the coredump_signal field is correctly exposed as SIGSEGV.
1007  */
TEST_F(coredump,socket_coredump_signal_sigsegv)1008 TEST_F(coredump, socket_coredump_signal_sigsegv)
1009 {
1010 	int pidfd, ret, status;
1011 	pid_t pid, pid_coredump_server;
1012 	struct pidfd_info info = {};
1013 	int ipc_sockets[2];
1014 	char c;
1015 
1016 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1017 
1018 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1019 	ASSERT_EQ(ret, 0);
1020 
1021 	pid_coredump_server = fork();
1022 	ASSERT_GE(pid_coredump_server, 0);
1023 	if (pid_coredump_server == 0) {
1024 		struct coredump_req req = {};
1025 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1026 		int exit_code = EXIT_FAILURE;
1027 
1028 		close(ipc_sockets[0]);
1029 
1030 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1031 		if (fd_server < 0) {
1032 			fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
1033 			goto out;
1034 		}
1035 
1036 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1037 			fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
1038 			goto out;
1039 		}
1040 
1041 		close(ipc_sockets[1]);
1042 
1043 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1044 		if (fd_coredump < 0) {
1045 			fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
1046 			goto out;
1047 		}
1048 
1049 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1050 		if (fd_peer_pidfd < 0) {
1051 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
1052 			goto out;
1053 		}
1054 
1055 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1056 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
1057 			goto out;
1058 		}
1059 
1060 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1061 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
1062 			goto out;
1063 		}
1064 
1065 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1066 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
1067 			goto out;
1068 		}
1069 
1070 		/* Verify coredump_signal is available and correct */
1071 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1072 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1073 			goto out;
1074 		}
1075 
1076 		if (info.coredump_signal != SIGSEGV) {
1077 			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
1078 				info.coredump_signal, SIGSEGV);
1079 			goto out;
1080 		}
1081 
1082 		if (!read_coredump_req(fd_coredump, &req)) {
1083 			fprintf(stderr, "socket_coredump_signal_sigsegv: read_coredump_req failed\n");
1084 			goto out;
1085 		}
1086 
1087 		if (!send_coredump_ack(fd_coredump, &req,
1088 				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1089 			fprintf(stderr, "socket_coredump_signal_sigsegv: send_coredump_ack failed\n");
1090 			goto out;
1091 		}
1092 
1093 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1094 			fprintf(stderr, "socket_coredump_signal_sigsegv: read_marker COREDUMP_MARK_REQACK failed\n");
1095 			goto out;
1096 		}
1097 
1098 		exit_code = EXIT_SUCCESS;
1099 		fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
1100 out:
1101 		if (fd_peer_pidfd >= 0)
1102 			close(fd_peer_pidfd);
1103 		if (fd_coredump >= 0)
1104 			close(fd_coredump);
1105 		if (fd_server >= 0)
1106 			close(fd_server);
1107 		_exit(exit_code);
1108 	}
1109 	self->pid_coredump_server = pid_coredump_server;
1110 
1111 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1112 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1113 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1114 
1115 	pid = fork();
1116 	ASSERT_GE(pid, 0);
1117 	if (pid == 0)
1118 		crashing_child();
1119 
1120 	pidfd = sys_pidfd_open(pid, 0);
1121 	ASSERT_GE(pidfd, 0);
1122 
1123 	waitpid(pid, &status, 0);
1124 	ASSERT_TRUE(WIFSIGNALED(status));
1125 	ASSERT_EQ(WTERMSIG(status), SIGSEGV);
1126 
1127 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1128 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1129 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1130 	ASSERT_EQ(info.coredump_signal, SIGSEGV);
1131 
1132 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1133 }
1134 
1135 /*
1136  * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGABRT
1137  *
1138  * Verify that when using socket-based coredump protocol,
1139  * the coredump_signal field is correctly exposed as SIGABRT.
1140  */
TEST_F(coredump,socket_coredump_signal_sigabrt)1141 TEST_F(coredump, socket_coredump_signal_sigabrt)
1142 {
1143 	int pidfd, ret, status;
1144 	pid_t pid, pid_coredump_server;
1145 	struct pidfd_info info = {};
1146 	int ipc_sockets[2];
1147 	char c;
1148 
1149 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1150 
1151 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1152 	ASSERT_EQ(ret, 0);
1153 
1154 	pid_coredump_server = fork();
1155 	ASSERT_GE(pid_coredump_server, 0);
1156 	if (pid_coredump_server == 0) {
1157 		struct coredump_req req = {};
1158 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1159 		int exit_code = EXIT_FAILURE;
1160 
1161 		close(ipc_sockets[0]);
1162 
1163 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1164 		if (fd_server < 0) {
1165 			fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
1166 			goto out;
1167 		}
1168 
1169 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1170 			fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
1171 			goto out;
1172 		}
1173 
1174 		close(ipc_sockets[1]);
1175 
1176 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1177 		if (fd_coredump < 0) {
1178 			fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
1179 			goto out;
1180 		}
1181 
1182 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1183 		if (fd_peer_pidfd < 0) {
1184 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
1185 			goto out;
1186 		}
1187 
1188 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1189 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
1190 			goto out;
1191 		}
1192 
1193 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1194 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
1195 			goto out;
1196 		}
1197 
1198 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1199 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
1200 			goto out;
1201 		}
1202 
1203 		/* Verify coredump_signal is available and correct */
1204 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1205 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1206 			goto out;
1207 		}
1208 
1209 		if (info.coredump_signal != SIGABRT) {
1210 			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
1211 				info.coredump_signal, SIGABRT);
1212 			goto out;
1213 		}
1214 
1215 		if (!read_coredump_req(fd_coredump, &req)) {
1216 			fprintf(stderr, "socket_coredump_signal_sigabrt: read_coredump_req failed\n");
1217 			goto out;
1218 		}
1219 
1220 		if (!send_coredump_ack(fd_coredump, &req,
1221 				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1222 			fprintf(stderr, "socket_coredump_signal_sigabrt: send_coredump_ack failed\n");
1223 			goto out;
1224 		}
1225 
1226 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1227 			fprintf(stderr, "socket_coredump_signal_sigabrt: read_marker COREDUMP_MARK_REQACK failed\n");
1228 			goto out;
1229 		}
1230 
1231 		exit_code = EXIT_SUCCESS;
1232 		fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
1233 out:
1234 		if (fd_peer_pidfd >= 0)
1235 			close(fd_peer_pidfd);
1236 		if (fd_coredump >= 0)
1237 			close(fd_coredump);
1238 		if (fd_server >= 0)
1239 			close(fd_server);
1240 		_exit(exit_code);
1241 	}
1242 	self->pid_coredump_server = pid_coredump_server;
1243 
1244 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1245 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1246 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1247 
1248 	pid = fork();
1249 	ASSERT_GE(pid, 0);
1250 	if (pid == 0)
1251 		abort();
1252 
1253 	pidfd = sys_pidfd_open(pid, 0);
1254 	ASSERT_GE(pidfd, 0);
1255 
1256 	waitpid(pid, &status, 0);
1257 	ASSERT_TRUE(WIFSIGNALED(status));
1258 	ASSERT_EQ(WTERMSIG(status), SIGABRT);
1259 
1260 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1261 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1262 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1263 	ASSERT_EQ(info.coredump_signal, SIGABRT);
1264 
1265 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1266 }
1267 
1268 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500)
1269 {
1270 	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1271 	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server;
1272 	struct pidfd_info info = {};
1273 	int ipc_sockets[2];
1274 	char c;
1275 
1276 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1277 
1278 	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1279 
1280 	pid_coredump_server = fork();
1281 	ASSERT_GE(pid_coredump_server, 0);
1282 	if (pid_coredump_server == 0) {
1283 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1284 		int exit_code = EXIT_FAILURE;
1285 		struct coredump_req req = {};
1286 
1287 		close(ipc_sockets[0]);
1288 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1289 		if (fd_server < 0) {
1290 			fprintf(stderr, "Failed to create and listen on unix socket\n");
1291 			goto out;
1292 		}
1293 
1294 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1295 			fprintf(stderr, "Failed to notify parent via ipc socket\n");
1296 			goto out;
1297 		}
1298 		close(ipc_sockets[1]);
1299 
1300 		for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1301 			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1302 			if (fd_coredump < 0) {
1303 				fprintf(stderr, "accept4 failed: %m\n");
1304 				goto out;
1305 			}
1306 
1307 			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1308 			if (fd_peer_pidfd < 0) {
1309 				fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump);
1310 				goto out;
1311 			}
1312 
1313 			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1314 				fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd);
1315 				goto out;
1316 			}
1317 
1318 			if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1319 				fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd);
1320 				goto out;
1321 			}
1322 			if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1323 				fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd);
1324 				goto out;
1325 			}
1326 
1327 			if (!read_coredump_req(fd_coredump, &req)) {
1328 				fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump);
1329 				goto out;
1330 			}
1331 
1332 			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1333 						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1334 						COREDUMP_REJECT | COREDUMP_WAIT)) {
1335 				fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump);
1336 				goto out;
1337 			}
1338 
1339 			if (!send_coredump_ack(fd_coredump, &req,
1340 					       COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1341 				fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump);
1342 				goto out;
1343 			}
1344 
1345 			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1346 				fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump);
1347 				goto out;
1348 			}
1349 
1350 			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1351 			if (fd_core_file < 0) {
1352 				fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump);
1353 				goto out;
1354 			}
1355 
1356 			for (;;) {
1357 				char buffer[4096];
1358 				ssize_t bytes_read, bytes_write;
1359 
1360 				bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1361 				if (bytes_read < 0) {
1362 					fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump);
1363 					goto out;
1364 				}
1365 
1366 				if (bytes_read == 0)
1367 					break;
1368 
1369 				bytes_write = write(fd_core_file, buffer, bytes_read);
1370 				if (bytes_read != bytes_write) {
1371 					if (bytes_write < 0 && errno == ENOSPC)
1372 						continue;
1373 					fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file);
1374 					goto out;
1375 				}
1376 			}
1377 
1378 			close(fd_core_file);
1379 			close(fd_peer_pidfd);
1380 			close(fd_coredump);
1381 			fd_peer_pidfd = -1;
1382 			fd_coredump = -1;
1383 		}
1384 
1385 		exit_code = EXIT_SUCCESS;
1386 out:
1387 		if (fd_core_file >= 0)
1388 			close(fd_core_file);
1389 		if (fd_peer_pidfd >= 0)
1390 			close(fd_peer_pidfd);
1391 		if (fd_coredump >= 0)
1392 			close(fd_coredump);
1393 		if (fd_server >= 0)
1394 			close(fd_server);
1395 		_exit(exit_code);
1396 	}
1397 	self->pid_coredump_server = pid_coredump_server;
1398 
1399 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1400 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1401 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1402 
1403 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1404 		pid[i] = fork();
1405 		ASSERT_GE(pid[i], 0);
1406 		if (pid[i] == 0)
1407 			crashing_child();
1408 		pidfd[i] = sys_pidfd_open(pid[i], 0);
1409 		ASSERT_GE(pidfd[i], 0);
1410 	}
1411 
1412 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1413 		waitpid(pid[i], &status[i], 0);
1414 		ASSERT_TRUE(WIFSIGNALED(status[i]));
1415 		ASSERT_TRUE(WCOREDUMP(status[i]));
1416 	}
1417 
1418 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1419 		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1420 		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1421 		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1422 		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1423 	}
1424 
1425 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1426 }
1427 
1428 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500)
1429 {
1430 	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1431 	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS];
1432 	struct pidfd_info info = {};
1433 	int ipc_sockets[2];
1434 	char c;
1435 
1436 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1437 	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1438 
1439 	pid_coredump_server = fork();
1440 	ASSERT_GE(pid_coredump_server, 0);
1441 	if (pid_coredump_server == 0) {
1442 		int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0;
1443 		fd_server = -1;
1444 		exit_code = EXIT_FAILURE;
1445 		n_conns = 0;
1446 		close(ipc_sockets[0]);
1447 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1448 		if (fd_server < 0) {
1449 			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: create_and_listen_unix_socket failed: %m\n");
1450 			goto out;
1451 		}
1452 
1453 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1454 			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: write_nointr to ipc socket failed: %m\n");
1455 			goto out;
1456 		}
1457 		close(ipc_sockets[1]);
1458 
1459 		while (n_conns < NUM_CRASHING_COREDUMPS) {
1460 			int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1461 			struct coredump_req req = {};
1462 			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1463 			if (fd_coredump < 0) {
1464 				if (errno == EAGAIN || errno == EWOULDBLOCK)
1465 					continue;
1466 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: accept4 failed: %m\n");
1467 				goto out;
1468 			}
1469 			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1470 			if (fd_peer_pidfd < 0) {
1471 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_peer_pidfd failed\n");
1472 				goto out;
1473 			}
1474 			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1475 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_pidfd_info failed\n");
1476 				goto out;
1477 			}
1478 			if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) {
1479 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: missing PIDFD_INFO_COREDUMP or PIDFD_COREDUMPED\n");
1480 				goto out;
1481 			}
1482 			if (!read_coredump_req(fd_coredump, &req)) {
1483 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_coredump_req failed\n");
1484 				goto out;
1485 			}
1486 			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1487 						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1488 						COREDUMP_REJECT | COREDUMP_WAIT)) {
1489 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: check_coredump_req failed\n");
1490 				goto out;
1491 			}
1492 			if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1493 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: send_coredump_ack failed\n");
1494 				goto out;
1495 			}
1496 			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1497 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_marker failed\n");
1498 				goto out;
1499 			}
1500 			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1501 			if (fd_core_file < 0) {
1502 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: open_coredump_tmpfile failed: %m\n");
1503 				goto out;
1504 			}
1505 			pid_t worker = fork();
1506 			if (worker == 0) {
1507 				close(fd_server);
1508 				process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file);
1509 			}
1510 			worker_pids[n_conns] = worker;
1511 			if (fd_coredump >= 0)
1512 				close(fd_coredump);
1513 			if (fd_peer_pidfd >= 0)
1514 				close(fd_peer_pidfd);
1515 			if (fd_core_file >= 0)
1516 				close(fd_core_file);
1517 			n_conns++;
1518 		}
1519 		exit_code = EXIT_SUCCESS;
1520 out:
1521 		if (fd_server >= 0)
1522 			close(fd_server);
1523 
1524 		// Reap all worker processes
1525 		for (int i = 0; i < n_conns; i++) {
1526 			int wstatus;
1527 			if (waitpid(worker_pids[i], &wstatus, 0) < 0) {
1528 				fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]);
1529 			} else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) {
1530 				fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus));
1531 				exit_code = EXIT_FAILURE;
1532 			}
1533 		}
1534 
1535 		_exit(exit_code);
1536 	}
1537 	self->pid_coredump_server = pid_coredump_server;
1538 
1539 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1540 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1541 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1542 
1543 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1544 		pid[i] = fork();
1545 		ASSERT_GE(pid[i], 0);
1546 		if (pid[i] == 0)
1547 			crashing_child();
1548 		pidfd[i] = sys_pidfd_open(pid[i], 0);
1549 		ASSERT_GE(pidfd[i], 0);
1550 	}
1551 
1552 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1553 		ASSERT_GE(waitpid(pid[i], &status[i], 0), 0);
1554 		ASSERT_TRUE(WIFSIGNALED(status[i]));
1555 		ASSERT_TRUE(WCOREDUMP(status[i]));
1556 	}
1557 
1558 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1559 		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1560 		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1561 		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1562 		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1563 	}
1564 
1565 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1566 }
1567 
1568 TEST_HARNESS_MAIN
1569