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