gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/processes.cc (about) 1 // Copyright 2021 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 <stdint.h> 16 #include <sys/mman.h> 17 #include <sys/syscall.h> 18 #include <unistd.h> 19 20 #include <algorithm> 21 #include <cstring> 22 #include <memory> 23 24 #include "gmock/gmock.h" 25 #include "gtest/gtest.h" 26 #include "absl/flags/flag.h" 27 #include "absl/strings/str_format.h" 28 #include "absl/strings/string_view.h" 29 #include "absl/time/clock.h" 30 #include "absl/time/time.h" 31 #include "test/util/capability_util.h" 32 #include "test/util/multiprocess_util.h" 33 #include "test/util/save_util.h" 34 #include "test/util/test_util.h" 35 #include "test/util/thread_util.h" 36 37 ABSL_FLAG(bool, processes_test_exec_swap, false, 38 "If true, run the ExecSwap function."); 39 ABSL_FLAG(int, processes_test_exec_swap_pre_clone_pid, -1, 40 "Process ID from before clone; required when using " 41 "--processes_test_exec_swap."); 42 ABSL_FLAG(int, processes_test_exec_swap_pre_clone_tid, -1, 43 "Thread ID from before clone; required when using " 44 "--processes_test_exec_swap."); 45 ABSL_FLAG(int, processes_test_exec_swap_pre_exec_pid, -1, 46 "Process ID from before exec; required when using " 47 "--processes_test_exec_swap."); 48 ABSL_FLAG(int, processes_test_exec_swap_pre_exec_tid, -1, 49 "Thread ID from before exec; required when using " 50 "--processes_test_exec_swap."); 51 ABSL_FLAG(int, processes_test_exec_swap_pipe_fd, -1, 52 "File descriptor to write data to; required when using " 53 "--processes_test_exec_swap."); 54 55 namespace gvisor { 56 namespace testing { 57 58 int testSetPGIDOfZombie(void* arg) { 59 int p[2]; 60 61 TEST_PCHECK(pipe(p) == 0); 62 63 pid_t pid = fork(); 64 if (pid == 0) { 65 pid = fork(); 66 // Create a second child to repeat one of syzkaller reproducers. 67 if (pid == 0) { 68 pid = getpid(); 69 TEST_PCHECK(setpgid(pid, 0) == 0); 70 TEST_PCHECK(WriteFd(p[1], &pid, sizeof(pid)) == sizeof(pid)); 71 _exit(0); 72 } 73 TEST_PCHECK(pid > 0); 74 _exit(0); 75 } 76 close(p[1]); 77 TEST_PCHECK(pid > 0); 78 79 // Get PID of the second child. 80 pid_t cpid; 81 TEST_PCHECK(ReadFd(p[0], &cpid, sizeof(cpid)) == sizeof(cpid)); 82 83 // Wait when both child processes will die. 84 int c; 85 TEST_PCHECK(ReadFd(p[0], &c, sizeof(c)) == 0); 86 87 // Wait the second child process to collect its zombie. 88 int status; 89 TEST_PCHECK(RetryEINTR(waitpid)(cpid, &status, 0) == cpid); 90 91 // Set the child's group. 92 TEST_PCHECK(setpgid(pid, pid) == 0); 93 94 TEST_PCHECK(RetryEINTR(waitpid)(-pid, &status, 0) == pid); 95 96 TEST_PCHECK(status == 0); 97 _exit(0); 98 } 99 100 TEST(Processes, SetPGIDOfZombie) { 101 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_SYS_ADMIN))); 102 103 // Fork a test process in a new PID namespace, because it needs to manipulate 104 // with reparented processes. 105 struct clone_arg { 106 // Reserve some space for clone() to locate arguments and retcode in this 107 // place. 108 char stack[128] __attribute__((aligned(16))); 109 char stack_ptr[0]; 110 } ca; 111 pid_t pid; 112 ASSERT_THAT(pid = clone(testSetPGIDOfZombie, ca.stack_ptr, 113 CLONE_NEWPID | SIGCHLD, &ca), 114 SyscallSucceeds()); 115 116 int status; 117 ASSERT_THAT(RetryEINTR(waitpid)(pid, &status, 0), 118 SyscallSucceedsWithValue(pid)); 119 EXPECT_EQ(status, 0); 120 } 121 122 void WritePIDToPipe(int* pipe_fds) { 123 pid_t child_pid; 124 TEST_PCHECK(child_pid = getpid()); 125 TEST_PCHECK(child_pid != gettid()); 126 TEST_PCHECK(WriteFd(pipe_fds[1], &child_pid, sizeof(child_pid)) == 127 sizeof(child_pid)); 128 } 129 130 TEST(Processes, TheadSharesSamePID) { 131 int pipe_fds[2]; 132 ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds()); 133 pid_t test_pid; 134 ASSERT_THAT(test_pid = getpid(), SyscallSucceeds()); 135 EXPECT_NE(test_pid, 0); 136 ScopedThread([&pipe_fds]() { WritePIDToPipe(pipe_fds); }).Join(); 137 ASSERT_THAT(close(pipe_fds[1]), SyscallSucceeds()); 138 pid_t pid_from_child; 139 TEST_PCHECK(ReadFd(pipe_fds[0], &pid_from_child, sizeof(pid_from_child)) == 140 sizeof(pid_from_child)); 141 int buf; 142 TEST_PCHECK(ReadFd(pipe_fds[0], &buf, sizeof(buf)) == 143 0); // Wait for cloned thread to exit 144 ASSERT_THAT(close(pipe_fds[0]), SyscallSucceeds()); 145 EXPECT_EQ(test_pid, pid_from_child); 146 } 147 148 TEST(Processes, ThousandsOfThreads) { 149 const DisableSave ds; // Too many syscalls. 150 const int kThreadCount = 1000; 151 const int kSyscallsPerThread = 1000; 152 std::unique_ptr<ScopedThread> threads[kThreadCount]; 153 int pipe_fds[2]; 154 ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds()); 155 156 for (int i = 0; i < kThreadCount; i++) { 157 threads[i] = std::make_unique<ScopedThread>([&pipe_fds]() { 158 char c; 159 EXPECT_THAT(ReadFd(pipe_fds[0], &c, 1), SyscallSucceedsWithValue(0)); 160 for (int j = 0; j < kSyscallsPerThread; j++) { 161 syscall(SYS_close, -1); 162 } 163 }); 164 } 165 close(pipe_fds[1]); 166 for (int i = 0; i < kThreadCount; i++) { 167 threads[i]->Join(); 168 } 169 } 170 171 // ExecSwapResult is used to carry PIDs and TIDs in ExecSwapThreadGroupLeader. 172 struct ExecSwapResult { 173 int pipe_fd; // FD to write result data to. 174 175 // PID and TID before we call clone(). 176 pid_t pre_clone_pid; 177 pid_t pre_clone_tid; 178 179 // PID and TID before the clone calls execv(). 180 pid_t pre_exec_pid; 181 pid_t pre_exec_tid; 182 183 // PID and TID after the execv(). 184 pid_t post_exec_pid; 185 pid_t post_exec_tid; 186 }; 187 188 // The number of elements in ExecSwapArg.execve_array. 189 constexpr int kExecveArraySize = 7; 190 191 // The size of the preallocated elements of execve_array that are populated 192 // in ExecSwapPreExec. Should be large enough to hold any flag string. 193 constexpr int kExecveArrayComponentsSize = 256; 194 195 // ExecSwapArg is passed as argument to ExecSwapPreExec. 196 struct ExecSwapArg { 197 // The pipe FD to write results to. 198 int pipe_fd; 199 200 // Data from prior to cloning. 201 pid_t pre_clone_pid; 202 pid_t pre_clone_tid; 203 204 // Pre-allocated array to use in execve, so that we can use it without doing 205 // allocations in ExecSwapPreExec. 206 char* execve_array[kExecveArraySize]; 207 }; 208 209 // ExecSwapPostExec is the third part of the ExecSwapThreadGroupLeader test. 210 // It is called after the test has fork()'d, clone()'d, and exec()'d into 211 // this. It writes all the PIDs and TIDs from each part of the test to a pipe. 212 int ExecSwapPostExec() { 213 std::cerr << "Test exec'd." << std::endl; 214 pid_t pid; 215 TEST_PCHECK(pid = getpid()); 216 pid_t tid; 217 TEST_PCHECK(tid = gettid()); 218 ExecSwapResult result; 219 result.pipe_fd = absl::GetFlag(FLAGS_processes_test_exec_swap_pipe_fd); 220 result.pre_clone_pid = 221 absl::GetFlag(FLAGS_processes_test_exec_swap_pre_clone_pid); 222 result.pre_clone_tid = 223 absl::GetFlag(FLAGS_processes_test_exec_swap_pre_clone_tid); 224 result.pre_exec_pid = 225 absl::GetFlag(FLAGS_processes_test_exec_swap_pre_exec_pid); 226 result.pre_exec_tid = 227 absl::GetFlag(FLAGS_processes_test_exec_swap_pre_exec_tid); 228 result.post_exec_pid = pid; 229 result.post_exec_tid = tid; 230 std::cerr << "Test writing results to pipe FD." << std::endl; 231 TEST_PCHECK(WriteFd(result.pipe_fd, &result, sizeof(result)) == 232 sizeof(result)); 233 if (close(result.pipe_fd) != 0) { 234 std::cerr << "Failed to close pipe FD: " << errno << std::endl; 235 } 236 std::cerr << "Test results written out." << std::endl; 237 return 0; 238 } 239 240 // ExecSwapPreExec is the second part of the ExecSwapThreadGroupLeader test. 241 // It is called after the test has fork()'d and clone()'d. 242 // It calls exec() with flags that cause the test binary to run 243 // ExecSwapPostExec. 244 [[noreturn]] int ExecSwapPreExec(void* void_arg) { 245 ExecSwapArg* arg = reinterpret_cast<ExecSwapArg*>(void_arg); 246 pid_t pid = getpid(); 247 TEST_PCHECK(pid > 0); 248 pid_t tid = gettid(); 249 TEST_PCHECK(tid > 0); 250 251 strncpy(arg->execve_array[0], "/proc/self/exe", kExecveArrayComponentsSize); 252 strncpy(arg->execve_array[1], "--processes_test_exec_swap", 253 kExecveArrayComponentsSize); 254 absl::SNPrintF(arg->execve_array[2], kExecveArrayComponentsSize, 255 "--processes_test_exec_swap_pre_clone_pid=%d", 256 arg->pre_clone_pid); 257 absl::SNPrintF(arg->execve_array[3], kExecveArrayComponentsSize, 258 "--processes_test_exec_swap_pre_clone_tid=%d", 259 arg->pre_clone_tid); 260 absl::SNPrintF(arg->execve_array[4], kExecveArrayComponentsSize, 261 "--processes_test_exec_swap_pre_exec_pid=%d", pid); 262 absl::SNPrintF(arg->execve_array[5], kExecveArrayComponentsSize, 263 "--processes_test_exec_swap_pre_exec_tid=%d", tid); 264 absl::SNPrintF(arg->execve_array[6], kExecveArrayComponentsSize, 265 "--processes_test_exec_swap_pipe_fd=%d", arg->pipe_fd); 266 std::cerr << "Test exec'ing:" << std::endl; 267 for (int i = 0; i < kExecveArraySize; ++i) { 268 std::cerr << " execve_array[" << i << "] = " << arg->execve_array[i] 269 << std::endl; 270 } 271 TEST_PCHECK(execv("/proc/self/exe", arg->execve_array) == 0); 272 _exit(1); // Should be unreachable. 273 } 274 275 // ExecSwapPreClone is the first part of the ExecSwapThreadGroupLeader test. 276 // It is called after the test has fork()'d. 277 // It calls clone() to run ExecSwapPreExec. 278 [[noreturn]] void ExecSwapPreClone(ExecSwapArg* exec_swap_arg) { 279 pid_t pid = getpid(); 280 TEST_PCHECK(pid > 0); 281 pid_t tid = gettid(); 282 TEST_PCHECK(tid > 0); 283 struct clone_arg { 284 char stack[4096] __attribute__((aligned(16))); 285 char stack_ptr[0]; 286 } ca; 287 exec_swap_arg->pre_clone_pid = pid; 288 exec_swap_arg->pre_clone_tid = tid; 289 std::cerr << "Test cloning." << std::endl; 290 TEST_PCHECK(clone(ExecSwapPreExec, ca.stack_ptr, 291 CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_FS, 292 exec_swap_arg) > 0); 293 // The clone thread will call exec, so just sit around here until it does. 294 while (true) { 295 absl::SleepFor(absl::Milliseconds(500)); 296 } 297 } 298 299 TEST(Processes, ExecSwapThreadGroupLeader) { 300 // This test verifies that a non-leading thread calling exec() replaces the 301 // former leader of its thread group and adopts its thread ID. 302 // This is the zeroth part of this test, which calls fork() to run 303 // ExecSwapPreClone in a separate thread group. 304 305 int pipe_fds[2]; 306 ASSERT_THAT(pipe(pipe_fds), SyscallSucceeds()); 307 pid_t test_pid; 308 ASSERT_THAT(test_pid = getpid(), SyscallSucceeds()); 309 pid_t test_tid; 310 ASSERT_THAT(test_tid = gettid(), SyscallSucceeds()); 311 312 // Preallocate ExecSwapArg ahead of fork(). 313 // This uses shared memory because we use it after fork()+clone(). 314 ExecSwapArg* exec_swap_arg = 315 (ExecSwapArg*)mmap(NULL, sizeof(ExecSwapArg), PROT_READ | PROT_WRITE, 316 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 317 ASSERT_NE(exec_swap_arg, MAP_FAILED); 318 exec_swap_arg->pipe_fd = pipe_fds[1]; 319 char* execve_array_component; 320 for (int i = 0; i < kExecveArraySize; ++i) { 321 execve_array_component = 322 (char*)mmap(NULL, kExecveArrayComponentsSize * sizeof(char), 323 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 324 ASSERT_NE(execve_array_component, MAP_FAILED); 325 exec_swap_arg->execve_array[i] = execve_array_component; 326 } 327 328 std::cerr << "Test forking." << std::endl; 329 pid_t fork_pid = fork(); 330 if (fork_pid == 0) { 331 ExecSwapPreClone(exec_swap_arg); 332 } 333 ASSERT_THAT(close(pipe_fds[1]), SyscallSucceeds()); 334 335 std::cerr << "Waiting for test results." << std::endl; 336 ExecSwapResult result; 337 TEST_PCHECK(ReadFd(pipe_fds[0], &result, sizeof(result)) == sizeof(result)); 338 339 std::cerr << "ExecSwap results:" << std::endl; 340 std::cerr << " Parent test process PID / TID:" << test_pid << " / " 341 << test_tid << std::endl; 342 std::cerr << " Parent test child PID, as seen by parent:" << fork_pid 343 << std::endl; 344 std::cerr << " Pre-clone PID / TID: " << result.pre_clone_pid << " / " 345 << result.pre_clone_tid << std::endl; 346 std::cerr << " Pre-exec PID / TID: " << result.pre_exec_pid << " / " 347 << result.pre_exec_tid << std::endl; 348 std::cerr << " Post-exec PID / TID: " << result.post_exec_pid << " / " 349 << result.post_exec_tid << std::endl; 350 351 ASSERT_THAT(close(pipe_fds[0]), SyscallSucceeds()); 352 353 // Test starts out as the thread group leader of itself. 354 EXPECT_EQ(test_pid, test_tid); 355 356 // The child is a different thread group altogether. 357 EXPECT_NE(test_pid, fork_pid); 358 EXPECT_EQ(fork_pid, result.pre_clone_pid); // Sanity check. 359 360 // Before cloning, PID == TID, the child thread is leader of its thread 361 // group. 362 EXPECT_EQ(result.pre_clone_pid, result.pre_clone_tid); 363 364 // PID should not change with clone. 365 EXPECT_EQ(result.pre_clone_pid, result.pre_exec_pid); 366 367 // But TID should change with clone. 368 EXPECT_NE(result.pre_clone_tid, result.pre_exec_tid); 369 370 // So we now have PID != TID. 371 EXPECT_NE(result.pre_exec_pid, result.pre_exec_tid); 372 373 // exec'ing does not change the PID, even when done from non-leader thread. 374 EXPECT_EQ(result.pre_exec_pid, result.post_exec_pid); 375 376 // After exec, the PID is back to matching TID. 377 EXPECT_EQ(result.post_exec_pid, result.post_exec_tid); 378 379 // The TID matches the one from before clone. 380 EXPECT_EQ(result.post_exec_tid, result.pre_clone_tid); 381 } 382 383 } // namespace testing 384 } // namespace gvisor 385 386 int main(int argc, char** argv) { 387 gvisor::testing::TestInit(&argc, &argv); 388 389 if (absl::GetFlag(FLAGS_processes_test_exec_swap)) { 390 return gvisor::testing::ExecSwapPostExec(); 391 } 392 return gvisor::testing::RunAllTests(); 393 }