xref: /linux/tools/testing/selftests/coredump/coredump_socket_protocol_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 #define NUM_CRASHING_COREDUMPS 5
11 
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 
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 
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 
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 
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 
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 
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 
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 
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  * Also check that the coredump_code field is correctly exposed
1008  * as SEGV_MAPERR.
1009  */
1010 TEST_F(coredump, socket_coredump_signal_sigsegv)
1011 {
1012 	int pidfd, ret, status;
1013 	pid_t pid, pid_coredump_server;
1014 	struct pidfd_info info = {};
1015 	int ipc_sockets[2];
1016 	char c;
1017 
1018 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1019 
1020 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1021 	ASSERT_EQ(ret, 0);
1022 
1023 	pid_coredump_server = fork();
1024 	ASSERT_GE(pid_coredump_server, 0);
1025 	if (pid_coredump_server == 0) {
1026 		struct coredump_req req = {};
1027 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1028 		int exit_code = EXIT_FAILURE;
1029 
1030 		close(ipc_sockets[0]);
1031 
1032 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1033 		if (fd_server < 0) {
1034 			fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
1035 			goto out;
1036 		}
1037 
1038 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1039 			fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
1040 			goto out;
1041 		}
1042 
1043 		close(ipc_sockets[1]);
1044 
1045 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1046 		if (fd_coredump < 0) {
1047 			fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
1048 			goto out;
1049 		}
1050 
1051 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1052 		if (fd_peer_pidfd < 0) {
1053 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
1054 			goto out;
1055 		}
1056 
1057 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1058 			fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
1059 			goto out;
1060 		}
1061 
1062 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1063 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
1064 			goto out;
1065 		}
1066 
1067 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1068 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
1069 			goto out;
1070 		}
1071 
1072 		/* Verify coredump_signal is available and correct */
1073 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1074 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1075 			goto out;
1076 		}
1077 
1078 		if (info.coredump_signal != SIGSEGV) {
1079 			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
1080 				info.coredump_signal, SIGSEGV);
1081 			goto out;
1082 		}
1083 
1084 		/* Verify coredump_code is available and correct */
1085 		if (!(info.mask & PIDFD_INFO_COREDUMP_CODE)) {
1086 			fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_CODE not set in mask\n");
1087 			goto out;
1088 		}
1089 
1090 		if (info.coredump_code != SEGV_MAPERR) {
1091 			fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_code=%d, expected SEGV_MAPERR=%d\n",
1092 				info.coredump_code, SEGV_MAPERR);
1093 			goto out;
1094 		}
1095 
1096 		if (!read_coredump_req(fd_coredump, &req)) {
1097 			fprintf(stderr, "socket_coredump_signal_sigsegv: read_coredump_req failed\n");
1098 			goto out;
1099 		}
1100 
1101 		if (!send_coredump_ack(fd_coredump, &req,
1102 				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1103 			fprintf(stderr, "socket_coredump_signal_sigsegv: send_coredump_ack failed\n");
1104 			goto out;
1105 		}
1106 
1107 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1108 			fprintf(stderr, "socket_coredump_signal_sigsegv: read_marker COREDUMP_MARK_REQACK failed\n");
1109 			goto out;
1110 		}
1111 
1112 		exit_code = EXIT_SUCCESS;
1113 		fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
1114 out:
1115 		if (fd_peer_pidfd >= 0)
1116 			close(fd_peer_pidfd);
1117 		if (fd_coredump >= 0)
1118 			close(fd_coredump);
1119 		if (fd_server >= 0)
1120 			close(fd_server);
1121 		_exit(exit_code);
1122 	}
1123 	self->pid_coredump_server = pid_coredump_server;
1124 
1125 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1126 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1127 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1128 
1129 	pid = fork();
1130 	ASSERT_GE(pid, 0);
1131 	if (pid == 0)
1132 		crashing_child();
1133 
1134 	pidfd = sys_pidfd_open(pid, 0);
1135 	ASSERT_GE(pidfd, 0);
1136 
1137 	waitpid(pid, &status, 0);
1138 	ASSERT_TRUE(WIFSIGNALED(status));
1139 	ASSERT_EQ(WTERMSIG(status), SIGSEGV);
1140 
1141 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1142 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1143 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1144 	ASSERT_EQ(info.coredump_signal, SIGSEGV);
1145 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
1146 	ASSERT_EQ(info.coredump_code, SEGV_MAPERR);
1147 
1148 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1149 }
1150 
1151 /*
1152  * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGABRT
1153  *
1154  * Verify that when using socket-based coredump protocol,
1155  * the coredump_signal field is correctly exposed as SIGABRT.
1156  * Also check that the coredump_code field is correctly exposed
1157  * as SI_TKILL.
1158  */
1159 TEST_F(coredump, socket_coredump_signal_sigabrt)
1160 {
1161 	int pidfd, ret, status;
1162 	pid_t pid, pid_coredump_server;
1163 	struct pidfd_info info = {};
1164 	int ipc_sockets[2];
1165 	char c;
1166 
1167 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1168 
1169 	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
1170 	ASSERT_EQ(ret, 0);
1171 
1172 	pid_coredump_server = fork();
1173 	ASSERT_GE(pid_coredump_server, 0);
1174 	if (pid_coredump_server == 0) {
1175 		struct coredump_req req = {};
1176 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
1177 		int exit_code = EXIT_FAILURE;
1178 
1179 		close(ipc_sockets[0]);
1180 
1181 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1182 		if (fd_server < 0) {
1183 			fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
1184 			goto out;
1185 		}
1186 
1187 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1188 			fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
1189 			goto out;
1190 		}
1191 
1192 		close(ipc_sockets[1]);
1193 
1194 		fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1195 		if (fd_coredump < 0) {
1196 			fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
1197 			goto out;
1198 		}
1199 
1200 		fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1201 		if (fd_peer_pidfd < 0) {
1202 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
1203 			goto out;
1204 		}
1205 
1206 		if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1207 			fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
1208 			goto out;
1209 		}
1210 
1211 		if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1212 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
1213 			goto out;
1214 		}
1215 
1216 		if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1217 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
1218 			goto out;
1219 		}
1220 
1221 		/* Verify coredump_signal is available and correct */
1222 		if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
1223 			fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
1224 			goto out;
1225 		}
1226 
1227 		if (info.coredump_signal != SIGABRT) {
1228 			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
1229 				info.coredump_signal, SIGABRT);
1230 			goto out;
1231 		}
1232 
1233 		if (info.coredump_code != SI_TKILL) {
1234 			fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_code=%d, expected SI_TKILL=%d\n",
1235 				info.coredump_code, SI_TKILL);
1236 			goto out;
1237 		}
1238 
1239 		if (!read_coredump_req(fd_coredump, &req)) {
1240 			fprintf(stderr, "socket_coredump_signal_sigabrt: read_coredump_req failed\n");
1241 			goto out;
1242 		}
1243 
1244 		if (!send_coredump_ack(fd_coredump, &req,
1245 				       COREDUMP_REJECT | COREDUMP_WAIT, 0)) {
1246 			fprintf(stderr, "socket_coredump_signal_sigabrt: send_coredump_ack failed\n");
1247 			goto out;
1248 		}
1249 
1250 		if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1251 			fprintf(stderr, "socket_coredump_signal_sigabrt: read_marker COREDUMP_MARK_REQACK failed\n");
1252 			goto out;
1253 		}
1254 
1255 		exit_code = EXIT_SUCCESS;
1256 		fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
1257 out:
1258 		if (fd_peer_pidfd >= 0)
1259 			close(fd_peer_pidfd);
1260 		if (fd_coredump >= 0)
1261 			close(fd_coredump);
1262 		if (fd_server >= 0)
1263 			close(fd_server);
1264 		_exit(exit_code);
1265 	}
1266 	self->pid_coredump_server = pid_coredump_server;
1267 
1268 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1269 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1270 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1271 
1272 	pid = fork();
1273 	ASSERT_GE(pid, 0);
1274 	if (pid == 0)
1275 		abort();
1276 
1277 	pidfd = sys_pidfd_open(pid, 0);
1278 	ASSERT_GE(pidfd, 0);
1279 
1280 	waitpid(pid, &status, 0);
1281 	ASSERT_TRUE(WIFSIGNALED(status));
1282 	ASSERT_EQ(WTERMSIG(status), SIGABRT);
1283 
1284 	ASSERT_TRUE(get_pidfd_info(pidfd, &info));
1285 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
1286 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
1287 	ASSERT_EQ(info.coredump_signal, SIGABRT);
1288 	ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_CODE));
1289 	ASSERT_EQ(info.coredump_code, SI_TKILL);
1290 
1291 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1292 }
1293 
1294 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500)
1295 {
1296 	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1297 	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server;
1298 	struct pidfd_info info = {};
1299 	int ipc_sockets[2];
1300 	char c;
1301 
1302 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1303 
1304 	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1305 
1306 	pid_coredump_server = fork();
1307 	ASSERT_GE(pid_coredump_server, 0);
1308 	if (pid_coredump_server == 0) {
1309 		int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1310 		int exit_code = EXIT_FAILURE;
1311 		struct coredump_req req = {};
1312 
1313 		close(ipc_sockets[0]);
1314 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1315 		if (fd_server < 0) {
1316 			fprintf(stderr, "Failed to create and listen on unix socket\n");
1317 			goto out;
1318 		}
1319 
1320 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1321 			fprintf(stderr, "Failed to notify parent via ipc socket\n");
1322 			goto out;
1323 		}
1324 		close(ipc_sockets[1]);
1325 
1326 		for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1327 			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1328 			if (fd_coredump < 0) {
1329 				fprintf(stderr, "accept4 failed: %m\n");
1330 				goto out;
1331 			}
1332 
1333 			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1334 			if (fd_peer_pidfd < 0) {
1335 				fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump);
1336 				goto out;
1337 			}
1338 
1339 			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1340 				fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd);
1341 				goto out;
1342 			}
1343 
1344 			if (!(info.mask & PIDFD_INFO_COREDUMP)) {
1345 				fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd);
1346 				goto out;
1347 			}
1348 			if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
1349 				fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd);
1350 				goto out;
1351 			}
1352 
1353 			if (!read_coredump_req(fd_coredump, &req)) {
1354 				fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump);
1355 				goto out;
1356 			}
1357 
1358 			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1359 						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1360 						COREDUMP_REJECT | COREDUMP_WAIT)) {
1361 				fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump);
1362 				goto out;
1363 			}
1364 
1365 			if (!send_coredump_ack(fd_coredump, &req,
1366 					       COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1367 				fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump);
1368 				goto out;
1369 			}
1370 
1371 			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1372 				fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump);
1373 				goto out;
1374 			}
1375 
1376 			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1377 			if (fd_core_file < 0) {
1378 				fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump);
1379 				goto out;
1380 			}
1381 
1382 			for (;;) {
1383 				char buffer[4096];
1384 				ssize_t bytes_read, bytes_write;
1385 
1386 				bytes_read = read(fd_coredump, buffer, sizeof(buffer));
1387 				if (bytes_read < 0) {
1388 					fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump);
1389 					goto out;
1390 				}
1391 
1392 				if (bytes_read == 0)
1393 					break;
1394 
1395 				bytes_write = write(fd_core_file, buffer, bytes_read);
1396 				if (bytes_read != bytes_write) {
1397 					if (bytes_write < 0 && errno == ENOSPC)
1398 						continue;
1399 					fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file);
1400 					goto out;
1401 				}
1402 			}
1403 
1404 			close(fd_core_file);
1405 			close(fd_peer_pidfd);
1406 			close(fd_coredump);
1407 			fd_peer_pidfd = -1;
1408 			fd_coredump = -1;
1409 		}
1410 
1411 		exit_code = EXIT_SUCCESS;
1412 out:
1413 		if (fd_core_file >= 0)
1414 			close(fd_core_file);
1415 		if (fd_peer_pidfd >= 0)
1416 			close(fd_peer_pidfd);
1417 		if (fd_coredump >= 0)
1418 			close(fd_coredump);
1419 		if (fd_server >= 0)
1420 			close(fd_server);
1421 		_exit(exit_code);
1422 	}
1423 	self->pid_coredump_server = pid_coredump_server;
1424 
1425 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1426 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1427 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1428 
1429 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1430 		pid[i] = fork();
1431 		ASSERT_GE(pid[i], 0);
1432 		if (pid[i] == 0)
1433 			crashing_child();
1434 		pidfd[i] = sys_pidfd_open(pid[i], 0);
1435 		ASSERT_GE(pidfd[i], 0);
1436 	}
1437 
1438 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1439 		waitpid(pid[i], &status[i], 0);
1440 		ASSERT_TRUE(WIFSIGNALED(status[i]));
1441 		ASSERT_TRUE(WCOREDUMP(status[i]));
1442 	}
1443 
1444 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1445 		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1446 		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1447 		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1448 		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1449 	}
1450 
1451 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1452 }
1453 
1454 TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500)
1455 {
1456 	int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS];
1457 	pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS];
1458 	struct pidfd_info info = {};
1459 	int ipc_sockets[2];
1460 	char c;
1461 
1462 	ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
1463 	ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
1464 
1465 	pid_coredump_server = fork();
1466 	ASSERT_GE(pid_coredump_server, 0);
1467 	if (pid_coredump_server == 0) {
1468 		int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0;
1469 		fd_server = -1;
1470 		exit_code = EXIT_FAILURE;
1471 		n_conns = 0;
1472 		close(ipc_sockets[0]);
1473 		fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
1474 		if (fd_server < 0) {
1475 			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: create_and_listen_unix_socket failed: %m\n");
1476 			goto out;
1477 		}
1478 
1479 		if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
1480 			fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: write_nointr to ipc socket failed: %m\n");
1481 			goto out;
1482 		}
1483 		close(ipc_sockets[1]);
1484 
1485 		while (n_conns < NUM_CRASHING_COREDUMPS) {
1486 			int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
1487 			struct coredump_req req = {};
1488 			fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
1489 			if (fd_coredump < 0) {
1490 				if (errno == EAGAIN || errno == EWOULDBLOCK)
1491 					continue;
1492 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: accept4 failed: %m\n");
1493 				goto out;
1494 			}
1495 			fd_peer_pidfd = get_peer_pidfd(fd_coredump);
1496 			if (fd_peer_pidfd < 0) {
1497 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_peer_pidfd failed\n");
1498 				goto out;
1499 			}
1500 			if (!get_pidfd_info(fd_peer_pidfd, &info)) {
1501 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: get_pidfd_info failed\n");
1502 				goto out;
1503 			}
1504 			if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) {
1505 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: missing PIDFD_INFO_COREDUMP or PIDFD_COREDUMPED\n");
1506 				goto out;
1507 			}
1508 			if (!read_coredump_req(fd_coredump, &req)) {
1509 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_coredump_req failed\n");
1510 				goto out;
1511 			}
1512 			if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0,
1513 						COREDUMP_KERNEL | COREDUMP_USERSPACE |
1514 						COREDUMP_REJECT | COREDUMP_WAIT)) {
1515 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: check_coredump_req failed\n");
1516 				goto out;
1517 			}
1518 			if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) {
1519 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: send_coredump_ack failed\n");
1520 				goto out;
1521 			}
1522 			if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) {
1523 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: read_marker failed\n");
1524 				goto out;
1525 			}
1526 			fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
1527 			if (fd_core_file < 0) {
1528 				fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: open_coredump_tmpfile failed: %m\n");
1529 				goto out;
1530 			}
1531 			pid_t worker = fork();
1532 			if (worker == 0) {
1533 				close(fd_server);
1534 				process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file);
1535 			}
1536 			worker_pids[n_conns] = worker;
1537 			if (fd_coredump >= 0)
1538 				close(fd_coredump);
1539 			if (fd_peer_pidfd >= 0)
1540 				close(fd_peer_pidfd);
1541 			if (fd_core_file >= 0)
1542 				close(fd_core_file);
1543 			n_conns++;
1544 		}
1545 		exit_code = EXIT_SUCCESS;
1546 out:
1547 		if (fd_server >= 0)
1548 			close(fd_server);
1549 
1550 		// Reap all worker processes
1551 		for (int i = 0; i < n_conns; i++) {
1552 			int wstatus;
1553 			if (waitpid(worker_pids[i], &wstatus, 0) < 0) {
1554 				fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]);
1555 			} else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) {
1556 				fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus));
1557 				exit_code = EXIT_FAILURE;
1558 			}
1559 		}
1560 
1561 		_exit(exit_code);
1562 	}
1563 	self->pid_coredump_server = pid_coredump_server;
1564 
1565 	EXPECT_EQ(close(ipc_sockets[1]), 0);
1566 	ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
1567 	EXPECT_EQ(close(ipc_sockets[0]), 0);
1568 
1569 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1570 		pid[i] = fork();
1571 		ASSERT_GE(pid[i], 0);
1572 		if (pid[i] == 0)
1573 			crashing_child();
1574 		pidfd[i] = sys_pidfd_open(pid[i], 0);
1575 		ASSERT_GE(pidfd[i], 0);
1576 	}
1577 
1578 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1579 		ASSERT_GE(waitpid(pid[i], &status[i], 0), 0);
1580 		ASSERT_TRUE(WIFSIGNALED(status[i]));
1581 		ASSERT_TRUE(WCOREDUMP(status[i]));
1582 	}
1583 
1584 	for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) {
1585 		info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP;
1586 		ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0);
1587 		ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
1588 		ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
1589 	}
1590 
1591 	wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
1592 }
1593 
1594 TEST_HARNESS_MAIN
1595