github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/util/multiprocess_util.cc (about) 1 // Copyright 2018 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 "test/util/multiprocess_util.h" 16 17 #include <asm/unistd.h> 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <signal.h> 21 #include <sys/prctl.h> 22 #include <unistd.h> 23 24 #include "absl/strings/str_cat.h" 25 #include "test/util/cleanup.h" 26 #include "test/util/file_descriptor.h" 27 #include "test/util/posix_error.h" 28 #include "test/util/save_util.h" 29 #include "test/util/test_util.h" 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 // exec_fn wraps a variant of the exec family, e.g. execve or execveat. 37 PosixErrorOr<Cleanup> ForkAndExecHelper(const std::function<void()>& exec_fn, 38 const std::function<void()>& fn, 39 pid_t* child, int* execve_errno) { 40 int pfds[2]; 41 int ret = pipe2(pfds, O_CLOEXEC); 42 if (ret < 0) { 43 return PosixError(errno, "pipe failed"); 44 } 45 FileDescriptor rfd(pfds[0]); 46 FileDescriptor wfd(pfds[1]); 47 48 int parent_stdout = dup(STDOUT_FILENO); 49 if (parent_stdout < 0) { 50 return PosixError(errno, "dup stdout"); 51 } 52 int parent_stderr = dup(STDERR_FILENO); 53 if (parent_stdout < 0) { 54 return PosixError(errno, "dup stderr"); 55 } 56 57 pid_t pid = fork(); 58 if (pid < 0) { 59 return PosixError(errno, "fork failed"); 60 } else if (pid == 0) { 61 // Child. 62 rfd.reset(); 63 if (dup2(parent_stdout, STDOUT_FILENO) < 0) { 64 _exit(3); 65 } 66 if (dup2(parent_stderr, STDERR_FILENO) < 0) { 67 _exit(4); 68 } 69 close(parent_stdout); 70 close(parent_stderr); 71 72 // Clean ourself up in case the parent doesn't. 73 if (prctl(PR_SET_PDEATHSIG, SIGKILL)) { 74 _exit(3); 75 } 76 77 if (fn) { 78 fn(); 79 } 80 81 // Call variant of exec function. 82 exec_fn(); 83 84 int error = errno; 85 if (WriteFd(pfds[1], &error, sizeof(error)) != sizeof(error)) { 86 // We can't do much if the write fails, but we can at least exit with a 87 // different code. 88 _exit(2); 89 } 90 _exit(1); 91 } 92 93 // Parent. 94 if (child) { 95 *child = pid; 96 } 97 98 auto cleanup = Cleanup([pid] { 99 kill(pid, SIGKILL); 100 RetryEINTR(waitpid)(pid, nullptr, 0); 101 }); 102 103 wfd.reset(); 104 105 int read_errno; 106 ret = ReadFd(rfd.get(), &read_errno, sizeof(read_errno)); 107 if (ret == 0) { 108 // Other end of the pipe closed, execve must have succeeded. 109 read_errno = 0; 110 } else if (ret < 0) { 111 return PosixError(errno, "read pipe failed"); 112 } else if (ret != sizeof(read_errno)) { 113 return PosixError(EPIPE, absl::StrCat("pipe read wrong size ", ret)); 114 } 115 116 if (execve_errno) { 117 *execve_errno = read_errno; 118 } 119 120 return std::move(cleanup); 121 } 122 123 } // namespace 124 125 PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename, 126 const ExecveArray& argv, 127 const ExecveArray& envv, 128 const std::function<void()>& fn, pid_t* child, 129 int* execve_errno) { 130 char* const* argv_data = argv.get(); 131 char* const* envv_data = envv.get(); 132 const std::function<void()> exec_fn = [=] { 133 execve(filename.c_str(), argv_data, envv_data); 134 }; 135 return ForkAndExecHelper(exec_fn, fn, child, execve_errno); 136 } 137 138 PosixErrorOr<Cleanup> ForkAndExecveat(const int32_t dirfd, 139 const std::string& pathname, 140 const ExecveArray& argv, 141 const ExecveArray& envv, const int flags, 142 const std::function<void()>& fn, 143 pid_t* child, int* execve_errno) { 144 char* const* argv_data = argv.get(); 145 char* const* envv_data = envv.get(); 146 const std::function<void()> exec_fn = [=] { 147 syscall(__NR_execveat, dirfd, pathname.c_str(), argv_data, envv_data, 148 flags); 149 }; 150 return ForkAndExecHelper(exec_fn, fn, child, execve_errno); 151 } 152 153 PosixErrorOr<int> InForkedProcess(const std::function<void()>& fn) { 154 pid_t pid = fork(); 155 if (pid == 0) { 156 fn(); 157 TEST_CHECK_MSG(!::testing::Test::HasFailure(), 158 "EXPECT*/ASSERT* failed. These are not async-signal-safe " 159 "and must not be called from fn."); 160 _exit(0); 161 } 162 MaybeSave(); 163 if (pid < 0) { 164 return PosixError(errno, "fork failed"); 165 } 166 167 int status; 168 if (waitpid(pid, &status, 0) < 0) { 169 return PosixError(errno, "waitpid failed"); 170 } 171 172 return status; 173 } 174 175 } // namespace testing 176 } // namespace gvisor