Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/coredump: split out coredump socket tests

Split the coredump socket tests into separate files.

Link: https://patch.msgid.link/20251028-work-coredump-signal-v1-13-ca449b7b7aa0@kernel.org
Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>

+1722 -1661
+4
tools/testing/selftests/coredump/.gitignore
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + stackdump_test 3 + coredump_socket_test 4 + coredump_socket_protocol_test
+7 -1
tools/testing/selftests/coredump/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 CFLAGS += -Wall -O0 -g $(KHDR_INCLUDES) $(TOOLS_INCLUDES) 3 3 4 - TEST_GEN_PROGS := stackdump_test 4 + TEST_GEN_PROGS := stackdump_test \ 5 + coredump_socket_test \ 6 + coredump_socket_protocol_test 5 7 TEST_FILES := stackdump 6 8 7 9 include ../lib.mk 10 + 11 + $(OUTPUT)/stackdump_test: coredump_test_helpers.c 12 + $(OUTPUT)/coredump_socket_test: coredump_test_helpers.c 13 + $(OUTPUT)/coredump_socket_protocol_test: coredump_test_helpers.c
+1315
tools/testing/selftests/coredump/coredump_socket_protocol_test.c
··· 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 + goto out; 106 + 107 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 108 + goto out; 109 + 110 + close(ipc_sockets[1]); 111 + 112 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 113 + if (fd_coredump < 0) 114 + goto out; 115 + 116 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 117 + if (fd_peer_pidfd < 0) 118 + goto out; 119 + 120 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 121 + goto out; 122 + 123 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 124 + goto out; 125 + 126 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 127 + goto out; 128 + 129 + fd_core_file = creat("/tmp/coredump.file", 0644); 130 + if (fd_core_file < 0) 131 + goto out; 132 + 133 + if (!read_coredump_req(fd_coredump, &req)) 134 + goto out; 135 + 136 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 137 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 138 + COREDUMP_REJECT | COREDUMP_WAIT)) 139 + goto out; 140 + 141 + if (!send_coredump_ack(fd_coredump, &req, 142 + COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 143 + goto out; 144 + 145 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 146 + goto out; 147 + 148 + for (;;) { 149 + char buffer[4096]; 150 + ssize_t bytes_read, bytes_write; 151 + 152 + bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 153 + if (bytes_read < 0) 154 + goto out; 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 + goto out; 162 + } 163 + 164 + exit_code = EXIT_SUCCESS; 165 + out: 166 + if (fd_core_file >= 0) 167 + close(fd_core_file); 168 + if (fd_peer_pidfd >= 0) 169 + close(fd_peer_pidfd); 170 + if (fd_coredump >= 0) 171 + close(fd_coredump); 172 + if (fd_server >= 0) 173 + close(fd_server); 174 + _exit(exit_code); 175 + } 176 + self->pid_coredump_server = pid_coredump_server; 177 + 178 + EXPECT_EQ(close(ipc_sockets[1]), 0); 179 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 180 + EXPECT_EQ(close(ipc_sockets[0]), 0); 181 + 182 + pid = fork(); 183 + ASSERT_GE(pid, 0); 184 + if (pid == 0) 185 + crashing_child(); 186 + 187 + pidfd = sys_pidfd_open(pid, 0); 188 + ASSERT_GE(pidfd, 0); 189 + 190 + waitpid(pid, &status, 0); 191 + ASSERT_TRUE(WIFSIGNALED(status)); 192 + ASSERT_TRUE(WCOREDUMP(status)); 193 + 194 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 195 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 196 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 197 + 198 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 199 + 200 + ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 201 + ASSERT_GT(st.st_size, 0); 202 + system("file /tmp/coredump.file"); 203 + } 204 + 205 + TEST_F(coredump, socket_request_userspace) 206 + { 207 + int pidfd, ret, status; 208 + pid_t pid, pid_coredump_server; 209 + struct pidfd_info info = {}; 210 + int ipc_sockets[2]; 211 + char c; 212 + 213 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 214 + 215 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 216 + ASSERT_EQ(ret, 0); 217 + 218 + pid_coredump_server = fork(); 219 + ASSERT_GE(pid_coredump_server, 0); 220 + if (pid_coredump_server == 0) { 221 + struct coredump_req req = {}; 222 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 223 + int exit_code = EXIT_FAILURE; 224 + 225 + close(ipc_sockets[0]); 226 + 227 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 228 + if (fd_server < 0) 229 + goto out; 230 + 231 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 232 + goto out; 233 + 234 + close(ipc_sockets[1]); 235 + 236 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 237 + if (fd_coredump < 0) 238 + goto out; 239 + 240 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 241 + if (fd_peer_pidfd < 0) 242 + goto out; 243 + 244 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 245 + goto out; 246 + 247 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 248 + goto out; 249 + 250 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 251 + goto out; 252 + 253 + if (!read_coredump_req(fd_coredump, &req)) 254 + goto out; 255 + 256 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 257 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 258 + COREDUMP_REJECT | COREDUMP_WAIT)) 259 + goto out; 260 + 261 + if (!send_coredump_ack(fd_coredump, &req, 262 + COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) 263 + goto out; 264 + 265 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 266 + goto out; 267 + 268 + for (;;) { 269 + char buffer[4096]; 270 + ssize_t bytes_read; 271 + 272 + bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 273 + if (bytes_read > 0) 274 + goto out; 275 + 276 + if (bytes_read < 0) 277 + goto out; 278 + 279 + if (bytes_read == 0) 280 + break; 281 + } 282 + 283 + exit_code = EXIT_SUCCESS; 284 + out: 285 + if (fd_peer_pidfd >= 0) 286 + close(fd_peer_pidfd); 287 + if (fd_coredump >= 0) 288 + close(fd_coredump); 289 + if (fd_server >= 0) 290 + close(fd_server); 291 + _exit(exit_code); 292 + } 293 + self->pid_coredump_server = pid_coredump_server; 294 + 295 + EXPECT_EQ(close(ipc_sockets[1]), 0); 296 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 297 + EXPECT_EQ(close(ipc_sockets[0]), 0); 298 + 299 + pid = fork(); 300 + ASSERT_GE(pid, 0); 301 + if (pid == 0) 302 + crashing_child(); 303 + 304 + pidfd = sys_pidfd_open(pid, 0); 305 + ASSERT_GE(pidfd, 0); 306 + 307 + waitpid(pid, &status, 0); 308 + ASSERT_TRUE(WIFSIGNALED(status)); 309 + ASSERT_TRUE(WCOREDUMP(status)); 310 + 311 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 312 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 313 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 314 + 315 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 316 + } 317 + 318 + TEST_F(coredump, socket_request_reject) 319 + { 320 + int pidfd, ret, status; 321 + pid_t pid, pid_coredump_server; 322 + struct pidfd_info info = {}; 323 + int ipc_sockets[2]; 324 + char c; 325 + 326 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 327 + 328 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 329 + ASSERT_EQ(ret, 0); 330 + 331 + pid_coredump_server = fork(); 332 + ASSERT_GE(pid_coredump_server, 0); 333 + if (pid_coredump_server == 0) { 334 + struct coredump_req req = {}; 335 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 336 + int exit_code = EXIT_FAILURE; 337 + 338 + close(ipc_sockets[0]); 339 + 340 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 341 + if (fd_server < 0) 342 + goto out; 343 + 344 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 345 + goto out; 346 + 347 + close(ipc_sockets[1]); 348 + 349 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 350 + if (fd_coredump < 0) 351 + goto out; 352 + 353 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 354 + if (fd_peer_pidfd < 0) 355 + goto out; 356 + 357 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 358 + goto out; 359 + 360 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 361 + goto out; 362 + 363 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 364 + goto out; 365 + 366 + if (!read_coredump_req(fd_coredump, &req)) 367 + goto out; 368 + 369 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 370 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 371 + COREDUMP_REJECT | COREDUMP_WAIT)) 372 + goto out; 373 + 374 + if (!send_coredump_ack(fd_coredump, &req, 375 + COREDUMP_REJECT | COREDUMP_WAIT, 0)) 376 + goto out; 377 + 378 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 379 + goto out; 380 + 381 + for (;;) { 382 + char buffer[4096]; 383 + ssize_t bytes_read; 384 + 385 + bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 386 + if (bytes_read > 0) 387 + goto out; 388 + 389 + if (bytes_read < 0) 390 + goto out; 391 + 392 + if (bytes_read == 0) 393 + break; 394 + } 395 + 396 + exit_code = EXIT_SUCCESS; 397 + out: 398 + if (fd_peer_pidfd >= 0) 399 + close(fd_peer_pidfd); 400 + if (fd_coredump >= 0) 401 + close(fd_coredump); 402 + if (fd_server >= 0) 403 + close(fd_server); 404 + _exit(exit_code); 405 + } 406 + self->pid_coredump_server = pid_coredump_server; 407 + 408 + EXPECT_EQ(close(ipc_sockets[1]), 0); 409 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 410 + EXPECT_EQ(close(ipc_sockets[0]), 0); 411 + 412 + pid = fork(); 413 + ASSERT_GE(pid, 0); 414 + if (pid == 0) 415 + crashing_child(); 416 + 417 + pidfd = sys_pidfd_open(pid, 0); 418 + ASSERT_GE(pidfd, 0); 419 + 420 + waitpid(pid, &status, 0); 421 + ASSERT_TRUE(WIFSIGNALED(status)); 422 + ASSERT_FALSE(WCOREDUMP(status)); 423 + 424 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 425 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 426 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 427 + 428 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 429 + } 430 + 431 + TEST_F(coredump, socket_request_invalid_flag_combination) 432 + { 433 + int pidfd, ret, status; 434 + pid_t pid, pid_coredump_server; 435 + struct pidfd_info info = {}; 436 + int ipc_sockets[2]; 437 + char c; 438 + 439 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 440 + 441 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 442 + ASSERT_EQ(ret, 0); 443 + 444 + pid_coredump_server = fork(); 445 + ASSERT_GE(pid_coredump_server, 0); 446 + if (pid_coredump_server == 0) { 447 + struct coredump_req req = {}; 448 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 449 + int exit_code = EXIT_FAILURE; 450 + 451 + close(ipc_sockets[0]); 452 + 453 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 454 + if (fd_server < 0) 455 + goto out; 456 + 457 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 458 + goto out; 459 + 460 + close(ipc_sockets[1]); 461 + 462 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 463 + if (fd_coredump < 0) 464 + goto out; 465 + 466 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 467 + if (fd_peer_pidfd < 0) 468 + goto out; 469 + 470 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 471 + goto out; 472 + 473 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 474 + goto out; 475 + 476 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 477 + goto out; 478 + 479 + if (!read_coredump_req(fd_coredump, &req)) 480 + goto out; 481 + 482 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 483 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 484 + COREDUMP_REJECT | COREDUMP_WAIT)) 485 + goto out; 486 + 487 + if (!send_coredump_ack(fd_coredump, &req, 488 + COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) 489 + goto out; 490 + 491 + if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) 492 + goto out; 493 + 494 + exit_code = EXIT_SUCCESS; 495 + out: 496 + if (fd_peer_pidfd >= 0) 497 + close(fd_peer_pidfd); 498 + if (fd_coredump >= 0) 499 + close(fd_coredump); 500 + if (fd_server >= 0) 501 + close(fd_server); 502 + _exit(exit_code); 503 + } 504 + self->pid_coredump_server = pid_coredump_server; 505 + 506 + EXPECT_EQ(close(ipc_sockets[1]), 0); 507 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 508 + EXPECT_EQ(close(ipc_sockets[0]), 0); 509 + 510 + pid = fork(); 511 + ASSERT_GE(pid, 0); 512 + if (pid == 0) 513 + crashing_child(); 514 + 515 + pidfd = sys_pidfd_open(pid, 0); 516 + ASSERT_GE(pidfd, 0); 517 + 518 + waitpid(pid, &status, 0); 519 + ASSERT_TRUE(WIFSIGNALED(status)); 520 + ASSERT_FALSE(WCOREDUMP(status)); 521 + 522 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 523 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 524 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 525 + 526 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 527 + } 528 + 529 + TEST_F(coredump, socket_request_unknown_flag) 530 + { 531 + int pidfd, ret, status; 532 + pid_t pid, pid_coredump_server; 533 + struct pidfd_info info = {}; 534 + int ipc_sockets[2]; 535 + char c; 536 + 537 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 538 + 539 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 540 + ASSERT_EQ(ret, 0); 541 + 542 + pid_coredump_server = fork(); 543 + ASSERT_GE(pid_coredump_server, 0); 544 + if (pid_coredump_server == 0) { 545 + struct coredump_req req = {}; 546 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 547 + int exit_code = EXIT_FAILURE; 548 + 549 + close(ipc_sockets[0]); 550 + 551 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 552 + if (fd_server < 0) 553 + goto out; 554 + 555 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 556 + goto out; 557 + 558 + close(ipc_sockets[1]); 559 + 560 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 561 + if (fd_coredump < 0) 562 + goto out; 563 + 564 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 565 + if (fd_peer_pidfd < 0) 566 + goto out; 567 + 568 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 569 + goto out; 570 + 571 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 572 + goto out; 573 + 574 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 575 + goto out; 576 + 577 + if (!read_coredump_req(fd_coredump, &req)) 578 + goto out; 579 + 580 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 581 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 582 + COREDUMP_REJECT | COREDUMP_WAIT)) 583 + goto out; 584 + 585 + if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) 586 + goto out; 587 + 588 + if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) 589 + goto out; 590 + 591 + exit_code = EXIT_SUCCESS; 592 + out: 593 + if (fd_peer_pidfd >= 0) 594 + close(fd_peer_pidfd); 595 + if (fd_coredump >= 0) 596 + close(fd_coredump); 597 + if (fd_server >= 0) 598 + close(fd_server); 599 + _exit(exit_code); 600 + } 601 + self->pid_coredump_server = pid_coredump_server; 602 + 603 + EXPECT_EQ(close(ipc_sockets[1]), 0); 604 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 605 + EXPECT_EQ(close(ipc_sockets[0]), 0); 606 + 607 + pid = fork(); 608 + ASSERT_GE(pid, 0); 609 + if (pid == 0) 610 + crashing_child(); 611 + 612 + pidfd = sys_pidfd_open(pid, 0); 613 + ASSERT_GE(pidfd, 0); 614 + 615 + waitpid(pid, &status, 0); 616 + ASSERT_TRUE(WIFSIGNALED(status)); 617 + ASSERT_FALSE(WCOREDUMP(status)); 618 + 619 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 620 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 621 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 622 + 623 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 624 + } 625 + 626 + TEST_F(coredump, socket_request_invalid_size_small) 627 + { 628 + int pidfd, ret, status; 629 + pid_t pid, pid_coredump_server; 630 + struct pidfd_info info = {}; 631 + int ipc_sockets[2]; 632 + char c; 633 + 634 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 635 + 636 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 637 + ASSERT_EQ(ret, 0); 638 + 639 + pid_coredump_server = fork(); 640 + ASSERT_GE(pid_coredump_server, 0); 641 + if (pid_coredump_server == 0) { 642 + struct coredump_req req = {}; 643 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 644 + int exit_code = EXIT_FAILURE; 645 + 646 + close(ipc_sockets[0]); 647 + 648 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 649 + if (fd_server < 0) 650 + goto out; 651 + 652 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 653 + goto out; 654 + 655 + close(ipc_sockets[1]); 656 + 657 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 658 + if (fd_coredump < 0) 659 + goto out; 660 + 661 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 662 + if (fd_peer_pidfd < 0) 663 + goto out; 664 + 665 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 666 + goto out; 667 + 668 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 669 + goto out; 670 + 671 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 672 + goto out; 673 + 674 + if (!read_coredump_req(fd_coredump, &req)) 675 + goto out; 676 + 677 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 678 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 679 + COREDUMP_REJECT | COREDUMP_WAIT)) 680 + goto out; 681 + 682 + if (!send_coredump_ack(fd_coredump, &req, 683 + COREDUMP_REJECT | COREDUMP_WAIT, 684 + COREDUMP_ACK_SIZE_VER0 / 2)) 685 + goto out; 686 + 687 + if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) 688 + goto out; 689 + 690 + exit_code = EXIT_SUCCESS; 691 + out: 692 + if (fd_peer_pidfd >= 0) 693 + close(fd_peer_pidfd); 694 + if (fd_coredump >= 0) 695 + close(fd_coredump); 696 + if (fd_server >= 0) 697 + close(fd_server); 698 + _exit(exit_code); 699 + } 700 + self->pid_coredump_server = pid_coredump_server; 701 + 702 + EXPECT_EQ(close(ipc_sockets[1]), 0); 703 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 704 + EXPECT_EQ(close(ipc_sockets[0]), 0); 705 + 706 + pid = fork(); 707 + ASSERT_GE(pid, 0); 708 + if (pid == 0) 709 + crashing_child(); 710 + 711 + pidfd = sys_pidfd_open(pid, 0); 712 + ASSERT_GE(pidfd, 0); 713 + 714 + waitpid(pid, &status, 0); 715 + ASSERT_TRUE(WIFSIGNALED(status)); 716 + ASSERT_FALSE(WCOREDUMP(status)); 717 + 718 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 719 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 720 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 721 + 722 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 723 + } 724 + 725 + TEST_F(coredump, socket_request_invalid_size_large) 726 + { 727 + int pidfd, ret, status; 728 + pid_t pid, pid_coredump_server; 729 + struct pidfd_info info = {}; 730 + int ipc_sockets[2]; 731 + char c; 732 + 733 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 734 + 735 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 736 + ASSERT_EQ(ret, 0); 737 + 738 + pid_coredump_server = fork(); 739 + ASSERT_GE(pid_coredump_server, 0); 740 + if (pid_coredump_server == 0) { 741 + struct coredump_req req = {}; 742 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 743 + int exit_code = EXIT_FAILURE; 744 + 745 + close(ipc_sockets[0]); 746 + 747 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 748 + if (fd_server < 0) 749 + goto out; 750 + 751 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 752 + goto out; 753 + 754 + close(ipc_sockets[1]); 755 + 756 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 757 + if (fd_coredump < 0) 758 + goto out; 759 + 760 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 761 + if (fd_peer_pidfd < 0) 762 + goto out; 763 + 764 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 765 + goto out; 766 + 767 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 768 + goto out; 769 + 770 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 771 + goto out; 772 + 773 + if (!read_coredump_req(fd_coredump, &req)) 774 + goto out; 775 + 776 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 777 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 778 + COREDUMP_REJECT | COREDUMP_WAIT)) 779 + goto out; 780 + 781 + if (!send_coredump_ack(fd_coredump, &req, 782 + COREDUMP_REJECT | COREDUMP_WAIT, 783 + COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) 784 + goto out; 785 + 786 + if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) 787 + goto out; 788 + 789 + exit_code = EXIT_SUCCESS; 790 + out: 791 + if (fd_peer_pidfd >= 0) 792 + close(fd_peer_pidfd); 793 + if (fd_coredump >= 0) 794 + close(fd_coredump); 795 + if (fd_server >= 0) 796 + close(fd_server); 797 + _exit(exit_code); 798 + } 799 + self->pid_coredump_server = pid_coredump_server; 800 + 801 + EXPECT_EQ(close(ipc_sockets[1]), 0); 802 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 803 + EXPECT_EQ(close(ipc_sockets[0]), 0); 804 + 805 + pid = fork(); 806 + ASSERT_GE(pid, 0); 807 + if (pid == 0) 808 + crashing_child(); 809 + 810 + pidfd = sys_pidfd_open(pid, 0); 811 + ASSERT_GE(pidfd, 0); 812 + 813 + waitpid(pid, &status, 0); 814 + ASSERT_TRUE(WIFSIGNALED(status)); 815 + ASSERT_FALSE(WCOREDUMP(status)); 816 + 817 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 818 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 819 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 820 + 821 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 822 + } 823 + 824 + /* 825 + * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGSEGV 826 + * 827 + * Verify that when using socket-based coredump protocol, 828 + * the coredump_signal field is correctly exposed as SIGSEGV. 829 + */ 830 + TEST_F(coredump, socket_coredump_signal_sigsegv) 831 + { 832 + int pidfd, ret, status; 833 + pid_t pid, pid_coredump_server; 834 + struct pidfd_info info = {}; 835 + int ipc_sockets[2]; 836 + char c; 837 + 838 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 839 + 840 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 841 + ASSERT_EQ(ret, 0); 842 + 843 + pid_coredump_server = fork(); 844 + ASSERT_GE(pid_coredump_server, 0); 845 + if (pid_coredump_server == 0) { 846 + struct coredump_req req = {}; 847 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 848 + int exit_code = EXIT_FAILURE; 849 + 850 + close(ipc_sockets[0]); 851 + 852 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 853 + if (fd_server < 0) 854 + goto out; 855 + 856 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 857 + goto out; 858 + 859 + close(ipc_sockets[1]); 860 + 861 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 862 + if (fd_coredump < 0) 863 + goto out; 864 + 865 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 866 + if (fd_peer_pidfd < 0) 867 + goto out; 868 + 869 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 870 + goto out; 871 + 872 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 873 + goto out; 874 + 875 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 876 + goto out; 877 + 878 + /* Verify coredump_signal is available and correct */ 879 + if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) 880 + goto out; 881 + 882 + if (info.coredump_signal != SIGSEGV) 883 + goto out; 884 + 885 + if (!read_coredump_req(fd_coredump, &req)) 886 + goto out; 887 + 888 + if (!send_coredump_ack(fd_coredump, &req, 889 + COREDUMP_REJECT | COREDUMP_WAIT, 0)) 890 + goto out; 891 + 892 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 893 + goto out; 894 + 895 + exit_code = EXIT_SUCCESS; 896 + out: 897 + if (fd_peer_pidfd >= 0) 898 + close(fd_peer_pidfd); 899 + if (fd_coredump >= 0) 900 + close(fd_coredump); 901 + if (fd_server >= 0) 902 + close(fd_server); 903 + _exit(exit_code); 904 + } 905 + self->pid_coredump_server = pid_coredump_server; 906 + 907 + EXPECT_EQ(close(ipc_sockets[1]), 0); 908 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 909 + EXPECT_EQ(close(ipc_sockets[0]), 0); 910 + 911 + pid = fork(); 912 + ASSERT_GE(pid, 0); 913 + if (pid == 0) 914 + crashing_child(); 915 + 916 + pidfd = sys_pidfd_open(pid, 0); 917 + ASSERT_GE(pidfd, 0); 918 + 919 + waitpid(pid, &status, 0); 920 + ASSERT_TRUE(WIFSIGNALED(status)); 921 + ASSERT_EQ(WTERMSIG(status), SIGSEGV); 922 + 923 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 924 + ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); 925 + ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); 926 + ASSERT_EQ(info.coredump_signal, SIGSEGV); 927 + 928 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 929 + } 930 + 931 + /* 932 + * Test: PIDFD_INFO_COREDUMP_SIGNAL via socket coredump with SIGABRT 933 + * 934 + * Verify that when using socket-based coredump protocol, 935 + * the coredump_signal field is correctly exposed as SIGABRT. 936 + */ 937 + TEST_F(coredump, socket_coredump_signal_sigabrt) 938 + { 939 + int pidfd, ret, status; 940 + pid_t pid, pid_coredump_server; 941 + struct pidfd_info info = {}; 942 + int ipc_sockets[2]; 943 + char c; 944 + 945 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 946 + 947 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 948 + ASSERT_EQ(ret, 0); 949 + 950 + pid_coredump_server = fork(); 951 + ASSERT_GE(pid_coredump_server, 0); 952 + if (pid_coredump_server == 0) { 953 + struct coredump_req req = {}; 954 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 955 + int exit_code = EXIT_FAILURE; 956 + 957 + close(ipc_sockets[0]); 958 + 959 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 960 + if (fd_server < 0) 961 + goto out; 962 + 963 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 964 + goto out; 965 + 966 + close(ipc_sockets[1]); 967 + 968 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 969 + if (fd_coredump < 0) 970 + goto out; 971 + 972 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 973 + if (fd_peer_pidfd < 0) 974 + goto out; 975 + 976 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 977 + goto out; 978 + 979 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 980 + goto out; 981 + 982 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 983 + goto out; 984 + 985 + /* Verify coredump_signal is available and correct */ 986 + if (!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)) 987 + goto out; 988 + 989 + if (info.coredump_signal != SIGABRT) 990 + goto out; 991 + 992 + if (!read_coredump_req(fd_coredump, &req)) 993 + goto out; 994 + 995 + if (!send_coredump_ack(fd_coredump, &req, 996 + COREDUMP_REJECT | COREDUMP_WAIT, 0)) 997 + goto out; 998 + 999 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1000 + goto out; 1001 + 1002 + exit_code = EXIT_SUCCESS; 1003 + out: 1004 + if (fd_peer_pidfd >= 0) 1005 + close(fd_peer_pidfd); 1006 + if (fd_coredump >= 0) 1007 + close(fd_coredump); 1008 + if (fd_server >= 0) 1009 + close(fd_server); 1010 + _exit(exit_code); 1011 + } 1012 + self->pid_coredump_server = pid_coredump_server; 1013 + 1014 + EXPECT_EQ(close(ipc_sockets[1]), 0); 1015 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1016 + EXPECT_EQ(close(ipc_sockets[0]), 0); 1017 + 1018 + pid = fork(); 1019 + ASSERT_GE(pid, 0); 1020 + if (pid == 0) 1021 + abort(); 1022 + 1023 + pidfd = sys_pidfd_open(pid, 0); 1024 + ASSERT_GE(pidfd, 0); 1025 + 1026 + waitpid(pid, &status, 0); 1027 + ASSERT_TRUE(WIFSIGNALED(status)); 1028 + ASSERT_EQ(WTERMSIG(status), SIGABRT); 1029 + 1030 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1031 + ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP)); 1032 + ASSERT_TRUE(!!(info.mask & PIDFD_INFO_COREDUMP_SIGNAL)); 1033 + ASSERT_EQ(info.coredump_signal, SIGABRT); 1034 + 1035 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1036 + } 1037 + 1038 + TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500) 1039 + { 1040 + int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1041 + pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server; 1042 + struct pidfd_info info = {}; 1043 + int ipc_sockets[2]; 1044 + char c; 1045 + 1046 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1047 + 1048 + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1049 + 1050 + pid_coredump_server = fork(); 1051 + ASSERT_GE(pid_coredump_server, 0); 1052 + if (pid_coredump_server == 0) { 1053 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1054 + int exit_code = EXIT_FAILURE; 1055 + struct coredump_req req = {}; 1056 + 1057 + close(ipc_sockets[0]); 1058 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1059 + if (fd_server < 0) { 1060 + fprintf(stderr, "Failed to create and listen on unix socket\n"); 1061 + goto out; 1062 + } 1063 + 1064 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) { 1065 + fprintf(stderr, "Failed to notify parent via ipc socket\n"); 1066 + goto out; 1067 + } 1068 + close(ipc_sockets[1]); 1069 + 1070 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1071 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1072 + if (fd_coredump < 0) { 1073 + fprintf(stderr, "accept4 failed: %m\n"); 1074 + goto out; 1075 + } 1076 + 1077 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1078 + if (fd_peer_pidfd < 0) { 1079 + fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump); 1080 + goto out; 1081 + } 1082 + 1083 + if (!get_pidfd_info(fd_peer_pidfd, &info)) { 1084 + fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd); 1085 + goto out; 1086 + } 1087 + 1088 + if (!(info.mask & PIDFD_INFO_COREDUMP)) { 1089 + fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd); 1090 + goto out; 1091 + } 1092 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) { 1093 + fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd); 1094 + goto out; 1095 + } 1096 + 1097 + if (!read_coredump_req(fd_coredump, &req)) { 1098 + fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump); 1099 + goto out; 1100 + } 1101 + 1102 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1103 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 1104 + COREDUMP_REJECT | COREDUMP_WAIT)) { 1105 + fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump); 1106 + goto out; 1107 + } 1108 + 1109 + if (!send_coredump_ack(fd_coredump, &req, 1110 + COREDUMP_KERNEL | COREDUMP_WAIT, 0)) { 1111 + fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump); 1112 + goto out; 1113 + } 1114 + 1115 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) { 1116 + fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump); 1117 + goto out; 1118 + } 1119 + 1120 + fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1121 + if (fd_core_file < 0) { 1122 + fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump); 1123 + goto out; 1124 + } 1125 + 1126 + for (;;) { 1127 + char buffer[4096]; 1128 + ssize_t bytes_read, bytes_write; 1129 + 1130 + bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1131 + if (bytes_read < 0) { 1132 + fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump); 1133 + goto out; 1134 + } 1135 + 1136 + if (bytes_read == 0) 1137 + break; 1138 + 1139 + bytes_write = write(fd_core_file, buffer, bytes_read); 1140 + if (bytes_read != bytes_write) { 1141 + fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file); 1142 + goto out; 1143 + } 1144 + } 1145 + 1146 + close(fd_core_file); 1147 + close(fd_peer_pidfd); 1148 + close(fd_coredump); 1149 + fd_peer_pidfd = -1; 1150 + fd_coredump = -1; 1151 + } 1152 + 1153 + exit_code = EXIT_SUCCESS; 1154 + out: 1155 + if (fd_core_file >= 0) 1156 + close(fd_core_file); 1157 + if (fd_peer_pidfd >= 0) 1158 + close(fd_peer_pidfd); 1159 + if (fd_coredump >= 0) 1160 + close(fd_coredump); 1161 + if (fd_server >= 0) 1162 + close(fd_server); 1163 + _exit(exit_code); 1164 + } 1165 + self->pid_coredump_server = pid_coredump_server; 1166 + 1167 + EXPECT_EQ(close(ipc_sockets[1]), 0); 1168 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1169 + EXPECT_EQ(close(ipc_sockets[0]), 0); 1170 + 1171 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1172 + pid[i] = fork(); 1173 + ASSERT_GE(pid[i], 0); 1174 + if (pid[i] == 0) 1175 + crashing_child(); 1176 + pidfd[i] = sys_pidfd_open(pid[i], 0); 1177 + ASSERT_GE(pidfd[i], 0); 1178 + } 1179 + 1180 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1181 + waitpid(pid[i], &status[i], 0); 1182 + ASSERT_TRUE(WIFSIGNALED(status[i])); 1183 + ASSERT_TRUE(WCOREDUMP(status[i])); 1184 + } 1185 + 1186 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1187 + info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1188 + ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1189 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1190 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1191 + } 1192 + 1193 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1194 + } 1195 + 1196 + TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500) 1197 + { 1198 + int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1199 + pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS]; 1200 + struct pidfd_info info = {}; 1201 + int ipc_sockets[2]; 1202 + char c; 1203 + 1204 + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1205 + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1206 + 1207 + pid_coredump_server = fork(); 1208 + ASSERT_GE(pid_coredump_server, 0); 1209 + if (pid_coredump_server == 0) { 1210 + int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0; 1211 + fd_server = -1; 1212 + exit_code = EXIT_FAILURE; 1213 + n_conns = 0; 1214 + close(ipc_sockets[0]); 1215 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1216 + if (fd_server < 0) 1217 + goto out; 1218 + 1219 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1220 + goto out; 1221 + close(ipc_sockets[1]); 1222 + 1223 + while (n_conns < NUM_CRASHING_COREDUMPS) { 1224 + int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1225 + struct coredump_req req = {}; 1226 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1227 + if (fd_coredump < 0) { 1228 + if (errno == EAGAIN || errno == EWOULDBLOCK) 1229 + continue; 1230 + goto out; 1231 + } 1232 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1233 + if (fd_peer_pidfd < 0) 1234 + goto out; 1235 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 1236 + goto out; 1237 + if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) 1238 + goto out; 1239 + if (!read_coredump_req(fd_coredump, &req)) 1240 + goto out; 1241 + if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1242 + COREDUMP_KERNEL | COREDUMP_USERSPACE | 1243 + COREDUMP_REJECT | COREDUMP_WAIT)) 1244 + goto out; 1245 + if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 1246 + goto out; 1247 + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1248 + goto out; 1249 + fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1250 + if (fd_core_file < 0) 1251 + goto out; 1252 + pid_t worker = fork(); 1253 + if (worker == 0) { 1254 + close(fd_server); 1255 + process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file); 1256 + } 1257 + worker_pids[n_conns] = worker; 1258 + if (fd_coredump >= 0) 1259 + close(fd_coredump); 1260 + if (fd_peer_pidfd >= 0) 1261 + close(fd_peer_pidfd); 1262 + if (fd_core_file >= 0) 1263 + close(fd_core_file); 1264 + n_conns++; 1265 + } 1266 + exit_code = EXIT_SUCCESS; 1267 + out: 1268 + if (fd_server >= 0) 1269 + close(fd_server); 1270 + 1271 + // Reap all worker processes 1272 + for (int i = 0; i < n_conns; i++) { 1273 + int wstatus; 1274 + if (waitpid(worker_pids[i], &wstatus, 0) < 0) { 1275 + fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]); 1276 + } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) { 1277 + fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus)); 1278 + exit_code = EXIT_FAILURE; 1279 + } 1280 + } 1281 + 1282 + _exit(exit_code); 1283 + } 1284 + self->pid_coredump_server = pid_coredump_server; 1285 + 1286 + EXPECT_EQ(close(ipc_sockets[1]), 0); 1287 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1288 + EXPECT_EQ(close(ipc_sockets[0]), 0); 1289 + 1290 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1291 + pid[i] = fork(); 1292 + ASSERT_GE(pid[i], 0); 1293 + if (pid[i] == 0) 1294 + crashing_child(); 1295 + pidfd[i] = sys_pidfd_open(pid[i], 0); 1296 + ASSERT_GE(pidfd[i], 0); 1297 + } 1298 + 1299 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1300 + ASSERT_GE(waitpid(pid[i], &status[i], 0), 0); 1301 + ASSERT_TRUE(WIFSIGNALED(status[i])); 1302 + ASSERT_TRUE(WCOREDUMP(status[i])); 1303 + } 1304 + 1305 + for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1306 + info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1307 + ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1308 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1309 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1310 + } 1311 + 1312 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1313 + } 1314 + 1315 + TEST_HARNESS_MAIN
+394
tools/testing/selftests/coredump/coredump_socket_test.c
··· 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 + goto out; 103 + 104 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 105 + goto out; 106 + 107 + close(ipc_sockets[1]); 108 + 109 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 110 + if (fd_coredump < 0) 111 + goto out; 112 + 113 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 114 + if (fd_peer_pidfd < 0) 115 + goto out; 116 + 117 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 118 + goto out; 119 + 120 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 121 + goto out; 122 + 123 + if (!(info.coredump_mask & PIDFD_COREDUMPED)) 124 + goto out; 125 + 126 + fd_core_file = creat("/tmp/coredump.file", 0644); 127 + if (fd_core_file < 0) 128 + goto out; 129 + 130 + for (;;) { 131 + char buffer[4096]; 132 + ssize_t bytes_read, bytes_write; 133 + 134 + bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 135 + if (bytes_read < 0) 136 + goto out; 137 + 138 + if (bytes_read == 0) 139 + break; 140 + 141 + bytes_write = write(fd_core_file, buffer, bytes_read); 142 + if (bytes_read != bytes_write) 143 + goto out; 144 + } 145 + 146 + exit_code = EXIT_SUCCESS; 147 + out: 148 + if (fd_core_file >= 0) 149 + close(fd_core_file); 150 + if (fd_peer_pidfd >= 0) 151 + close(fd_peer_pidfd); 152 + if (fd_coredump >= 0) 153 + close(fd_coredump); 154 + if (fd_server >= 0) 155 + close(fd_server); 156 + _exit(exit_code); 157 + } 158 + self->pid_coredump_server = pid_coredump_server; 159 + 160 + EXPECT_EQ(close(ipc_sockets[1]), 0); 161 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 162 + EXPECT_EQ(close(ipc_sockets[0]), 0); 163 + 164 + pid = fork(); 165 + ASSERT_GE(pid, 0); 166 + if (pid == 0) 167 + crashing_child(); 168 + 169 + pidfd = sys_pidfd_open(pid, 0); 170 + ASSERT_GE(pidfd, 0); 171 + 172 + waitpid(pid, &status, 0); 173 + ASSERT_TRUE(WIFSIGNALED(status)); 174 + ASSERT_TRUE(WCOREDUMP(status)); 175 + 176 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 177 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 178 + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 179 + 180 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 181 + 182 + ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 183 + ASSERT_GT(st.st_size, 0); 184 + } 185 + 186 + TEST_F(coredump, socket_detect_userspace_client) 187 + { 188 + int pidfd, ret, status; 189 + pid_t pid, pid_coredump_server; 190 + struct stat st; 191 + struct pidfd_info info = {}; 192 + int ipc_sockets[2]; 193 + char c; 194 + 195 + ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 196 + 197 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 198 + ASSERT_EQ(ret, 0); 199 + 200 + pid_coredump_server = fork(); 201 + ASSERT_GE(pid_coredump_server, 0); 202 + if (pid_coredump_server == 0) { 203 + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 204 + int exit_code = EXIT_FAILURE; 205 + 206 + close(ipc_sockets[0]); 207 + 208 + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 209 + if (fd_server < 0) 210 + goto out; 211 + 212 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 213 + goto out; 214 + 215 + close(ipc_sockets[1]); 216 + 217 + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 218 + if (fd_coredump < 0) 219 + goto out; 220 + 221 + fd_peer_pidfd = get_peer_pidfd(fd_coredump); 222 + if (fd_peer_pidfd < 0) 223 + goto out; 224 + 225 + if (!get_pidfd_info(fd_peer_pidfd, &info)) 226 + goto out; 227 + 228 + if (!(info.mask & PIDFD_INFO_COREDUMP)) 229 + goto out; 230 + 231 + if (info.coredump_mask & PIDFD_COREDUMPED) 232 + goto out; 233 + 234 + exit_code = EXIT_SUCCESS; 235 + out: 236 + if (fd_peer_pidfd >= 0) 237 + close(fd_peer_pidfd); 238 + if (fd_coredump >= 0) 239 + close(fd_coredump); 240 + if (fd_server >= 0) 241 + close(fd_server); 242 + _exit(exit_code); 243 + } 244 + self->pid_coredump_server = pid_coredump_server; 245 + 246 + EXPECT_EQ(close(ipc_sockets[1]), 0); 247 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 248 + EXPECT_EQ(close(ipc_sockets[0]), 0); 249 + 250 + pid = fork(); 251 + ASSERT_GE(pid, 0); 252 + if (pid == 0) { 253 + int fd_socket; 254 + ssize_t ret; 255 + const struct sockaddr_un coredump_sk = { 256 + .sun_family = AF_UNIX, 257 + .sun_path = "/tmp/coredump.socket", 258 + }; 259 + size_t coredump_sk_len = 260 + offsetof(struct sockaddr_un, sun_path) + 261 + sizeof("/tmp/coredump.socket"); 262 + 263 + fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); 264 + if (fd_socket < 0) 265 + _exit(EXIT_FAILURE); 266 + 267 + ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 268 + if (ret < 0) 269 + _exit(EXIT_FAILURE); 270 + 271 + close(fd_socket); 272 + _exit(EXIT_SUCCESS); 273 + } 274 + 275 + pidfd = sys_pidfd_open(pid, 0); 276 + ASSERT_GE(pidfd, 0); 277 + 278 + waitpid(pid, &status, 0); 279 + ASSERT_TRUE(WIFEXITED(status)); 280 + ASSERT_EQ(WEXITSTATUS(status), 0); 281 + 282 + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 283 + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 284 + ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0); 285 + 286 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 287 + 288 + ASSERT_NE(stat("/tmp/coredump.file", &st), 0); 289 + ASSERT_EQ(errno, ENOENT); 290 + } 291 + 292 + TEST_F(coredump, socket_enoent) 293 + { 294 + int pidfd, status; 295 + pid_t pid; 296 + 297 + ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 298 + 299 + pid = fork(); 300 + ASSERT_GE(pid, 0); 301 + if (pid == 0) 302 + crashing_child(); 303 + 304 + pidfd = sys_pidfd_open(pid, 0); 305 + ASSERT_GE(pidfd, 0); 306 + 307 + waitpid(pid, &status, 0); 308 + ASSERT_TRUE(WIFSIGNALED(status)); 309 + ASSERT_FALSE(WCOREDUMP(status)); 310 + } 311 + 312 + TEST_F(coredump, socket_no_listener) 313 + { 314 + int pidfd, ret, status; 315 + pid_t pid, pid_coredump_server; 316 + int ipc_sockets[2]; 317 + char c; 318 + const struct sockaddr_un coredump_sk = { 319 + .sun_family = AF_UNIX, 320 + .sun_path = "/tmp/coredump.socket", 321 + }; 322 + size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) + 323 + sizeof("/tmp/coredump.socket"); 324 + 325 + ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 326 + 327 + ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 328 + ASSERT_EQ(ret, 0); 329 + 330 + pid_coredump_server = fork(); 331 + ASSERT_GE(pid_coredump_server, 0); 332 + if (pid_coredump_server == 0) { 333 + int fd_server = -1; 334 + int exit_code = EXIT_FAILURE; 335 + 336 + close(ipc_sockets[0]); 337 + 338 + fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 339 + if (fd_server < 0) 340 + goto out; 341 + 342 + ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 343 + if (ret < 0) 344 + goto out; 345 + 346 + if (write_nointr(ipc_sockets[1], "1", 1) < 0) 347 + goto out; 348 + 349 + exit_code = EXIT_SUCCESS; 350 + out: 351 + if (fd_server >= 0) 352 + close(fd_server); 353 + close(ipc_sockets[1]); 354 + _exit(exit_code); 355 + } 356 + self->pid_coredump_server = pid_coredump_server; 357 + 358 + EXPECT_EQ(close(ipc_sockets[1]), 0); 359 + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 360 + EXPECT_EQ(close(ipc_sockets[0]), 0); 361 + 362 + pid = fork(); 363 + ASSERT_GE(pid, 0); 364 + if (pid == 0) 365 + crashing_child(); 366 + 367 + pidfd = sys_pidfd_open(pid, 0); 368 + ASSERT_GE(pidfd, 0); 369 + 370 + waitpid(pid, &status, 0); 371 + ASSERT_TRUE(WIFSIGNALED(status)); 372 + ASSERT_FALSE(WCOREDUMP(status)); 373 + 374 + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 375 + } 376 + 377 + TEST_F(coredump, socket_invalid_paths) 378 + { 379 + ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket")); 380 + ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket")); 381 + ASSERT_FALSE(set_core_pattern("@../coredump.socket")); 382 + ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/..")); 383 + ASSERT_FALSE(set_core_pattern("@..")); 384 + 385 + ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket")); 386 + ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket")); 387 + ASSERT_FALSE(set_core_pattern("@@../coredump.socket")); 388 + ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/..")); 389 + ASSERT_FALSE(set_core_pattern("@@..")); 390 + 391 + ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket")); 392 + } 393 + 394 + TEST_HARNESS_MAIN
+2 -1660
tools/testing/selftests/coredump/stackdump_test.c
··· 23 23 #include "../filesystems/wrappers.h" 24 24 #include "../pidfd/pidfd.h" 25 25 26 + #include "coredump_test.h" 27 + 26 28 #define STACKDUMP_FILE "stack_values" 27 29 #define STACKDUMP_SCRIPT "stackdump" 28 - #define NUM_THREAD_SPAWN 128 29 30 30 31 #ifndef PAGE_SIZE 31 32 #define PAGE_SIZE 4096 32 33 #endif 33 - 34 - static void *do_nothing(void *) 35 - { 36 - while (1) 37 - pause(); 38 - 39 - return NULL; 40 - } 41 - 42 - static void crashing_child(void) 43 - { 44 - pthread_t thread; 45 - int i; 46 - 47 - for (i = 0; i < NUM_THREAD_SPAWN; ++i) 48 - pthread_create(&thread, NULL, do_nothing, NULL); 49 - 50 - /* crash on purpose */ 51 - i = *(int *)NULL; 52 - } 53 - 54 - FIXTURE(coredump) 55 - { 56 - char original_core_pattern[256]; 57 - pid_t pid_coredump_server; 58 - int fd_tmpfs_detached; 59 - }; 60 - 61 - static int create_detached_tmpfs(void) 62 - { 63 - int fd_context, fd_tmpfs; 64 - 65 - fd_context = sys_fsopen("tmpfs", 0); 66 - if (fd_context < 0) 67 - return -1; 68 - 69 - if (sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) 70 - return -1; 71 - 72 - fd_tmpfs = sys_fsmount(fd_context, 0, 0); 73 - close(fd_context); 74 - return fd_tmpfs; 75 - } 76 34 77 35 FIXTURE_SETUP(coredump) 78 36 { ··· 164 206 ASSERT_EQ(i, 1 + NUM_THREAD_SPAWN); 165 207 166 208 fclose(file); 167 - } 168 - 169 - static int create_and_listen_unix_socket(const char *path) 170 - { 171 - struct sockaddr_un addr = { 172 - .sun_family = AF_UNIX, 173 - }; 174 - assert(strlen(path) < sizeof(addr.sun_path) - 1); 175 - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); 176 - size_t addr_len = 177 - offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1; 178 - int fd, ret; 179 - 180 - fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 181 - if (fd < 0) 182 - goto out; 183 - 184 - ret = bind(fd, (const struct sockaddr *)&addr, addr_len); 185 - if (ret < 0) 186 - goto out; 187 - 188 - ret = listen(fd, 128); 189 - if (ret < 0) 190 - goto out; 191 - 192 - return fd; 193 - 194 - out: 195 - if (fd >= 0) 196 - close(fd); 197 - return -1; 198 - } 199 - 200 - static bool set_core_pattern(const char *pattern) 201 - { 202 - int fd; 203 - ssize_t ret; 204 - 205 - fd = open("/proc/sys/kernel/core_pattern", O_WRONLY | O_CLOEXEC); 206 - if (fd < 0) 207 - return false; 208 - 209 - ret = write(fd, pattern, strlen(pattern)); 210 - close(fd); 211 - if (ret < 0) 212 - return false; 213 - 214 - fprintf(stderr, "Set core_pattern to '%s' | %zu == %zu\n", pattern, ret, strlen(pattern)); 215 - return ret == strlen(pattern); 216 - } 217 - 218 - static int get_peer_pidfd(int fd) 219 - { 220 - int fd_peer_pidfd; 221 - socklen_t fd_peer_pidfd_len = sizeof(fd_peer_pidfd); 222 - int ret = getsockopt(fd, SOL_SOCKET, SO_PEERPIDFD, &fd_peer_pidfd, 223 - &fd_peer_pidfd_len); 224 - if (ret < 0) { 225 - fprintf(stderr, "%m - Failed to retrieve peer pidfd for coredump socket connection\n"); 226 - return -1; 227 - } 228 - return fd_peer_pidfd; 229 - } 230 - 231 - static bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info) 232 - { 233 - memset(info, 0, sizeof(*info)); 234 - info->mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 235 - return ioctl(fd_peer_pidfd, PIDFD_GET_INFO, info) == 0; 236 - } 237 - 238 - static void 239 - wait_and_check_coredump_server(pid_t pid_coredump_server, 240 - struct __test_metadata *const _metadata, 241 - FIXTURE_DATA(coredump)* self) 242 - { 243 - int status; 244 - waitpid(pid_coredump_server, &status, 0); 245 - self->pid_coredump_server = -ESRCH; 246 - ASSERT_TRUE(WIFEXITED(status)); 247 - ASSERT_EQ(WEXITSTATUS(status), 0); 248 - } 249 - 250 - TEST_F(coredump, socket) 251 - { 252 - int pidfd, ret, status; 253 - pid_t pid, pid_coredump_server; 254 - struct stat st; 255 - struct pidfd_info info = {}; 256 - int ipc_sockets[2]; 257 - char c; 258 - 259 - ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 260 - 261 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 262 - ASSERT_EQ(ret, 0); 263 - 264 - pid_coredump_server = fork(); 265 - ASSERT_GE(pid_coredump_server, 0); 266 - if (pid_coredump_server == 0) { 267 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 268 - int exit_code = EXIT_FAILURE; 269 - 270 - close(ipc_sockets[0]); 271 - 272 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 273 - if (fd_server < 0) 274 - goto out; 275 - 276 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 277 - goto out; 278 - 279 - close(ipc_sockets[1]); 280 - 281 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 282 - if (fd_coredump < 0) 283 - goto out; 284 - 285 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 286 - if (fd_peer_pidfd < 0) 287 - goto out; 288 - 289 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 290 - goto out; 291 - 292 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 293 - goto out; 294 - 295 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 296 - goto out; 297 - 298 - fd_core_file = creat("/tmp/coredump.file", 0644); 299 - if (fd_core_file < 0) 300 - goto out; 301 - 302 - for (;;) { 303 - char buffer[4096]; 304 - ssize_t bytes_read, bytes_write; 305 - 306 - bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 307 - if (bytes_read < 0) 308 - goto out; 309 - 310 - if (bytes_read == 0) 311 - break; 312 - 313 - bytes_write = write(fd_core_file, buffer, bytes_read); 314 - if (bytes_read != bytes_write) 315 - goto out; 316 - } 317 - 318 - exit_code = EXIT_SUCCESS; 319 - out: 320 - if (fd_core_file >= 0) 321 - close(fd_core_file); 322 - if (fd_peer_pidfd >= 0) 323 - close(fd_peer_pidfd); 324 - if (fd_coredump >= 0) 325 - close(fd_coredump); 326 - if (fd_server >= 0) 327 - close(fd_server); 328 - _exit(exit_code); 329 - } 330 - self->pid_coredump_server = pid_coredump_server; 331 - 332 - EXPECT_EQ(close(ipc_sockets[1]), 0); 333 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 334 - EXPECT_EQ(close(ipc_sockets[0]), 0); 335 - 336 - pid = fork(); 337 - ASSERT_GE(pid, 0); 338 - if (pid == 0) 339 - crashing_child(); 340 - 341 - pidfd = sys_pidfd_open(pid, 0); 342 - ASSERT_GE(pidfd, 0); 343 - 344 - waitpid(pid, &status, 0); 345 - ASSERT_TRUE(WIFSIGNALED(status)); 346 - ASSERT_TRUE(WCOREDUMP(status)); 347 - 348 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 349 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 350 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 351 - 352 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 353 - 354 - ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 355 - ASSERT_GT(st.st_size, 0); 356 - system("file /tmp/coredump.file"); 357 - } 358 - 359 - TEST_F(coredump, socket_detect_userspace_client) 360 - { 361 - int pidfd, ret, status; 362 - pid_t pid, pid_coredump_server; 363 - struct stat st; 364 - struct pidfd_info info = {}; 365 - int ipc_sockets[2]; 366 - char c; 367 - 368 - ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 369 - 370 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 371 - ASSERT_EQ(ret, 0); 372 - 373 - pid_coredump_server = fork(); 374 - ASSERT_GE(pid_coredump_server, 0); 375 - if (pid_coredump_server == 0) { 376 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 377 - int exit_code = EXIT_FAILURE; 378 - 379 - close(ipc_sockets[0]); 380 - 381 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 382 - if (fd_server < 0) 383 - goto out; 384 - 385 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 386 - goto out; 387 - 388 - close(ipc_sockets[1]); 389 - 390 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 391 - if (fd_coredump < 0) 392 - goto out; 393 - 394 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 395 - if (fd_peer_pidfd < 0) 396 - goto out; 397 - 398 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 399 - goto out; 400 - 401 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 402 - goto out; 403 - 404 - if (info.coredump_mask & PIDFD_COREDUMPED) 405 - goto out; 406 - 407 - exit_code = EXIT_SUCCESS; 408 - out: 409 - if (fd_peer_pidfd >= 0) 410 - close(fd_peer_pidfd); 411 - if (fd_coredump >= 0) 412 - close(fd_coredump); 413 - if (fd_server >= 0) 414 - close(fd_server); 415 - _exit(exit_code); 416 - } 417 - self->pid_coredump_server = pid_coredump_server; 418 - 419 - EXPECT_EQ(close(ipc_sockets[1]), 0); 420 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 421 - EXPECT_EQ(close(ipc_sockets[0]), 0); 422 - 423 - pid = fork(); 424 - ASSERT_GE(pid, 0); 425 - if (pid == 0) { 426 - int fd_socket; 427 - ssize_t ret; 428 - const struct sockaddr_un coredump_sk = { 429 - .sun_family = AF_UNIX, 430 - .sun_path = "/tmp/coredump.socket", 431 - }; 432 - size_t coredump_sk_len = 433 - offsetof(struct sockaddr_un, sun_path) + 434 - sizeof("/tmp/coredump.socket"); 435 - 436 - fd_socket = socket(AF_UNIX, SOCK_STREAM, 0); 437 - if (fd_socket < 0) 438 - _exit(EXIT_FAILURE); 439 - 440 - ret = connect(fd_socket, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 441 - if (ret < 0) 442 - _exit(EXIT_FAILURE); 443 - 444 - close(fd_socket); 445 - _exit(EXIT_SUCCESS); 446 - } 447 - 448 - pidfd = sys_pidfd_open(pid, 0); 449 - ASSERT_GE(pidfd, 0); 450 - 451 - waitpid(pid, &status, 0); 452 - ASSERT_TRUE(WIFEXITED(status)); 453 - ASSERT_EQ(WEXITSTATUS(status), 0); 454 - 455 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 456 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 457 - ASSERT_EQ((info.coredump_mask & PIDFD_COREDUMPED), 0); 458 - 459 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 460 - 461 - ASSERT_NE(stat("/tmp/coredump.file", &st), 0); 462 - ASSERT_EQ(errno, ENOENT); 463 - } 464 - 465 - TEST_F(coredump, socket_enoent) 466 - { 467 - int pidfd, status; 468 - pid_t pid; 469 - 470 - ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 471 - 472 - pid = fork(); 473 - ASSERT_GE(pid, 0); 474 - if (pid == 0) 475 - crashing_child(); 476 - 477 - pidfd = sys_pidfd_open(pid, 0); 478 - ASSERT_GE(pidfd, 0); 479 - 480 - waitpid(pid, &status, 0); 481 - ASSERT_TRUE(WIFSIGNALED(status)); 482 - ASSERT_FALSE(WCOREDUMP(status)); 483 - } 484 - 485 - TEST_F(coredump, socket_no_listener) 486 - { 487 - int pidfd, ret, status; 488 - pid_t pid, pid_coredump_server; 489 - int ipc_sockets[2]; 490 - char c; 491 - const struct sockaddr_un coredump_sk = { 492 - .sun_family = AF_UNIX, 493 - .sun_path = "/tmp/coredump.socket", 494 - }; 495 - size_t coredump_sk_len = offsetof(struct sockaddr_un, sun_path) + 496 - sizeof("/tmp/coredump.socket"); 497 - 498 - ASSERT_TRUE(set_core_pattern("@/tmp/coredump.socket")); 499 - 500 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 501 - ASSERT_EQ(ret, 0); 502 - 503 - pid_coredump_server = fork(); 504 - ASSERT_GE(pid_coredump_server, 0); 505 - if (pid_coredump_server == 0) { 506 - int fd_server = -1; 507 - int exit_code = EXIT_FAILURE; 508 - 509 - close(ipc_sockets[0]); 510 - 511 - fd_server = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 512 - if (fd_server < 0) 513 - goto out; 514 - 515 - ret = bind(fd_server, (const struct sockaddr *)&coredump_sk, coredump_sk_len); 516 - if (ret < 0) 517 - goto out; 518 - 519 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 520 - goto out; 521 - 522 - exit_code = EXIT_SUCCESS; 523 - out: 524 - if (fd_server >= 0) 525 - close(fd_server); 526 - close(ipc_sockets[1]); 527 - _exit(exit_code); 528 - } 529 - self->pid_coredump_server = pid_coredump_server; 530 - 531 - EXPECT_EQ(close(ipc_sockets[1]), 0); 532 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 533 - EXPECT_EQ(close(ipc_sockets[0]), 0); 534 - 535 - pid = fork(); 536 - ASSERT_GE(pid, 0); 537 - if (pid == 0) 538 - crashing_child(); 539 - 540 - pidfd = sys_pidfd_open(pid, 0); 541 - ASSERT_GE(pidfd, 0); 542 - 543 - waitpid(pid, &status, 0); 544 - ASSERT_TRUE(WIFSIGNALED(status)); 545 - ASSERT_FALSE(WCOREDUMP(status)); 546 - 547 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 548 - } 549 - 550 - static ssize_t recv_marker(int fd) 551 - { 552 - enum coredump_mark mark = COREDUMP_MARK_REQACK; 553 - ssize_t ret; 554 - 555 - ret = recv(fd, &mark, sizeof(mark), MSG_WAITALL); 556 - if (ret != sizeof(mark)) 557 - return -1; 558 - 559 - switch (mark) { 560 - case COREDUMP_MARK_REQACK: 561 - fprintf(stderr, "Received marker: ReqAck\n"); 562 - return COREDUMP_MARK_REQACK; 563 - case COREDUMP_MARK_MINSIZE: 564 - fprintf(stderr, "Received marker: MinSize\n"); 565 - return COREDUMP_MARK_MINSIZE; 566 - case COREDUMP_MARK_MAXSIZE: 567 - fprintf(stderr, "Received marker: MaxSize\n"); 568 - return COREDUMP_MARK_MAXSIZE; 569 - case COREDUMP_MARK_UNSUPPORTED: 570 - fprintf(stderr, "Received marker: Unsupported\n"); 571 - return COREDUMP_MARK_UNSUPPORTED; 572 - case COREDUMP_MARK_CONFLICTING: 573 - fprintf(stderr, "Received marker: Conflicting\n"); 574 - return COREDUMP_MARK_CONFLICTING; 575 - default: 576 - fprintf(stderr, "Received unknown marker: %u\n", mark); 577 - break; 578 - } 579 - return -1; 580 - } 581 - 582 - static bool read_marker(int fd, enum coredump_mark mark) 583 - { 584 - ssize_t ret; 585 - 586 - ret = recv_marker(fd); 587 - if (ret < 0) 588 - return false; 589 - return ret == mark; 590 - } 591 - 592 - static bool read_coredump_req(int fd, struct coredump_req *req) 593 - { 594 - ssize_t ret; 595 - size_t field_size, user_size, ack_size, kernel_size, remaining_size; 596 - 597 - memset(req, 0, sizeof(*req)); 598 - field_size = sizeof(req->size); 599 - 600 - /* Peek the size of the coredump request. */ 601 - ret = recv(fd, req, field_size, MSG_PEEK | MSG_WAITALL); 602 - if (ret != field_size) 603 - return false; 604 - kernel_size = req->size; 605 - 606 - if (kernel_size < COREDUMP_ACK_SIZE_VER0) 607 - return false; 608 - if (kernel_size >= PAGE_SIZE) 609 - return false; 610 - 611 - /* Use the minimum of user and kernel size to read the full request. */ 612 - user_size = sizeof(struct coredump_req); 613 - ack_size = user_size < kernel_size ? user_size : kernel_size; 614 - ret = recv(fd, req, ack_size, MSG_WAITALL); 615 - if (ret != ack_size) 616 - return false; 617 - 618 - fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n", 619 - req->size, (unsigned long long)req->mask); 620 - 621 - if (user_size > kernel_size) 622 - remaining_size = user_size - kernel_size; 623 - else 624 - remaining_size = kernel_size - user_size; 625 - 626 - if (PAGE_SIZE <= remaining_size) 627 - return false; 628 - 629 - /* 630 - * Discard any additional data if the kernel's request was larger than 631 - * what we knew about or cared about. 632 - */ 633 - if (remaining_size) { 634 - char buffer[PAGE_SIZE]; 635 - 636 - ret = recv(fd, buffer, sizeof(buffer), MSG_WAITALL); 637 - if (ret != remaining_size) 638 - return false; 639 - fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", remaining_size); 640 - } 641 - 642 - return true; 643 - } 644 - 645 - static bool send_coredump_ack(int fd, const struct coredump_req *req, 646 - __u64 mask, size_t size_ack) 647 - { 648 - ssize_t ret; 649 - /* 650 - * Wrap struct coredump_ack in a larger struct so we can 651 - * simulate sending to much data to the kernel. 652 - */ 653 - struct large_ack_for_size_testing { 654 - struct coredump_ack ack; 655 - char buffer[PAGE_SIZE]; 656 - } large_ack = {}; 657 - 658 - if (!size_ack) 659 - size_ack = sizeof(struct coredump_ack) < req->size_ack ? 660 - sizeof(struct coredump_ack) : 661 - req->size_ack; 662 - large_ack.ack.mask = mask; 663 - large_ack.ack.size = size_ack; 664 - ret = send(fd, &large_ack, size_ack, MSG_NOSIGNAL); 665 - if (ret != size_ack) 666 - return false; 667 - 668 - fprintf(stderr, "Sent coredump ack with size %zu and mask 0x%llx\n", 669 - size_ack, (unsigned long long)mask); 670 - return true; 671 - } 672 - 673 - static bool check_coredump_req(const struct coredump_req *req, size_t min_size, 674 - __u64 required_mask) 675 - { 676 - if (req->size < min_size) 677 - return false; 678 - if ((req->mask & required_mask) != required_mask) 679 - return false; 680 - if (req->mask & ~required_mask) 681 - return false; 682 - return true; 683 - } 684 - 685 - TEST_F(coredump, socket_request_kernel) 686 - { 687 - int pidfd, ret, status; 688 - pid_t pid, pid_coredump_server; 689 - struct stat st; 690 - struct pidfd_info info = {}; 691 - int ipc_sockets[2]; 692 - char c; 693 - 694 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 695 - 696 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 697 - ASSERT_EQ(ret, 0); 698 - 699 - pid_coredump_server = fork(); 700 - ASSERT_GE(pid_coredump_server, 0); 701 - if (pid_coredump_server == 0) { 702 - struct coredump_req req = {}; 703 - int fd_server = -1, fd_coredump = -1, fd_core_file = -1, fd_peer_pidfd = -1; 704 - int exit_code = EXIT_FAILURE; 705 - 706 - close(ipc_sockets[0]); 707 - 708 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 709 - if (fd_server < 0) 710 - goto out; 711 - 712 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 713 - goto out; 714 - 715 - close(ipc_sockets[1]); 716 - 717 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 718 - if (fd_coredump < 0) 719 - goto out; 720 - 721 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 722 - if (fd_peer_pidfd < 0) 723 - goto out; 724 - 725 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 726 - goto out; 727 - 728 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 729 - goto out; 730 - 731 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 732 - goto out; 733 - 734 - fd_core_file = creat("/tmp/coredump.file", 0644); 735 - if (fd_core_file < 0) 736 - goto out; 737 - 738 - if (!read_coredump_req(fd_coredump, &req)) 739 - goto out; 740 - 741 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 742 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 743 - COREDUMP_REJECT | COREDUMP_WAIT)) 744 - goto out; 745 - 746 - if (!send_coredump_ack(fd_coredump, &req, 747 - COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 748 - goto out; 749 - 750 - if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 751 - goto out; 752 - 753 - for (;;) { 754 - char buffer[4096]; 755 - ssize_t bytes_read, bytes_write; 756 - 757 - bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 758 - if (bytes_read < 0) 759 - goto out; 760 - 761 - if (bytes_read == 0) 762 - break; 763 - 764 - bytes_write = write(fd_core_file, buffer, bytes_read); 765 - if (bytes_read != bytes_write) 766 - goto out; 767 - } 768 - 769 - exit_code = EXIT_SUCCESS; 770 - out: 771 - if (fd_core_file >= 0) 772 - close(fd_core_file); 773 - if (fd_peer_pidfd >= 0) 774 - close(fd_peer_pidfd); 775 - if (fd_coredump >= 0) 776 - close(fd_coredump); 777 - if (fd_server >= 0) 778 - close(fd_server); 779 - _exit(exit_code); 780 - } 781 - self->pid_coredump_server = pid_coredump_server; 782 - 783 - EXPECT_EQ(close(ipc_sockets[1]), 0); 784 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 785 - EXPECT_EQ(close(ipc_sockets[0]), 0); 786 - 787 - pid = fork(); 788 - ASSERT_GE(pid, 0); 789 - if (pid == 0) 790 - crashing_child(); 791 - 792 - pidfd = sys_pidfd_open(pid, 0); 793 - ASSERT_GE(pidfd, 0); 794 - 795 - waitpid(pid, &status, 0); 796 - ASSERT_TRUE(WIFSIGNALED(status)); 797 - ASSERT_TRUE(WCOREDUMP(status)); 798 - 799 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 800 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 801 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 802 - 803 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 804 - 805 - ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); 806 - ASSERT_GT(st.st_size, 0); 807 - system("file /tmp/coredump.file"); 808 - } 809 - 810 - TEST_F(coredump, socket_request_userspace) 811 - { 812 - int pidfd, ret, status; 813 - pid_t pid, pid_coredump_server; 814 - struct pidfd_info info = {}; 815 - int ipc_sockets[2]; 816 - char c; 817 - 818 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 819 - 820 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 821 - ASSERT_EQ(ret, 0); 822 - 823 - pid_coredump_server = fork(); 824 - ASSERT_GE(pid_coredump_server, 0); 825 - if (pid_coredump_server == 0) { 826 - struct coredump_req req = {}; 827 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 828 - int exit_code = EXIT_FAILURE; 829 - 830 - close(ipc_sockets[0]); 831 - 832 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 833 - if (fd_server < 0) 834 - goto out; 835 - 836 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 837 - goto out; 838 - 839 - close(ipc_sockets[1]); 840 - 841 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 842 - if (fd_coredump < 0) 843 - goto out; 844 - 845 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 846 - if (fd_peer_pidfd < 0) 847 - goto out; 848 - 849 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 850 - goto out; 851 - 852 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 853 - goto out; 854 - 855 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 856 - goto out; 857 - 858 - if (!read_coredump_req(fd_coredump, &req)) 859 - goto out; 860 - 861 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 862 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 863 - COREDUMP_REJECT | COREDUMP_WAIT)) 864 - goto out; 865 - 866 - if (!send_coredump_ack(fd_coredump, &req, 867 - COREDUMP_USERSPACE | COREDUMP_WAIT, 0)) 868 - goto out; 869 - 870 - if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 871 - goto out; 872 - 873 - for (;;) { 874 - char buffer[4096]; 875 - ssize_t bytes_read; 876 - 877 - bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 878 - if (bytes_read > 0) 879 - goto out; 880 - 881 - if (bytes_read < 0) 882 - goto out; 883 - 884 - if (bytes_read == 0) 885 - break; 886 - } 887 - 888 - exit_code = EXIT_SUCCESS; 889 - out: 890 - if (fd_peer_pidfd >= 0) 891 - close(fd_peer_pidfd); 892 - if (fd_coredump >= 0) 893 - close(fd_coredump); 894 - if (fd_server >= 0) 895 - close(fd_server); 896 - _exit(exit_code); 897 - } 898 - self->pid_coredump_server = pid_coredump_server; 899 - 900 - EXPECT_EQ(close(ipc_sockets[1]), 0); 901 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 902 - EXPECT_EQ(close(ipc_sockets[0]), 0); 903 - 904 - pid = fork(); 905 - ASSERT_GE(pid, 0); 906 - if (pid == 0) 907 - crashing_child(); 908 - 909 - pidfd = sys_pidfd_open(pid, 0); 910 - ASSERT_GE(pidfd, 0); 911 - 912 - waitpid(pid, &status, 0); 913 - ASSERT_TRUE(WIFSIGNALED(status)); 914 - ASSERT_TRUE(WCOREDUMP(status)); 915 - 916 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 917 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 918 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 919 - 920 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 921 - } 922 - 923 - TEST_F(coredump, socket_request_reject) 924 - { 925 - int pidfd, ret, status; 926 - pid_t pid, pid_coredump_server; 927 - struct pidfd_info info = {}; 928 - int ipc_sockets[2]; 929 - char c; 930 - 931 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 932 - 933 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 934 - ASSERT_EQ(ret, 0); 935 - 936 - pid_coredump_server = fork(); 937 - ASSERT_GE(pid_coredump_server, 0); 938 - if (pid_coredump_server == 0) { 939 - struct coredump_req req = {}; 940 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 941 - int exit_code = EXIT_FAILURE; 942 - 943 - close(ipc_sockets[0]); 944 - 945 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 946 - if (fd_server < 0) 947 - goto out; 948 - 949 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 950 - goto out; 951 - 952 - close(ipc_sockets[1]); 953 - 954 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 955 - if (fd_coredump < 0) 956 - goto out; 957 - 958 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 959 - if (fd_peer_pidfd < 0) 960 - goto out; 961 - 962 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 963 - goto out; 964 - 965 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 966 - goto out; 967 - 968 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 969 - goto out; 970 - 971 - if (!read_coredump_req(fd_coredump, &req)) 972 - goto out; 973 - 974 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 975 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 976 - COREDUMP_REJECT | COREDUMP_WAIT)) 977 - goto out; 978 - 979 - if (!send_coredump_ack(fd_coredump, &req, 980 - COREDUMP_REJECT | COREDUMP_WAIT, 0)) 981 - goto out; 982 - 983 - if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 984 - goto out; 985 - 986 - for (;;) { 987 - char buffer[4096]; 988 - ssize_t bytes_read; 989 - 990 - bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 991 - if (bytes_read > 0) 992 - goto out; 993 - 994 - if (bytes_read < 0) 995 - goto out; 996 - 997 - if (bytes_read == 0) 998 - break; 999 - } 1000 - 1001 - exit_code = EXIT_SUCCESS; 1002 - out: 1003 - if (fd_peer_pidfd >= 0) 1004 - close(fd_peer_pidfd); 1005 - if (fd_coredump >= 0) 1006 - close(fd_coredump); 1007 - if (fd_server >= 0) 1008 - close(fd_server); 1009 - _exit(exit_code); 1010 - } 1011 - self->pid_coredump_server = pid_coredump_server; 1012 - 1013 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1014 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1015 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1016 - 1017 - pid = fork(); 1018 - ASSERT_GE(pid, 0); 1019 - if (pid == 0) 1020 - crashing_child(); 1021 - 1022 - pidfd = sys_pidfd_open(pid, 0); 1023 - ASSERT_GE(pidfd, 0); 1024 - 1025 - waitpid(pid, &status, 0); 1026 - ASSERT_TRUE(WIFSIGNALED(status)); 1027 - ASSERT_FALSE(WCOREDUMP(status)); 1028 - 1029 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1030 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1031 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1032 - 1033 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1034 - } 1035 - 1036 - TEST_F(coredump, socket_request_invalid_flag_combination) 1037 - { 1038 - int pidfd, ret, status; 1039 - pid_t pid, pid_coredump_server; 1040 - struct pidfd_info info = {}; 1041 - int ipc_sockets[2]; 1042 - char c; 1043 - 1044 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1045 - 1046 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1047 - ASSERT_EQ(ret, 0); 1048 - 1049 - pid_coredump_server = fork(); 1050 - ASSERT_GE(pid_coredump_server, 0); 1051 - if (pid_coredump_server == 0) { 1052 - struct coredump_req req = {}; 1053 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1054 - int exit_code = EXIT_FAILURE; 1055 - 1056 - close(ipc_sockets[0]); 1057 - 1058 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1059 - if (fd_server < 0) 1060 - goto out; 1061 - 1062 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1063 - goto out; 1064 - 1065 - close(ipc_sockets[1]); 1066 - 1067 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1068 - if (fd_coredump < 0) 1069 - goto out; 1070 - 1071 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1072 - if (fd_peer_pidfd < 0) 1073 - goto out; 1074 - 1075 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 1076 - goto out; 1077 - 1078 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 1079 - goto out; 1080 - 1081 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1082 - goto out; 1083 - 1084 - if (!read_coredump_req(fd_coredump, &req)) 1085 - goto out; 1086 - 1087 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1088 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1089 - COREDUMP_REJECT | COREDUMP_WAIT)) 1090 - goto out; 1091 - 1092 - if (!send_coredump_ack(fd_coredump, &req, 1093 - COREDUMP_KERNEL | COREDUMP_REJECT | COREDUMP_WAIT, 0)) 1094 - goto out; 1095 - 1096 - if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) 1097 - goto out; 1098 - 1099 - exit_code = EXIT_SUCCESS; 1100 - out: 1101 - if (fd_peer_pidfd >= 0) 1102 - close(fd_peer_pidfd); 1103 - if (fd_coredump >= 0) 1104 - close(fd_coredump); 1105 - if (fd_server >= 0) 1106 - close(fd_server); 1107 - _exit(exit_code); 1108 - } 1109 - self->pid_coredump_server = pid_coredump_server; 1110 - 1111 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1112 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1113 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1114 - 1115 - pid = fork(); 1116 - ASSERT_GE(pid, 0); 1117 - if (pid == 0) 1118 - crashing_child(); 1119 - 1120 - pidfd = sys_pidfd_open(pid, 0); 1121 - ASSERT_GE(pidfd, 0); 1122 - 1123 - waitpid(pid, &status, 0); 1124 - ASSERT_TRUE(WIFSIGNALED(status)); 1125 - ASSERT_FALSE(WCOREDUMP(status)); 1126 - 1127 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1128 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1129 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1130 - 1131 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1132 - } 1133 - 1134 - TEST_F(coredump, socket_request_unknown_flag) 1135 - { 1136 - int pidfd, ret, status; 1137 - pid_t pid, pid_coredump_server; 1138 - struct pidfd_info info = {}; 1139 - int ipc_sockets[2]; 1140 - char c; 1141 - 1142 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1143 - 1144 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1145 - ASSERT_EQ(ret, 0); 1146 - 1147 - pid_coredump_server = fork(); 1148 - ASSERT_GE(pid_coredump_server, 0); 1149 - if (pid_coredump_server == 0) { 1150 - struct coredump_req req = {}; 1151 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1152 - int exit_code = EXIT_FAILURE; 1153 - 1154 - close(ipc_sockets[0]); 1155 - 1156 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1157 - if (fd_server < 0) 1158 - goto out; 1159 - 1160 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1161 - goto out; 1162 - 1163 - close(ipc_sockets[1]); 1164 - 1165 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1166 - if (fd_coredump < 0) 1167 - goto out; 1168 - 1169 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1170 - if (fd_peer_pidfd < 0) 1171 - goto out; 1172 - 1173 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 1174 - goto out; 1175 - 1176 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 1177 - goto out; 1178 - 1179 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1180 - goto out; 1181 - 1182 - if (!read_coredump_req(fd_coredump, &req)) 1183 - goto out; 1184 - 1185 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1186 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1187 - COREDUMP_REJECT | COREDUMP_WAIT)) 1188 - goto out; 1189 - 1190 - if (!send_coredump_ack(fd_coredump, &req, (1ULL << 63), 0)) 1191 - goto out; 1192 - 1193 - if (!read_marker(fd_coredump, COREDUMP_MARK_UNSUPPORTED)) 1194 - goto out; 1195 - 1196 - exit_code = EXIT_SUCCESS; 1197 - out: 1198 - if (fd_peer_pidfd >= 0) 1199 - close(fd_peer_pidfd); 1200 - if (fd_coredump >= 0) 1201 - close(fd_coredump); 1202 - if (fd_server >= 0) 1203 - close(fd_server); 1204 - _exit(exit_code); 1205 - } 1206 - self->pid_coredump_server = pid_coredump_server; 1207 - 1208 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1209 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1210 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1211 - 1212 - pid = fork(); 1213 - ASSERT_GE(pid, 0); 1214 - if (pid == 0) 1215 - crashing_child(); 1216 - 1217 - pidfd = sys_pidfd_open(pid, 0); 1218 - ASSERT_GE(pidfd, 0); 1219 - 1220 - waitpid(pid, &status, 0); 1221 - ASSERT_TRUE(WIFSIGNALED(status)); 1222 - ASSERT_FALSE(WCOREDUMP(status)); 1223 - 1224 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1225 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1226 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1227 - 1228 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1229 - } 1230 - 1231 - TEST_F(coredump, socket_request_invalid_size_small) 1232 - { 1233 - int pidfd, ret, status; 1234 - pid_t pid, pid_coredump_server; 1235 - struct pidfd_info info = {}; 1236 - int ipc_sockets[2]; 1237 - char c; 1238 - 1239 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1240 - 1241 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1242 - ASSERT_EQ(ret, 0); 1243 - 1244 - pid_coredump_server = fork(); 1245 - ASSERT_GE(pid_coredump_server, 0); 1246 - if (pid_coredump_server == 0) { 1247 - struct coredump_req req = {}; 1248 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1249 - int exit_code = EXIT_FAILURE; 1250 - 1251 - close(ipc_sockets[0]); 1252 - 1253 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1254 - if (fd_server < 0) 1255 - goto out; 1256 - 1257 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1258 - goto out; 1259 - 1260 - close(ipc_sockets[1]); 1261 - 1262 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1263 - if (fd_coredump < 0) 1264 - goto out; 1265 - 1266 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1267 - if (fd_peer_pidfd < 0) 1268 - goto out; 1269 - 1270 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 1271 - goto out; 1272 - 1273 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 1274 - goto out; 1275 - 1276 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1277 - goto out; 1278 - 1279 - if (!read_coredump_req(fd_coredump, &req)) 1280 - goto out; 1281 - 1282 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1283 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1284 - COREDUMP_REJECT | COREDUMP_WAIT)) 1285 - goto out; 1286 - 1287 - if (!send_coredump_ack(fd_coredump, &req, 1288 - COREDUMP_REJECT | COREDUMP_WAIT, 1289 - COREDUMP_ACK_SIZE_VER0 / 2)) 1290 - goto out; 1291 - 1292 - if (!read_marker(fd_coredump, COREDUMP_MARK_MINSIZE)) 1293 - goto out; 1294 - 1295 - exit_code = EXIT_SUCCESS; 1296 - out: 1297 - if (fd_peer_pidfd >= 0) 1298 - close(fd_peer_pidfd); 1299 - if (fd_coredump >= 0) 1300 - close(fd_coredump); 1301 - if (fd_server >= 0) 1302 - close(fd_server); 1303 - _exit(exit_code); 1304 - } 1305 - self->pid_coredump_server = pid_coredump_server; 1306 - 1307 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1308 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1309 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1310 - 1311 - pid = fork(); 1312 - ASSERT_GE(pid, 0); 1313 - if (pid == 0) 1314 - crashing_child(); 1315 - 1316 - pidfd = sys_pidfd_open(pid, 0); 1317 - ASSERT_GE(pidfd, 0); 1318 - 1319 - waitpid(pid, &status, 0); 1320 - ASSERT_TRUE(WIFSIGNALED(status)); 1321 - ASSERT_FALSE(WCOREDUMP(status)); 1322 - 1323 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1324 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1325 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1326 - 1327 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1328 - } 1329 - 1330 - TEST_F(coredump, socket_request_invalid_size_large) 1331 - { 1332 - int pidfd, ret, status; 1333 - pid_t pid, pid_coredump_server; 1334 - struct pidfd_info info = {}; 1335 - int ipc_sockets[2]; 1336 - char c; 1337 - 1338 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1339 - 1340 - ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 1341 - ASSERT_EQ(ret, 0); 1342 - 1343 - pid_coredump_server = fork(); 1344 - ASSERT_GE(pid_coredump_server, 0); 1345 - if (pid_coredump_server == 0) { 1346 - struct coredump_req req = {}; 1347 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1; 1348 - int exit_code = EXIT_FAILURE; 1349 - 1350 - close(ipc_sockets[0]); 1351 - 1352 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1353 - if (fd_server < 0) 1354 - goto out; 1355 - 1356 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1357 - goto out; 1358 - 1359 - close(ipc_sockets[1]); 1360 - 1361 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1362 - if (fd_coredump < 0) 1363 - goto out; 1364 - 1365 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1366 - if (fd_peer_pidfd < 0) 1367 - goto out; 1368 - 1369 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 1370 - goto out; 1371 - 1372 - if (!(info.mask & PIDFD_INFO_COREDUMP)) 1373 - goto out; 1374 - 1375 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) 1376 - goto out; 1377 - 1378 - if (!read_coredump_req(fd_coredump, &req)) 1379 - goto out; 1380 - 1381 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1382 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1383 - COREDUMP_REJECT | COREDUMP_WAIT)) 1384 - goto out; 1385 - 1386 - if (!send_coredump_ack(fd_coredump, &req, 1387 - COREDUMP_REJECT | COREDUMP_WAIT, 1388 - COREDUMP_ACK_SIZE_VER0 + PAGE_SIZE)) 1389 - goto out; 1390 - 1391 - if (!read_marker(fd_coredump, COREDUMP_MARK_MAXSIZE)) 1392 - goto out; 1393 - 1394 - exit_code = EXIT_SUCCESS; 1395 - out: 1396 - if (fd_peer_pidfd >= 0) 1397 - close(fd_peer_pidfd); 1398 - if (fd_coredump >= 0) 1399 - close(fd_coredump); 1400 - if (fd_server >= 0) 1401 - close(fd_server); 1402 - _exit(exit_code); 1403 - } 1404 - self->pid_coredump_server = pid_coredump_server; 1405 - 1406 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1407 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1408 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1409 - 1410 - pid = fork(); 1411 - ASSERT_GE(pid, 0); 1412 - if (pid == 0) 1413 - crashing_child(); 1414 - 1415 - pidfd = sys_pidfd_open(pid, 0); 1416 - ASSERT_GE(pidfd, 0); 1417 - 1418 - waitpid(pid, &status, 0); 1419 - ASSERT_TRUE(WIFSIGNALED(status)); 1420 - ASSERT_FALSE(WCOREDUMP(status)); 1421 - 1422 - ASSERT_TRUE(get_pidfd_info(pidfd, &info)); 1423 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1424 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1425 - 1426 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1427 - } 1428 - 1429 - static int open_coredump_tmpfile(int fd_tmpfs_detached) 1430 - { 1431 - return openat(fd_tmpfs_detached, ".", O_TMPFILE | O_RDWR | O_EXCL, 0600); 1432 - } 1433 - 1434 - #define NUM_CRASHING_COREDUMPS 5 1435 - 1436 - TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps, 500) 1437 - { 1438 - int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1439 - pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server; 1440 - struct pidfd_info info = {}; 1441 - int ipc_sockets[2]; 1442 - char c; 1443 - 1444 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1445 - 1446 - ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1447 - 1448 - pid_coredump_server = fork(); 1449 - ASSERT_GE(pid_coredump_server, 0); 1450 - if (pid_coredump_server == 0) { 1451 - int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1452 - int exit_code = EXIT_FAILURE; 1453 - struct coredump_req req = {}; 1454 - 1455 - close(ipc_sockets[0]); 1456 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1457 - if (fd_server < 0) { 1458 - fprintf(stderr, "Failed to create and listen on unix socket\n"); 1459 - goto out; 1460 - } 1461 - 1462 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) { 1463 - fprintf(stderr, "Failed to notify parent via ipc socket\n"); 1464 - goto out; 1465 - } 1466 - close(ipc_sockets[1]); 1467 - 1468 - for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1469 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1470 - if (fd_coredump < 0) { 1471 - fprintf(stderr, "accept4 failed: %m\n"); 1472 - goto out; 1473 - } 1474 - 1475 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1476 - if (fd_peer_pidfd < 0) { 1477 - fprintf(stderr, "get_peer_pidfd failed for fd %d: %m\n", fd_coredump); 1478 - goto out; 1479 - } 1480 - 1481 - if (!get_pidfd_info(fd_peer_pidfd, &info)) { 1482 - fprintf(stderr, "get_pidfd_info failed for fd %d\n", fd_peer_pidfd); 1483 - goto out; 1484 - } 1485 - 1486 - if (!(info.mask & PIDFD_INFO_COREDUMP)) { 1487 - fprintf(stderr, "pidfd info missing PIDFD_INFO_COREDUMP for fd %d\n", fd_peer_pidfd); 1488 - goto out; 1489 - } 1490 - if (!(info.coredump_mask & PIDFD_COREDUMPED)) { 1491 - fprintf(stderr, "pidfd info missing PIDFD_COREDUMPED for fd %d\n", fd_peer_pidfd); 1492 - goto out; 1493 - } 1494 - 1495 - if (!read_coredump_req(fd_coredump, &req)) { 1496 - fprintf(stderr, "read_coredump_req failed for fd %d\n", fd_coredump); 1497 - goto out; 1498 - } 1499 - 1500 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1501 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1502 - COREDUMP_REJECT | COREDUMP_WAIT)) { 1503 - fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump); 1504 - goto out; 1505 - } 1506 - 1507 - if (!send_coredump_ack(fd_coredump, &req, 1508 - COREDUMP_KERNEL | COREDUMP_WAIT, 0)) { 1509 - fprintf(stderr, "send_coredump_ack failed for fd %d\n", fd_coredump); 1510 - goto out; 1511 - } 1512 - 1513 - if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) { 1514 - fprintf(stderr, "read_marker failed for fd %d\n", fd_coredump); 1515 - goto out; 1516 - } 1517 - 1518 - fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1519 - if (fd_core_file < 0) { 1520 - fprintf(stderr, "%m - open_coredump_tmpfile failed for fd %d\n", fd_coredump); 1521 - goto out; 1522 - } 1523 - 1524 - for (;;) { 1525 - char buffer[4096]; 1526 - ssize_t bytes_read, bytes_write; 1527 - 1528 - bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1529 - if (bytes_read < 0) { 1530 - fprintf(stderr, "read failed for fd %d: %m\n", fd_coredump); 1531 - goto out; 1532 - } 1533 - 1534 - if (bytes_read == 0) 1535 - break; 1536 - 1537 - bytes_write = write(fd_core_file, buffer, bytes_read); 1538 - if (bytes_read != bytes_write) { 1539 - fprintf(stderr, "write failed for fd %d: %m\n", fd_core_file); 1540 - goto out; 1541 - } 1542 - } 1543 - 1544 - close(fd_core_file); 1545 - close(fd_peer_pidfd); 1546 - close(fd_coredump); 1547 - fd_peer_pidfd = -1; 1548 - fd_coredump = -1; 1549 - } 1550 - 1551 - exit_code = EXIT_SUCCESS; 1552 - out: 1553 - if (fd_core_file >= 0) 1554 - close(fd_core_file); 1555 - if (fd_peer_pidfd >= 0) 1556 - close(fd_peer_pidfd); 1557 - if (fd_coredump >= 0) 1558 - close(fd_coredump); 1559 - if (fd_server >= 0) 1560 - close(fd_server); 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 - waitpid(pid[i], &status[i], 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 - #define MAX_EVENTS 128 1595 - 1596 - static void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_core_file) 1597 - { 1598 - int epfd = -1; 1599 - int exit_code = EXIT_FAILURE; 1600 - 1601 - epfd = epoll_create1(0); 1602 - if (epfd < 0) 1603 - goto out; 1604 - 1605 - struct epoll_event ev; 1606 - ev.events = EPOLLIN | EPOLLRDHUP | EPOLLET; 1607 - ev.data.fd = fd_coredump; 1608 - if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd_coredump, &ev) < 0) 1609 - goto out; 1610 - 1611 - for (;;) { 1612 - struct epoll_event events[1]; 1613 - int n = epoll_wait(epfd, events, 1, -1); 1614 - if (n < 0) 1615 - break; 1616 - 1617 - if (events[0].events & (EPOLLIN | EPOLLRDHUP)) { 1618 - for (;;) { 1619 - char buffer[4096]; 1620 - ssize_t bytes_read = read(fd_coredump, buffer, sizeof(buffer)); 1621 - if (bytes_read < 0) { 1622 - if (errno == EAGAIN || errno == EWOULDBLOCK) 1623 - break; 1624 - goto out; 1625 - } 1626 - if (bytes_read == 0) 1627 - goto done; 1628 - ssize_t bytes_write = write(fd_core_file, buffer, bytes_read); 1629 - if (bytes_write != bytes_read) 1630 - goto out; 1631 - } 1632 - } 1633 - } 1634 - 1635 - done: 1636 - exit_code = EXIT_SUCCESS; 1637 - out: 1638 - if (epfd >= 0) 1639 - close(epfd); 1640 - if (fd_core_file >= 0) 1641 - close(fd_core_file); 1642 - if (fd_peer_pidfd >= 0) 1643 - close(fd_peer_pidfd); 1644 - if (fd_coredump >= 0) 1645 - close(fd_coredump); 1646 - _exit(exit_code); 1647 - } 1648 - 1649 - TEST_F_TIMEOUT(coredump, socket_multiple_crashing_coredumps_epoll_workers, 500) 1650 - { 1651 - int pidfd[NUM_CRASHING_COREDUMPS], status[NUM_CRASHING_COREDUMPS]; 1652 - pid_t pid[NUM_CRASHING_COREDUMPS], pid_coredump_server, worker_pids[NUM_CRASHING_COREDUMPS]; 1653 - struct pidfd_info info = {}; 1654 - int ipc_sockets[2]; 1655 - char c; 1656 - 1657 - ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); 1658 - ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0); 1659 - 1660 - pid_coredump_server = fork(); 1661 - ASSERT_GE(pid_coredump_server, 0); 1662 - if (pid_coredump_server == 0) { 1663 - int fd_server = -1, exit_code = EXIT_FAILURE, n_conns = 0; 1664 - fd_server = -1; 1665 - exit_code = EXIT_FAILURE; 1666 - n_conns = 0; 1667 - close(ipc_sockets[0]); 1668 - fd_server = create_and_listen_unix_socket("/tmp/coredump.socket"); 1669 - if (fd_server < 0) 1670 - goto out; 1671 - 1672 - if (write_nointr(ipc_sockets[1], "1", 1) < 0) 1673 - goto out; 1674 - close(ipc_sockets[1]); 1675 - 1676 - while (n_conns < NUM_CRASHING_COREDUMPS) { 1677 - int fd_coredump = -1, fd_peer_pidfd = -1, fd_core_file = -1; 1678 - struct coredump_req req = {}; 1679 - fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); 1680 - if (fd_coredump < 0) { 1681 - if (errno == EAGAIN || errno == EWOULDBLOCK) 1682 - continue; 1683 - goto out; 1684 - } 1685 - fd_peer_pidfd = get_peer_pidfd(fd_coredump); 1686 - if (fd_peer_pidfd < 0) 1687 - goto out; 1688 - if (!get_pidfd_info(fd_peer_pidfd, &info)) 1689 - goto out; 1690 - if (!(info.mask & PIDFD_INFO_COREDUMP) || !(info.coredump_mask & PIDFD_COREDUMPED)) 1691 - goto out; 1692 - if (!read_coredump_req(fd_coredump, &req)) 1693 - goto out; 1694 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, 1695 - COREDUMP_KERNEL | COREDUMP_USERSPACE | 1696 - COREDUMP_REJECT | COREDUMP_WAIT)) 1697 - goto out; 1698 - if (!send_coredump_ack(fd_coredump, &req, COREDUMP_KERNEL | COREDUMP_WAIT, 0)) 1699 - goto out; 1700 - if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) 1701 - goto out; 1702 - fd_core_file = open_coredump_tmpfile(self->fd_tmpfs_detached); 1703 - if (fd_core_file < 0) 1704 - goto out; 1705 - pid_t worker = fork(); 1706 - if (worker == 0) { 1707 - close(fd_server); 1708 - process_coredump_worker(fd_coredump, fd_peer_pidfd, fd_core_file); 1709 - } 1710 - worker_pids[n_conns] = worker; 1711 - if (fd_coredump >= 0) 1712 - close(fd_coredump); 1713 - if (fd_peer_pidfd >= 0) 1714 - close(fd_peer_pidfd); 1715 - if (fd_core_file >= 0) 1716 - close(fd_core_file); 1717 - n_conns++; 1718 - } 1719 - exit_code = EXIT_SUCCESS; 1720 - out: 1721 - if (fd_server >= 0) 1722 - close(fd_server); 1723 - 1724 - // Reap all worker processes 1725 - for (int i = 0; i < n_conns; i++) { 1726 - int wstatus; 1727 - if (waitpid(worker_pids[i], &wstatus, 0) < 0) { 1728 - fprintf(stderr, "Failed to wait for worker %d: %m\n", worker_pids[i]); 1729 - } else if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) != EXIT_SUCCESS) { 1730 - fprintf(stderr, "Worker %d exited with error code %d\n", worker_pids[i], WEXITSTATUS(wstatus)); 1731 - exit_code = EXIT_FAILURE; 1732 - } 1733 - } 1734 - 1735 - _exit(exit_code); 1736 - } 1737 - self->pid_coredump_server = pid_coredump_server; 1738 - 1739 - EXPECT_EQ(close(ipc_sockets[1]), 0); 1740 - ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); 1741 - EXPECT_EQ(close(ipc_sockets[0]), 0); 1742 - 1743 - for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1744 - pid[i] = fork(); 1745 - ASSERT_GE(pid[i], 0); 1746 - if (pid[i] == 0) 1747 - crashing_child(); 1748 - pidfd[i] = sys_pidfd_open(pid[i], 0); 1749 - ASSERT_GE(pidfd[i], 0); 1750 - } 1751 - 1752 - for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1753 - ASSERT_GE(waitpid(pid[i], &status[i], 0), 0); 1754 - ASSERT_TRUE(WIFSIGNALED(status[i])); 1755 - ASSERT_TRUE(WCOREDUMP(status[i])); 1756 - } 1757 - 1758 - for (int i = 0; i < NUM_CRASHING_COREDUMPS; i++) { 1759 - info.mask = PIDFD_INFO_EXIT | PIDFD_INFO_COREDUMP; 1760 - ASSERT_EQ(ioctl(pidfd[i], PIDFD_GET_INFO, &info), 0); 1761 - ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); 1762 - ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); 1763 - } 1764 - 1765 - wait_and_check_coredump_server(pid_coredump_server, _metadata, self); 1766 - } 1767 - 1768 - TEST_F(coredump, socket_invalid_paths) 1769 - { 1770 - ASSERT_FALSE(set_core_pattern("@ /tmp/coredump.socket")); 1771 - ASSERT_FALSE(set_core_pattern("@/tmp/../coredump.socket")); 1772 - ASSERT_FALSE(set_core_pattern("@../coredump.socket")); 1773 - ASSERT_FALSE(set_core_pattern("@/tmp/coredump.socket/..")); 1774 - ASSERT_FALSE(set_core_pattern("@..")); 1775 - 1776 - ASSERT_FALSE(set_core_pattern("@@ /tmp/coredump.socket")); 1777 - ASSERT_FALSE(set_core_pattern("@@/tmp/../coredump.socket")); 1778 - ASSERT_FALSE(set_core_pattern("@@../coredump.socket")); 1779 - ASSERT_FALSE(set_core_pattern("@@/tmp/coredump.socket/..")); 1780 - ASSERT_FALSE(set_core_pattern("@@..")); 1781 - 1782 - ASSERT_FALSE(set_core_pattern("@@@/tmp/coredump.socket")); 1783 209 } 1784 210 1785 211 TEST_HARNESS_MAIN