gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/trace/workload/workload.cc (about) 1 // Copyright 2022 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <bits/types/struct_itimerspec.h> 16 #include <err.h> 17 #include <fcntl.h> 18 #include <sched.h> 19 #include <stdlib.h> 20 #include <sys/eventfd.h> 21 #include <sys/inotify.h> 22 #include <sys/mman.h> 23 #include <sys/resource.h> 24 #include <sys/signalfd.h> 25 #include <sys/socket.h> 26 #include <sys/stat.h> 27 #include <sys/timerfd.h> 28 #include <sys/types.h> 29 #include <sys/un.h> 30 #include <unistd.h> 31 32 #include <csignal> 33 #include <cstdio> 34 #include <iostream> 35 #include <ostream> 36 37 #include "absl/cleanup/cleanup.h" 38 #include "absl/strings/str_cat.h" 39 #include "absl/time/clock.h" 40 #include "test/util/eventfd_util.h" 41 #include "test/util/file_descriptor.h" 42 #include "test/util/memory_util.h" 43 #include "test/util/multiprocess_util.h" 44 #include "test/util/posix_error.h" 45 #include "test/util/test_util.h" 46 47 namespace gvisor { 48 namespace testing { 49 50 void runForkExecve() { 51 auto root_or_error = Open("/", O_RDONLY, 0); 52 auto& root = root_or_error.ValueOrDie(); 53 54 pid_t child; 55 int execve_errno; 56 ExecveArray argv = {"/bin/true"}; 57 ExecveArray envv = {"TEST=123"}; 58 auto kill_or_error = ForkAndExecveat(root.get(), "/bin/true", argv, envv, 0, 59 nullptr, &child, &execve_errno); 60 ASSERT_EQ(0, execve_errno); 61 // Don't kill child, just wait for gracefully exit. 62 kill_or_error.ValueOrDie().Release(); 63 RetryEINTR(waitpid)(child, nullptr, 0); 64 } 65 66 // Creates a simple UDS in the abstract namespace and send one byte from the 67 // client to the server. 68 void runSocket() { 69 auto path = absl::StrCat(std::string("\0", 1), "trace_test.", getpid(), 70 absl::GetCurrentTimeNanos()); 71 72 struct sockaddr_un addr; 73 addr.sun_family = AF_UNIX; 74 strncpy(addr.sun_path, path.c_str(), path.size() + 1); 75 76 int parent_sock = socket(AF_UNIX, SOCK_STREAM, 0); 77 if (parent_sock < 0) { 78 err(1, "socket"); 79 } 80 auto sock_closer = absl::MakeCleanup([parent_sock] { close(parent_sock); }); 81 82 if (bind(parent_sock, reinterpret_cast<struct sockaddr*>(&addr), 83 sizeof(addr))) { 84 err(1, "bind"); 85 } 86 if (listen(parent_sock, 5) < 0) { 87 err(1, "listen"); 88 } 89 90 pid_t pid = fork(); 91 if (pid < 0) { 92 // Fork error. 93 err(1, "fork"); 94 } else if (pid == 0) { 95 // Child. 96 close(parent_sock); // ensure it's not mistakely used in child. 97 98 int server = socket(AF_UNIX, SOCK_STREAM, 0); 99 if (server < 0) { 100 err(1, "socket"); 101 } 102 auto server_closer = absl::MakeCleanup([server] { close(server); }); 103 104 if (connect(server, reinterpret_cast<struct sockaddr*>(&addr), 105 sizeof(addr)) < 0) { 106 err(1, "connect"); 107 } 108 109 char buf = 'A'; 110 int bytes = write(server, &buf, sizeof(buf)); 111 if (bytes != 1) { 112 err(1, "write: %d", bytes); 113 } 114 exit(0); 115 116 } else { 117 // Parent. 118 int client = RetryEINTR(accept)(parent_sock, nullptr, nullptr); 119 if (client < 0) { 120 err(1, "accept"); 121 } 122 auto client_closer = absl::MakeCleanup([client] { close(client); }); 123 124 char buf; 125 int bytes = read(client, &buf, sizeof(buf)); 126 if (bytes != 1) { 127 err(1, "read: %d", bytes); 128 } 129 130 // Wait to reap the child. 131 RetryEINTR(waitpid)(pid, nullptr, 0); 132 } 133 } 134 135 void runReadWrite() { 136 const std::string path = "read-write.txt"; 137 auto fd_or = Open(path, O_RDWR | O_CREAT, 0644); 138 if (!fd_or.ok()) { 139 err(1, "open(O_CREAT): %s", fd_or.error().ToString().c_str()); 140 } 141 auto cleaup = absl::MakeCleanup([path] { unlink(path.c_str()); }); 142 143 auto fd = std::move(fd_or.ValueOrDie()); 144 145 // Test different flavors of write. 146 char msg[] = "hello world"; 147 if (WriteFd(fd.get(), msg, ABSL_ARRAYSIZE(msg)) < 0) { 148 err(1, "write"); 149 } 150 if (PwriteFd(fd.get(), msg, ABSL_ARRAYSIZE(msg), 10) < 0) { 151 err(1, "pwrite"); 152 } 153 154 struct iovec write_vecs[] = { 155 { 156 .iov_base = msg, 157 .iov_len = ABSL_ARRAYSIZE(msg), 158 }, 159 { 160 .iov_base = msg, 161 .iov_len = ABSL_ARRAYSIZE(msg) / 2, 162 }, 163 }; 164 if (writev(fd.get(), write_vecs, ABSL_ARRAYSIZE(write_vecs)) < 0) { 165 err(1, "writev"); 166 } 167 if (pwritev(fd.get(), write_vecs, ABSL_ARRAYSIZE(write_vecs), 10) < 0) { 168 err(1, "pwritev"); 169 } 170 if (pwritev2(fd.get(), write_vecs, ABSL_ARRAYSIZE(write_vecs), 10, 171 RWF_HIPRI) < 0) { 172 err(1, "pwritev2"); 173 } 174 175 // Rewind the file and test different flavors of read. 176 if (lseek(fd.get(), 0, SEEK_SET) < 0) { 177 err(1, "seek(0)"); 178 } 179 char buf[1024]; 180 if (ReadFd(fd.get(), buf, ABSL_ARRAYSIZE(buf)) < 0) { 181 err(1, "read"); 182 } 183 if (PreadFd(fd.get(), buf, ABSL_ARRAYSIZE(buf), 20) < 0) { 184 err(1, "read"); 185 } 186 187 // Reuse same buffer, since it's not using the result anyways. 188 struct iovec read_vecs[] = { 189 { 190 .iov_base = buf, 191 .iov_len = ABSL_ARRAYSIZE(msg), 192 }, 193 { 194 .iov_base = buf, 195 .iov_len = ABSL_ARRAYSIZE(msg) / 2, 196 }, 197 }; 198 if (readv(fd.get(), read_vecs, ABSL_ARRAYSIZE(read_vecs)) < 0) { 199 err(1, "writev"); 200 } 201 if (preadv(fd.get(), read_vecs, ABSL_ARRAYSIZE(read_vecs), 20) < 0) { 202 err(1, "pwritev"); 203 } 204 if (preadv2(fd.get(), read_vecs, ABSL_ARRAYSIZE(read_vecs), 20, RWF_HIPRI) < 205 0) { 206 err(1, "pwritev2"); 207 } 208 } 209 210 void runChdir() { 211 const auto pathname = "trace_test.abc"; 212 static constexpr mode_t kDefaultDirMode = 0755; 213 int path_or_error = mkdir(pathname, kDefaultDirMode); 214 if (path_or_error != 0) { 215 err(1, "mkdir"); 216 } 217 int res = chdir(pathname); 218 if (res != 0) { 219 err(1, "chdir"); 220 } 221 rmdir(pathname); 222 } 223 224 void runFchdir() { 225 const auto pathname = "trace_test.abc"; 226 static constexpr mode_t kDefaultDirMode = 0755; 227 int path_or_error = mkdir(pathname, kDefaultDirMode); 228 if (path_or_error != 0) { 229 err(1, "mkdir"); 230 } 231 int fd = open(pathname, O_DIRECTORY | O_RDONLY); 232 int res = fchdir(fd); 233 if (res != 0) { 234 err(1, "fchdir"); 235 } 236 rmdir(pathname); 237 close(fd); 238 } 239 240 void runSetgid() { 241 auto get = setgid(0); 242 if (get != 0) { 243 err(1, "setgid"); 244 } 245 } 246 247 void runSetuid() { 248 auto get = setuid(0); 249 if (get != 0) { 250 err(1, "setuid"); 251 } 252 } 253 254 void runSetsid() { 255 auto get = setsid(); 256 // Operation is not permitted so we get an error. 257 if (get != -1) { 258 err(1, "setsid"); 259 } 260 } 261 262 void runSetresuid() { 263 auto get = setresuid(0, 0, 0); 264 if (get != 0) { 265 err(1, "setresuid"); 266 } 267 } 268 269 void runSetresgid() { 270 auto get = setresgid(0, 0, 0); 271 if (get != 0) { 272 err(1, "setresgid"); 273 } 274 } 275 276 void runChroot() { 277 const auto pathname = "trace_test.abc"; 278 static constexpr mode_t kDefaultDirMode = 0755; 279 int path_or_error = mkdir(pathname, kDefaultDirMode); 280 if (path_or_error != 0) { 281 err(1, "mkdir"); 282 } 283 if (chroot(pathname)) { 284 err(1, "chroot"); 285 } 286 } 287 void runDup() { 288 const auto pathname = "trace_test.abc"; 289 static constexpr mode_t kDefaultDirMode = 0755; 290 int path_or_error = mkdir(pathname, kDefaultDirMode); 291 if (path_or_error != 0) { 292 err(1, "mkdir"); 293 } 294 int fd = open(pathname, O_DIRECTORY | O_RDONLY); 295 if (fd < 0) { 296 err(1, "open"); 297 } 298 int res = dup(fd); 299 if (res < 0) { 300 err(1, "dup"); 301 } 302 rmdir(pathname); 303 } 304 305 void runDup2() { 306 const auto pathname = "trace_test.abc"; 307 static constexpr mode_t kDefaultDirMode = 0755; 308 int path_or_error = mkdir(pathname, kDefaultDirMode); 309 if (path_or_error != 0) { 310 err(1, "mkdir"); 311 } 312 int oldfd = open(pathname, O_DIRECTORY | O_RDONLY); 313 if (oldfd < 0) { 314 err(1, "open"); 315 } 316 int newfd = open(pathname, O_DIRECTORY | O_RDONLY); 317 if (newfd < 0) { 318 err(1, "open"); 319 } 320 int res = dup2(oldfd, newfd); 321 if (res != newfd) { 322 err(1, "dup2"); 323 } 324 rmdir(pathname); 325 } 326 327 void runDup3() { 328 const auto pathname = "trace_test.abc"; 329 static constexpr mode_t kDefaultDirMode = 0755; 330 int path_or_error = mkdir(pathname, kDefaultDirMode); 331 if (path_or_error != 0) { 332 err(1, "mkdir"); 333 } 334 int oldfd = open(pathname, O_DIRECTORY | O_RDONLY); 335 if (oldfd < 0) { 336 err(1, "open"); 337 } 338 int newfd = open(pathname, O_DIRECTORY | O_RDONLY); 339 if (newfd < 0) { 340 err(1, "open"); 341 } 342 int res = dup3(oldfd, newfd, O_CLOEXEC); 343 if (res != newfd) { 344 err(1, "dup3"); 345 } 346 rmdir(pathname); 347 } 348 349 void runPrlimit64() { 350 struct rlimit setlim; 351 setlim.rlim_cur = 0; 352 setlim.rlim_max = RLIM_INFINITY; 353 int res = prlimit(0, RLIMIT_DATA, &setlim, nullptr); 354 if (res != 0) { 355 err(1, "prlimit64"); 356 } 357 } 358 359 void runEventfd() { 360 int res = eventfd(0, EFD_NONBLOCK); 361 if (res < 0) { 362 err(1, "eventfd"); 363 } 364 } 365 366 void runEventfd2() { 367 int res = Eventdfd2Setup(0, EFD_NONBLOCK); 368 if (res < 0) { 369 err(1, "eventfd2"); 370 } 371 } 372 373 void runBind() { 374 auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); 375 376 struct sockaddr_un addr; 377 addr.sun_family = AF_UNIX; 378 strncpy(addr.sun_path, path.c_str(), path.size() + 1); 379 380 int fd = socket(AF_UNIX, SOCK_STREAM, 0); 381 if (fd < 0) { 382 err(1, "socket"); 383 } 384 auto sock_closer = absl::MakeCleanup([fd] { close(fd); }); 385 386 if (bind(fd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr))) { 387 err(1, "bind"); 388 } 389 } 390 391 void runAccept() { 392 auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); 393 394 struct sockaddr_un addr; 395 addr.sun_family = AF_UNIX; 396 strncpy(addr.sun_path, path.c_str(), path.size() + 1); 397 398 int server = socket(AF_UNIX, SOCK_STREAM, 0); 399 if (server < 0) { 400 err(1, "socket"); 401 } 402 auto sock_closer = absl::MakeCleanup([server] { close(server); }); 403 404 if (bind(server, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { 405 err(1, "bind"); 406 } 407 408 if (listen(server, 5) < 0) { 409 err(1, "listen"); 410 } 411 412 int client = socket(AF_UNIX, SOCK_STREAM, 0); 413 if (client < 0) { 414 err(1, "socket"); 415 } 416 auto client_closer = absl::MakeCleanup([client] { close(client); }); 417 418 if (connect(client, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 419 0) { 420 err(1, "connect"); 421 } 422 423 int fd = RetryEINTR(accept)(server, nullptr, nullptr); 424 if (fd < 0) { 425 err(1, "accept"); 426 } 427 close(fd); 428 } 429 430 void runAccept4() { 431 auto path = absl::StrCat(std::string("\0", 1), "trace_test.abc"); 432 433 struct sockaddr_un addr; 434 addr.sun_family = AF_UNIX; 435 strncpy(addr.sun_path, path.c_str(), path.size() + 1); 436 437 int server = socket(AF_UNIX, SOCK_STREAM, 0); 438 if (server < 0) { 439 err(1, "socket"); 440 } 441 auto sock_closer = absl::MakeCleanup([server] { close(server); }); 442 443 if (bind(server, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { 444 err(1, "bind"); 445 } 446 447 if (listen(server, 5) < 0) { 448 err(1, "listen"); 449 } 450 451 int client = socket(AF_UNIX, SOCK_STREAM, 0); 452 if (client < 0) { 453 err(1, "socket"); 454 } 455 auto client_closer = absl::MakeCleanup([client] { close(client); }); 456 457 if (connect(client, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 458 0) { 459 err(1, "connect"); 460 } 461 462 int fd = RetryEINTR(accept4)(server, nullptr, nullptr, SOCK_CLOEXEC); 463 if (fd < 0) { 464 err(1, "accept4"); 465 } 466 close(fd); 467 } 468 469 void runSignalfd4() { 470 sigset_t mask; 471 sigemptyset(&mask); 472 int res = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK); 473 if (res < 0) { 474 err(1, "signalfd4"); 475 } 476 } 477 478 void runFcntl() { 479 const auto pathname = "trace_test.abc"; 480 static constexpr mode_t kDefaultDirMode = 0755; 481 int path_or_error = mkdir(pathname, kDefaultDirMode); 482 if (path_or_error != 0) { 483 err(1, "mkdir"); 484 } 485 int fd = open(pathname, O_DIRECTORY | O_RDONLY); 486 if (fd < 0) { 487 err(1, "open"); 488 } 489 auto fd_closer = absl::MakeCleanup([fd] { close(fd); }); 490 491 int res = fcntl(fd, F_GETFL); 492 if (res < 0) { 493 err(1, "fcntl"); 494 } 495 rmdir(pathname); 496 } 497 498 void runPipe() { 499 int fd[2]; 500 int res = pipe(fd); 501 if (res < 0) { 502 err(1, "pipe"); 503 } 504 close(fd[0]); 505 close(fd[1]); 506 } 507 508 void runPipe2() { 509 int fd[2]; 510 int res = pipe2(fd, O_CLOEXEC); 511 if (res < 0) { 512 err(1, "pipe2"); 513 } 514 close(fd[0]); 515 close(fd[1]); 516 } 517 518 void runTimerfdCreate() { 519 int fd = timerfd_create(CLOCK_REALTIME, 0); 520 if (fd < 0) { 521 err(1, "timerfd_create"); 522 } 523 close(fd); 524 } 525 526 void runTimerfdSettime() { 527 int fd = timerfd_create(CLOCK_REALTIME, 0); 528 if (fd < 0) { 529 err(1, "timerfd_create"); 530 } 531 auto fd_closer = absl::MakeCleanup([fd] { close(fd); }); 532 533 constexpr auto kInitial = absl::Milliseconds(10); 534 constexpr auto kInterval = absl::Milliseconds(25); 535 const itimerspec val = {absl::ToTimespec(kInitial), 536 absl::ToTimespec(kInterval)}; 537 int res = timerfd_settime(fd, TFD_TIMER_ABSTIME, &val, 0); 538 if (res < 0) { 539 err(1, "timerfd_settime"); 540 } 541 } 542 543 void runTimerfdGettime() { 544 int fd = timerfd_create(CLOCK_REALTIME, 0); 545 if (fd < 0) { 546 err(1, "timerfd_create"); 547 } 548 auto fd_closer = absl::MakeCleanup([fd] { close(fd); }); 549 550 itimerspec val; 551 int res = timerfd_gettime(fd, &val); 552 if (res < 0) { 553 err(1, "timerfd_gettime"); 554 } 555 } 556 // signalfd(2), fork(2), and vfork(2) system calls are not supported in arm 557 // architecture. 558 #ifdef __x86_64__ 559 void runFork() { 560 pid_t pid = syscall(__NR_fork); 561 if (pid < 0) { 562 err(1, "fork"); 563 } else if (pid == 0) { 564 exit(0); 565 } 566 RetryEINTR(waitpid)(pid, nullptr, 0); 567 } 568 569 void runVfork() { 570 pid_t pid = vfork(); 571 if (pid < 0) { 572 err(1, "vfork"); 573 } else if (pid == 0) { 574 _exit(0); 575 } 576 RetryEINTR(waitpid)(pid, nullptr, 0); 577 } 578 579 void runSignalfd() { 580 sigset_t mask; 581 sigemptyset(&mask); 582 constexpr int kSizeofKernelSigset = 8; 583 int res = syscall(__NR_signalfd, -1, &mask, kSizeofKernelSigset); 584 if (res < 0) { 585 err(1, "signalfd"); 586 } 587 } 588 #endif 589 590 void runClone() { 591 Mapping child_stack = ASSERT_NO_ERRNO_AND_VALUE( 592 MmapAnon(kPageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE)); 593 int child_pid; 594 child_pid = clone( 595 +[](void*) { return 0; }, 596 reinterpret_cast<void*>(child_stack.addr() + kPageSize), 597 SIGCHLD | CLONE_VFORK | CLONE_FILES, nullptr); 598 599 if (child_pid < 0) { 600 err(1, "clone"); 601 } 602 RetryEINTR(waitpid)(child_pid, nullptr, 0); 603 } 604 605 void runInotifyInit() { 606 int fd = inotify_init(); 607 if (fd < 0) { 608 err(1, "inotify_init"); 609 } 610 close(fd); 611 } 612 613 void runInotifyInit1() { 614 int fd = inotify_init1(IN_NONBLOCK); 615 if (fd < 0) { 616 err(1, "inotify_init1"); 617 } 618 close(fd); 619 } 620 621 void runInotifyAddWatch() { 622 const auto pathname = "timer_trace_test.abc"; 623 static constexpr mode_t kDefaultDirMode = 0755; 624 int path_or_error = mkdir(pathname, kDefaultDirMode); 625 if (path_or_error != 0) { 626 err(1, "mkdir"); 627 } 628 int fd = inotify_init1(IN_NONBLOCK); 629 if (fd < 0) { 630 err(1, "inotify_init1"); 631 } 632 auto fd_closer = absl::MakeCleanup([fd] { close(fd); }); 633 634 int res = inotify_add_watch(fd, pathname, IN_NONBLOCK); 635 if (res < 0) { 636 err(1, "inotify_add_watch"); 637 } 638 rmdir(pathname); 639 } 640 641 void runInotifyRmWatch() { 642 const auto pathname = "timer_trace_test.abc"; 643 static constexpr mode_t kDefaultDirMode = 0755; 644 int path_or_error = mkdir(pathname, kDefaultDirMode); 645 if (path_or_error != 0) { 646 err(1, "mkdir"); 647 } 648 int fd = inotify_init1(IN_NONBLOCK); 649 if (fd < 0) { 650 err(1, "inotify_init1"); 651 } 652 auto fd_closer = absl::MakeCleanup([fd] { close(fd); }); 653 654 int wd = inotify_add_watch(fd, pathname, IN_NONBLOCK); 655 if (wd < 0) { 656 err(1, "inotify_add_watch"); 657 } 658 int res = inotify_rm_watch(fd, wd); 659 if (res < 0) { 660 err(1, "inotify_rm_watch"); 661 } 662 rmdir(pathname); 663 } 664 665 } // namespace testing 666 } // namespace gvisor 667 668 int main(int argc, char** argv) { 669 ::gvisor::testing::runForkExecve(); 670 ::gvisor::testing::runSocket(); 671 ::gvisor::testing::runReadWrite(); 672 ::gvisor::testing::runChdir(); 673 ::gvisor::testing::runFchdir(); 674 ::gvisor::testing::runSetgid(); 675 ::gvisor::testing::runSetuid(); 676 ::gvisor::testing::runSetsid(); 677 ::gvisor::testing::runSetresuid(); 678 ::gvisor::testing::runSetresgid(); 679 ::gvisor::testing::runDup(); 680 ::gvisor::testing::runDup2(); 681 ::gvisor::testing::runDup3(); 682 ::gvisor::testing::runPrlimit64(); 683 ::gvisor::testing::runEventfd(); 684 ::gvisor::testing::runEventfd2(); 685 ::gvisor::testing::runBind(); 686 ::gvisor::testing::runAccept(); 687 ::gvisor::testing::runAccept4(); 688 ::gvisor::testing::runSignalfd4(); 689 ::gvisor::testing::runFcntl(); 690 ::gvisor::testing::runPipe(); 691 ::gvisor::testing::runPipe2(); 692 ::gvisor::testing::runTimerfdCreate(); 693 ::gvisor::testing::runTimerfdSettime(); 694 ::gvisor::testing::runTimerfdGettime(); 695 ::gvisor::testing::runClone(); 696 ::gvisor::testing::runInotifyInit(); 697 ::gvisor::testing::runInotifyInit1(); 698 ::gvisor::testing::runInotifyAddWatch(); 699 ::gvisor::testing::runInotifyRmWatch(); 700 // signalfd(2), fork(2), and vfork(2) system calls are not supported in arm 701 // architecture. 702 #ifdef __x86_64__ 703 ::gvisor::testing::runSignalfd(); 704 ::gvisor::testing::runFork(); 705 ::gvisor::testing::runVfork(); 706 #endif 707 // Run chroot at the end since it changes the root for all other tests. 708 ::gvisor::testing::runChroot(); 709 return 0; 710 }