1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <sys/stat.h>
4 #include <sys/epoll.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7
8 #include "coredump_test.h"
9
FIXTURE_SETUP(coredump)10 FIXTURE_SETUP(coredump)
11 {
12 FILE *file;
13 int ret;
14
15 self->pid_coredump_server = -ESRCH;
16 self->fd_tmpfs_detached = -1;
17 file = fopen("/proc/sys/kernel/core_pattern", "r");
18 ASSERT_NE(NULL, file);
19
20 ret = fread(self->original_core_pattern, 1, sizeof(self->original_core_pattern), file);
21 ASSERT_TRUE(ret || feof(file));
22 ASSERT_LT(ret, sizeof(self->original_core_pattern));
23
24 self->original_core_pattern[ret] = '\0';
25 self->fd_tmpfs_detached = create_detached_tmpfs();
26 ASSERT_GE(self->fd_tmpfs_detached, 0);
27
28 ret = fclose(file);
29 ASSERT_EQ(0, ret);
30 }
31
FIXTURE_TEARDOWN(coredump)32 FIXTURE_TEARDOWN(coredump)
33 {
34 const char *reason;
35 FILE *file;
36 int ret, status;
37
38 if (self->pid_coredump_server > 0) {
39 kill(self->pid_coredump_server, SIGTERM);
40 waitpid(self->pid_coredump_server, &status, 0);
41 }
42 unlink("/tmp/coredump.file");
43 unlink("/tmp/coredump.socket");
44
45 file = fopen("/proc/sys/kernel/core_pattern", "w");
46 if (!file) {
47 reason = "Unable to open core_pattern";
48 goto fail;
49 }
50
51 ret = fprintf(file, "%s", self->original_core_pattern);
52 if (ret < 0) {
53 reason = "Unable to write to core_pattern";
54 goto fail;
55 }
56
57 ret = fclose(file);
58 if (ret) {
59 reason = "Unable to close core_pattern";
60 goto fail;
61 }
62
63 if (self->fd_tmpfs_detached >= 0) {
64 ret = close(self->fd_tmpfs_detached);
65 if (ret < 0) {
66 reason = "Unable to close detached tmpfs";
67 goto fail;
68 }
69 self->fd_tmpfs_detached = -1;
70 }
71
72 return;
73 fail:
74 /* This should never happen */
75 fprintf(stderr, "Failed to cleanup coredump test: %s\n", reason);
76 }
77
TEST_F(coredump,socket)78 TEST_F(coredump, socket)
79 {
80 int pidfd, ret, status;
81 pid_t pid, pid_coredump_server;
82 struct stat st;
83 struct pidfd_info info = {};
84 int ipc_sockets[2];
85 char c;
86
87 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
88
89 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
90 ASSERT_EQ(ret, 0);
91
92 pid_coredump_server = fork();
93 ASSERT_GE(pid_coredump_server, 0);
94 if (pid_coredump_server == 0) {
95 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
96 int exit_code = EXIT_FAILURE;
97
98 close(ipc_sockets[0]);
99
100 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
101 if (fd_server < 0) {
102 fprintf(stderr, "socket test: create_and_listen_unix_socket failed: %m\n");
103 goto out;
104 }
105
106 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
107 fprintf(stderr, "socket test: write_nointr to ipc socket failed: %m\n");
108 goto out;
109 }
110
111 close(ipc_sockets[1]);
112
113 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
114 if (fd_coredump < 0) {
115 fprintf(stderr, "socket test: accept4 failed: %m\n");
116 goto out;
117 }
118
119 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
120 if (fd_peer_pidfd < 0) {
121 fprintf(stderr, "socket test: get_peer_pidfd failed\n");
122 goto out;
123 }
124
125 if (!get_pidfd_info(fd_peer_pidfd, &info)) {
126 fprintf(stderr, "socket test: get_pidfd_info failed\n");
127 goto out;
128 }
129
130 if (!(info.mask & PIDFD_INFO_COREDUMP)) {
131 fprintf(stderr, "socket test: PIDFD_INFO_COREDUMP not set in mask\n");
132 goto out;
133 }
134
135 if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
136 fprintf(stderr, "socket test: PIDFD_COREDUMPED not set in coredump_mask\n");
137 goto out;
138 }
139
140 fd_core_file = creat("/tmp/coredump.file", 0644);
141 if (fd_core_file < 0) {
142 fprintf(stderr, "socket test: creat coredump file failed: %m\n");
143 goto out;
144 }
145
146 for (;;) {
147 char buffer[4096];
148 ssize_t bytes_read, bytes_write;
149
150 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
151 if (bytes_read < 0) {
152 fprintf(stderr, "socket test: read from coredump socket failed: %m\n");
153 goto out;
154 }
155
156 if (bytes_read == 0)
157 break;
158
159 bytes_write = write(fd_core_file, buffer, bytes_read);
160 if (bytes_read != bytes_write) {
161 if (bytes_write < 0 && errno == ENOSPC)
162 continue;
163 fprintf(stderr, "socket test: write to core file failed (read=%zd, write=%zd): %m\n", bytes_read, bytes_write);
164 goto out;
165 }
166 }
167
168 exit_code = EXIT_SUCCESS;
169 fprintf(stderr, "socket test: completed successfully\n");
170 out:
171 if (fd_core_file >= 0)
172 close(fd_core_file);
173 if (fd_peer_pidfd >= 0)
174 close(fd_peer_pidfd);
175 if (fd_coredump >= 0)
176 close(fd_coredump);
177 if (fd_server >= 0)
178 close(fd_server);
179 _exit(exit_code);
180 }
181 self->pid_coredump_server = pid_coredump_server;
182
183 EXPECT_EQ(close(ipc_sockets[1]), 0);
184 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
185 EXPECT_EQ(close(ipc_sockets[0]), 0);
186
187 pid = fork();
188 ASSERT_GE(pid, 0);
189 if (pid == 0)
190 crashing_child();
191
192 pidfd = sys_pidfd_open(pid, 0);
193 ASSERT_GE(pidfd, 0);
194
195 waitpid(pid, &status, 0);
196 ASSERT_TRUE(WIFSIGNALED(status));
197 ASSERT_TRUE(WCOREDUMP(status));
198
199 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
200 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
201 ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
202
203 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
204
205 ASSERT_EQ(stat("/tmp/coredump.file", &st), 0);
206 ASSERT_GT(st.st_size, 0);
207 }
208
TEST_F(coredump,socket_detect_userspace_client)209 TEST_F(coredump, socket_detect_userspace_client)
210 {
211 int pidfd, ret, status;
212 pid_t pid, pid_coredump_server;
213 struct stat st;
214 struct pidfd_info info = {
215 .mask = PIDFD_INFO_COREDUMP,
216 };
217 int ipc_sockets[2];
218 char c;
219
220 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
221
222 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
223 ASSERT_EQ(ret, 0);
224
225 pid_coredump_server = fork();
226 ASSERT_GE(pid_coredump_server, 0);
227 if (pid_coredump_server == 0) {
228 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
229 int exit_code = EXIT_FAILURE;
230
231 close(ipc_sockets[0]);
232
233 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
234 if (fd_server < 0) {
235 fprintf(stderr, "socket_detect_userspace_client: create_and_listen_unix_socket failed: %m\n");
236 goto out;
237 }
238
239 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
240 fprintf(stderr, "socket_detect_userspace_client: write_nointr to ipc socket failed: %m\n");
241 goto out;
242 }
243
244 close(ipc_sockets[1]);
245
246 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
247 if (fd_coredump < 0) {
248 fprintf(stderr, "socket_detect_userspace_client: accept4 failed: %m\n");
249 goto out;
250 }
251
252 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
253 if (fd_peer_pidfd < 0) {
254 fprintf(stderr, "socket_detect_userspace_client: get_peer_pidfd failed\n");
255 goto out;
256 }
257
258 if (!get_pidfd_info(fd_peer_pidfd, &info)) {
259 fprintf(stderr, "socket_detect_userspace_client: get_pidfd_info failed\n");
260 goto out;
261 }
262
263 if (!(info.mask & PIDFD_INFO_COREDUMP)) {
264 fprintf(stderr, "socket_detect_userspace_client: PIDFD_INFO_COREDUMP not set in mask\n");
265 goto out;
266 }
267
268 if (info.coredump_mask & PIDFD_COREDUMPED) {
269 fprintf(stderr, "socket_detect_userspace_client: PIDFD_COREDUMPED incorrectly set (should be userspace client)\n");
270 goto out;
271 }
272
273 exit_code = EXIT_SUCCESS;
274 fprintf(stderr, "socket_detect_userspace_client: completed successfully\n");
275 out:
276 if (fd_peer_pidfd >= 0)
277 close(fd_peer_pidfd);
278 if (fd_coredump >= 0)
279 close(fd_coredump);
280 if (fd_server >= 0)
281 close(fd_server);
282 _exit(exit_code);
283 }
284 self->pid_coredump_server = pid_coredump_server;
285
286 EXPECT_EQ(close(ipc_sockets[1]), 0);
287 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
288 EXPECT_EQ(close(ipc_sockets[0]), 0);
289
290 pid = fork();
291 ASSERT_GE(pid, 0);
292 if (pid == 0) {
293 int fd_socket;
294 ssize_t ret;
295 const struct sockaddr_un coredump_sk = {
296 .sun_family = AF_UNIX,
297 .sun_path = "/tmp/coredump.socket",
298 };
299 size_t coredump_sk_len =
300 offsetof(struct sockaddr_un, sun_path) +
301 sizeof("/tmp/coredump.socket");
302
303 fd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
304 if (fd_socket < 0) {
305 fprintf(stderr, "socket_detect_userspace_client (client): socket failed: %m\n");
306 _exit(EXIT_FAILURE);
307 }
308
309 ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
310 if (ret < 0) {
311 fprintf(stderr, "socket_detect_userspace_client (client): connect failed: %m\n");
312 _exit(EXIT_FAILURE);
313 }
314
315 close(fd_socket);
316 pause();
317 fprintf(stderr, "socket_detect_userspace_client (client): completed successfully\n");
318 _exit(EXIT_SUCCESS);
319 }
320
321 pidfd = sys_pidfd_open(pid, 0);
322 ASSERT_GE(pidfd, 0);
323
324 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
325 ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
326 ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0);
327
328 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
329
330 ASSERT_EQ(sys_pidfd_send_signal(pidfd, SIGKILL, NULL, 0), 0);
331 ASSERT_EQ(close(pidfd), 0);
332
333 waitpid(pid, &status, 0);
334 ASSERT_TRUE(WIFSIGNALED(status));
335 ASSERT_EQ(WTERMSIG(status), SIGKILL);
336
337 ASSERT_NE(stat("/tmp/coredump.file", &st), 0);
338 ASSERT_EQ(errno, ENOENT);
339 }
340
TEST_F(coredump,socket_enoent)341 TEST_F(coredump, socket_enoent)
342 {
343 int pidfd, status;
344 pid_t pid;
345
346 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
347
348 pid = fork();
349 ASSERT_GE(pid, 0);
350 if (pid == 0)
351 crashing_child();
352
353 pidfd = sys_pidfd_open(pid, 0);
354 ASSERT_GE(pidfd, 0);
355
356 waitpid(pid, &status, 0);
357 ASSERT_TRUE(WIFSIGNALED(status));
358 ASSERT_FALSE(WCOREDUMP(status));
359 }
360
TEST_F(coredump,socket_no_listener)361 TEST_F(coredump, socket_no_listener)
362 {
363 int pidfd, ret, status;
364 pid_t pid, pid_coredump_server;
365 int ipc_sockets[2];
366 char c;
367 const struct sockaddr_un coredump_sk = {
368 .sun_family = AF_UNIX,
369 .sun_path = "/tmp/coredump.socket",
370 };
371 size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) +
372 sizeof("/tmp/coredump.socket");
373
374 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
375
376 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
377 ASSERT_EQ(ret, 0);
378
379 pid_coredump_server = fork();
380 ASSERT_GE(pid_coredump_server, 0);
381 if (pid_coredump_server == 0) {
382 int fd_server = -1;
383 int exit_code = EXIT_FAILURE;
384
385 close(ipc_sockets[0]);
386
387 fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
388 if (fd_server < 0) {
389 fprintf(stderr, "socket_no_listener: socket failed: %m\n");
390 goto out;
391 }
392
393 ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len);
394 if (ret < 0) {
395 fprintf(stderr, "socket_no_listener: bind failed: %m\n");
396 goto out;
397 }
398
399 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
400 fprintf(stderr, "socket_no_listener: write_nointr to ipc socket failed: %m\n");
401 goto out;
402 }
403
404 exit_code = EXIT_SUCCESS;
405 fprintf(stderr, "socket_no_listener: completed successfully\n");
406 out:
407 if (fd_server >= 0)
408 close(fd_server);
409 close(ipc_sockets[1]);
410 _exit(exit_code);
411 }
412 self->pid_coredump_server = pid_coredump_server;
413
414 EXPECT_EQ(close(ipc_sockets[1]), 0);
415 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
416 EXPECT_EQ(close(ipc_sockets[0]), 0);
417
418 pid = fork();
419 ASSERT_GE(pid, 0);
420 if (pid == 0)
421 crashing_child();
422
423 pidfd = sys_pidfd_open(pid, 0);
424 ASSERT_GE(pidfd, 0);
425
426 waitpid(pid, &status, 0);
427 ASSERT_TRUE(WIFSIGNALED(status));
428 ASSERT_FALSE(WCOREDUMP(status));
429
430 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
431 }
432
433 /*
434 * Test: PIDFD_INFO_COREDUMP_SIGNAL via simple socket coredump
435 *
436 * Verify that when using simple socket-based coredump (@ pattern),
437 * the coredump_signal field is correctly exposed as SIGSEGV.
438 */
TEST_F(coredump,socket_coredump_signal_sigsegv)439 TEST_F(coredump, socket_coredump_signal_sigsegv)
440 {
441 int pidfd, ret, status;
442 pid_t pid, pid_coredump_server;
443 struct pidfd_info info = {};
444 int ipc_sockets[2];
445 char c;
446
447 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
448
449 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
450 ASSERT_EQ(ret, 0);
451
452 pid_coredump_server = fork();
453 ASSERT_GE(pid_coredump_server, 0);
454 if (pid_coredump_server == 0) {
455 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
456 int exit_code = EXIT_FAILURE;
457
458 close(ipc_sockets[0]);
459
460 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
461 if (fd_server < 0) {
462 fprintf(stderr, "socket_coredump_signal_sigsegv: create_and_listen_unix_socket failed: %m\n");
463 goto out;
464 }
465
466 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
467 fprintf(stderr, "socket_coredump_signal_sigsegv: write_nointr to ipc socket failed: %m\n");
468 goto out;
469 }
470
471 close(ipc_sockets[1]);
472
473 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
474 if (fd_coredump < 0) {
475 fprintf(stderr, "socket_coredump_signal_sigsegv: accept4 failed: %m\n");
476 goto out;
477 }
478
479 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
480 if (fd_peer_pidfd < 0) {
481 fprintf(stderr, "socket_coredump_signal_sigsegv: get_peer_pidfd failed\n");
482 goto out;
483 }
484
485 if (!get_pidfd_info(fd_peer_pidfd, &info)) {
486 fprintf(stderr, "socket_coredump_signal_sigsegv: get_pidfd_info failed\n");
487 goto out;
488 }
489
490 if (!(info.mask & PIDFD_INFO_COREDUMP)) {
491 fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP not set in mask\n");
492 goto out;
493 }
494
495 if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
496 fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_COREDUMPED not set in coredump_mask\n");
497 goto out;
498 }
499
500 /* Verify coredump_signal is available and correct */
501 if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
502 fprintf(stderr, "socket_coredump_signal_sigsegv: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
503 goto out;
504 }
505
506 if (info.coredump_signal != SIGSEGV) {
507 fprintf(stderr, "socket_coredump_signal_sigsegv: coredump_signal=%d, expected SIGSEGV=%d\n",
508 info.coredump_signal, SIGSEGV);
509 goto out;
510 }
511
512 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
513 if (fd_core_file < 0) {
514 fprintf(stderr, "socket_coredump_signal_sigsegv: open_coredump_tmpfile failed: %m\n");
515 goto out;
516 }
517
518 for (;;) {
519 char buffer[4096];
520 ssize_t bytes_read, bytes_write;
521
522 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
523 if (bytes_read < 0) {
524 fprintf(stderr, "socket_coredump_signal_sigsegv: read from coredump socket failed: %m\n");
525 goto out;
526 }
527
528 if (bytes_read == 0)
529 break;
530
531 bytes_write = write(fd_core_file, buffer, bytes_read);
532 if (bytes_read != bytes_write) {
533 fprintf(stderr, "socket_coredump_signal_sigsegv: write to core file failed (read=%zd, write=%zd): %m\n",
534 bytes_read, bytes_write);
535 goto out;
536 }
537 }
538
539 exit_code = EXIT_SUCCESS;
540 fprintf(stderr, "socket_coredump_signal_sigsegv: completed successfully\n");
541 out:
542 if (fd_core_file >= 0)
543 close(fd_core_file);
544 if (fd_peer_pidfd >= 0)
545 close(fd_peer_pidfd);
546 if (fd_coredump >= 0)
547 close(fd_coredump);
548 if (fd_server >= 0)
549 close(fd_server);
550 _exit(exit_code);
551 }
552 self->pid_coredump_server = pid_coredump_server;
553
554 EXPECT_EQ(close(ipc_sockets[1]), 0);
555 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
556 EXPECT_EQ(close(ipc_sockets[0]), 0);
557
558 pid = fork();
559 ASSERT_GE(pid, 0);
560 if (pid == 0)
561 crashing_child();
562
563 pidfd = sys_pidfd_open(pid, 0);
564 ASSERT_GE(pidfd, 0);
565
566 waitpid(pid, &status, 0);
567 ASSERT_TRUE(WIFSIGNALED(status));
568 ASSERT_EQ(WTERMSIG(status), SIGSEGV);
569 ASSERT_TRUE(WCOREDUMP(status));
570
571 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
572 ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
573 ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
574 ASSERT_EQ(info.coredump_signal, SIGSEGV);
575
576 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
577 }
578
579 /*
580 * Test: PIDFD_INFO_COREDUMP_SIGNAL via simple socket coredump with SIGABRT
581 *
582 * Verify that when using simple socket-based coredump (@ pattern),
583 * the coredump_signal field is correctly exposed as SIGABRT.
584 */
TEST_F(coredump,socket_coredump_signal_sigabrt)585 TEST_F(coredump, socket_coredump_signal_sigabrt)
586 {
587 int pidfd, ret, status;
588 pid_t pid, pid_coredump_server;
589 struct pidfd_info info = {};
590 int ipc_sockets[2];
591 char c;
592
593 ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket"));
594
595 ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets);
596 ASSERT_EQ(ret, 0);
597
598 pid_coredump_server = fork();
599 ASSERT_GE(pid_coredump_server, 0);
600 if (pid_coredump_server == 0) {
601 int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1;
602 int exit_code = EXIT_FAILURE;
603
604 close(ipc_sockets[0]);
605
606 fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
607 if (fd_server < 0) {
608 fprintf(stderr, "socket_coredump_signal_sigabrt: create_and_listen_unix_socket failed: %m\n");
609 goto out;
610 }
611
612 if (write_nointr(ipc_sockets[1], "1", 1) < 0) {
613 fprintf(stderr, "socket_coredump_signal_sigabrt: write_nointr to ipc socket failed: %m\n");
614 goto out;
615 }
616
617 close(ipc_sockets[1]);
618
619 fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
620 if (fd_coredump < 0) {
621 fprintf(stderr, "socket_coredump_signal_sigabrt: accept4 failed: %m\n");
622 goto out;
623 }
624
625 fd_peer_pidfd = get_peer_pidfd(fd_coredump);
626 if (fd_peer_pidfd < 0) {
627 fprintf(stderr, "socket_coredump_signal_sigabrt: get_peer_pidfd failed\n");
628 goto out;
629 }
630
631 if (!get_pidfd_info(fd_peer_pidfd, &info)) {
632 fprintf(stderr, "socket_coredump_signal_sigabrt: get_pidfd_info failed\n");
633 goto out;
634 }
635
636 if (!(info.mask & PIDFD_INFO_COREDUMP)) {
637 fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP not set in mask\n");
638 goto out;
639 }
640
641 if (!(info.coredump_mask & PIDFD_COREDUMPED)) {
642 fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_COREDUMPED not set in coredump_mask\n");
643 goto out;
644 }
645
646 /* Verify coredump_signal is available and correct */
647 if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) {
648 fprintf(stderr, "socket_coredump_signal_sigabrt: PIDFD_INFO_COREDUMP_SIGNAL not set in mask\n");
649 goto out;
650 }
651
652 if (info.coredump_signal != SIGABRT) {
653 fprintf(stderr, "socket_coredump_signal_sigabrt: coredump_signal=%d, expected SIGABRT=%d\n",
654 info.coredump_signal, SIGABRT);
655 goto out;
656 }
657
658 fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
659 if (fd_core_file < 0) {
660 fprintf(stderr, "socket_coredump_signal_sigabrt: open_coredump_tmpfile failed: %m\n");
661 goto out;
662 }
663
664 for (;;) {
665 char buffer[4096];
666 ssize_t bytes_read, bytes_write;
667
668 bytes_read = read(fd_coredump, buffer, sizeof(buffer));
669 if (bytes_read < 0) {
670 fprintf(stderr, "socket_coredump_signal_sigabrt: read from coredump socket failed: %m\n");
671 goto out;
672 }
673
674 if (bytes_read == 0)
675 break;
676
677 bytes_write = write(fd_core_file, buffer, bytes_read);
678 if (bytes_read != bytes_write) {
679 fprintf(stderr, "socket_coredump_signal_sigabrt: write to core file failed (read=%zd, write=%zd): %m\n",
680 bytes_read, bytes_write);
681 goto out;
682 }
683 }
684
685 exit_code = EXIT_SUCCESS;
686 fprintf(stderr, "socket_coredump_signal_sigabrt: completed successfully\n");
687 out:
688 if (fd_core_file >= 0)
689 close(fd_core_file);
690 if (fd_peer_pidfd >= 0)
691 close(fd_peer_pidfd);
692 if (fd_coredump >= 0)
693 close(fd_coredump);
694 if (fd_server >= 0)
695 close(fd_server);
696 _exit(exit_code);
697 }
698 self->pid_coredump_server = pid_coredump_server;
699
700 EXPECT_EQ(close(ipc_sockets[1]), 0);
701 ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
702 EXPECT_EQ(close(ipc_sockets[0]), 0);
703
704 pid = fork();
705 ASSERT_GE(pid, 0);
706 if (pid == 0)
707 abort();
708
709 pidfd = sys_pidfd_open(pid, 0);
710 ASSERT_GE(pidfd, 0);
711
712 waitpid(pid, &status, 0);
713 ASSERT_TRUE(WIFSIGNALED(status));
714 ASSERT_EQ(WTERMSIG(status), SIGABRT);
715 ASSERT_TRUE(WCOREDUMP(status));
716
717 ASSERT_TRUE(get_pidfd_info(pidfd, &info));
718 ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP));
719 ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL));
720 ASSERT_EQ(info.coredump_signal, SIGABRT);
721
722 wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
723 }
724
TEST_F(coredump,socket_invalid_paths)725 TEST_F(coredump, socket_invalid_paths)
726 {
727 ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket"));
728 ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket"));
729 ASSERT_FALSE(set_core_pattern("@../coredump.socket"));
730 ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/.."));
731 ASSERT_FALSE(set_core_pattern("@.."));
732
733 ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket"));
734 ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket"));
735 ASSERT_FALSE(set_core_pattern("@@../coredump.socket"));
736 ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/.."));
737 ASSERT_FALSE(set_core_pattern("@@.."));
738
739 ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket"));
740 }
741
742 TEST_HARNESS_MAIN
743