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