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