gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 <sys/socket.h> 23 #include <unistd.h> 24 25 #include <functional> 26 #include <string> 27 28 #include "gtest/gtest.h" 29 #include "absl/strings/str_cat.h" 30 #include "absl/strings/str_format.h" 31 #include "test/util/cleanup.h" 32 #include "test/util/file_descriptor.h" 33 #include "test/util/logging.h" 34 #include "test/util/posix_error.h" 35 #include "test/util/save_util.h" 36 #include "test/util/test_util.h" 37 38 namespace gvisor { 39 namespace testing { 40 41 namespace { 42 43 // exec_fn wraps a variant of the exec family, e.g. execve or execveat. 44 PosixErrorOr<Cleanup> ForkAndExecHelper(const std::function<void()>& exec_fn, 45 const std::function<void()>& fn, 46 pid_t* child, int* execve_errno) { 47 int pfds[2]; 48 int ret = pipe2(pfds, O_CLOEXEC); 49 if (ret < 0) { 50 return PosixError(errno, "pipe failed"); 51 } 52 FileDescriptor rfd(pfds[0]); 53 FileDescriptor wfd(pfds[1]); 54 55 int parent_stdout = dup(STDOUT_FILENO); 56 if (parent_stdout < 0) { 57 return PosixError(errno, "dup stdout"); 58 } 59 int parent_stderr = dup(STDERR_FILENO); 60 if (parent_stdout < 0) { 61 return PosixError(errno, "dup stderr"); 62 } 63 64 pid_t pid = fork(); 65 if (pid < 0) { 66 return PosixError(errno, "fork failed"); 67 } else if (pid == 0) { 68 // Child. 69 rfd.reset(); 70 if (dup2(parent_stdout, STDOUT_FILENO) < 0) { 71 _exit(3); 72 } 73 if (dup2(parent_stderr, STDERR_FILENO) < 0) { 74 _exit(4); 75 } 76 close(parent_stdout); 77 close(parent_stderr); 78 79 // Clean ourself up in case the parent doesn't. 80 if (prctl(PR_SET_PDEATHSIG, SIGKILL)) { 81 _exit(3); 82 } 83 84 if (fn) { 85 fn(); 86 } 87 88 // Call variant of exec function. 89 exec_fn(); 90 91 int error = errno; 92 if (WriteFd(pfds[1], &error, sizeof(error)) != sizeof(error)) { 93 // We can't do much if the write fails, but we can at least exit with a 94 // different code. 95 _exit(2); 96 } 97 _exit(1); 98 } 99 100 // Parent. 101 if (child) { 102 *child = pid; 103 } 104 105 auto cleanup = Cleanup([pid] { 106 kill(pid, SIGKILL); 107 RetryEINTR(waitpid)(pid, nullptr, 0); 108 }); 109 110 wfd.reset(); 111 112 int read_errno; 113 ret = ReadFd(rfd.get(), &read_errno, sizeof(read_errno)); 114 if (ret == 0) { 115 // Other end of the pipe closed, execve must have succeeded. 116 read_errno = 0; 117 } else if (ret < 0) { 118 return PosixError(errno, "read pipe failed"); 119 } else if (ret != sizeof(read_errno)) { 120 return PosixError(EPIPE, absl::StrCat("pipe read wrong size ", ret)); 121 } 122 123 if (execve_errno) { 124 *execve_errno = read_errno; 125 } 126 127 return std::move(cleanup); 128 } 129 130 } // namespace 131 132 PosixErrorOr<Cleanup> ForkAndExec(const std::string& filename, 133 const ExecveArray& argv, 134 const ExecveArray& envv, 135 const std::function<void()>& fn, pid_t* child, 136 int* execve_errno) { 137 char* const* argv_data = argv.get(); 138 char* const* envv_data = envv.get(); 139 const std::function<void()> exec_fn = [=] { 140 execve(filename.c_str(), argv_data, envv_data); 141 }; 142 return ForkAndExecHelper(exec_fn, fn, child, execve_errno); 143 } 144 145 PosixErrorOr<Cleanup> ForkAndExecveat(const int32_t dirfd, 146 const std::string& pathname, 147 const ExecveArray& argv, 148 const ExecveArray& envv, const int flags, 149 const std::function<void()>& fn, 150 pid_t* child, int* execve_errno) { 151 char* const* argv_data = argv.get(); 152 char* const* envv_data = envv.get(); 153 const std::function<void()> exec_fn = [=] { 154 syscall(__NR_execveat, dirfd, pathname.c_str(), argv_data, envv_data, 155 flags); 156 }; 157 return ForkAndExecHelper(exec_fn, fn, child, execve_errno); 158 } 159 160 PosixErrorOr<int> InForkedProcess(const std::function<void()>& fn) { 161 pid_t pid = fork(); 162 if (pid == 0) { 163 fn(); 164 TEST_CHECK_MSG(!::testing::Test::HasFailure(), 165 "EXPECT*/ASSERT* failed. These are not async-signal-safe " 166 "and must not be called from fn."); 167 _exit(0); 168 } 169 MaybeSave(); 170 if (pid < 0) { 171 return PosixError(errno, "fork failed"); 172 } 173 174 int status; 175 if (waitpid(pid, &status, 0) < 0) { 176 return PosixError(errno, "waitpid failed"); 177 } 178 179 return status; 180 } 181 182 PosixErrorOr<int> InForkedUserMountNamespace( 183 const std::function<void()>& parent, const std::function<void()>& child) { 184 std::string umap_str = absl::StrFormat("0 %lu 1", geteuid()); 185 std::string gmap_str = absl::StrFormat("0 %lu 1", getegid()); 186 int sync_sks[2] = {}; 187 TEST_CHECK_SUCCESS(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sync_sks)); 188 189 pid_t pid = fork(); 190 if (pid == 0) { 191 TEST_CHECK_SUCCESS(close(sync_sks[0])); 192 TEST_CHECK(unshare(CLONE_NEWNS | CLONE_NEWUSER) == 0); 193 194 // Setup uid and gid maps for child. 195 int fd = open("/proc/self/uid_map", O_WRONLY); 196 TEST_CHECK(fd > 0); 197 TEST_CHECK(write(fd, umap_str.c_str(), umap_str.size()) > 0); 198 TEST_CHECK(close(fd) == 0); 199 200 // setgroups isn't implemented in gVisor but is necessary for native 201 // tests. 202 fd = open("/proc/self/setgroups", O_WRONLY); 203 if (fd > 0) { 204 TEST_CHECK(write(fd, "deny", 4) > 0); 205 TEST_CHECK(close(fd) == 0); 206 } 207 208 fd = open("/proc/self/gid_map", O_WRONLY); 209 TEST_CHECK(fd > 0); 210 TEST_CHECK(write(fd, gmap_str.c_str(), gmap_str.size()) > 0); 211 TEST_CHECK(close(fd) == 0); 212 213 // Wait until uid and gid maps are setup. 214 TEST_CHECK(setuid(0) == 0); 215 TEST_CHECK(setgid(0) == 0); 216 217 // Mount/user namespace setup is complete. Now run the parent function. 218 TEST_CHECK_SUCCESS(shutdown(sync_sks[1], SHUT_WR)); 219 char s; 220 // Wait for the parent function to be complete. 221 TEST_CHECK(read(sync_sks[1], &s, 1) == 0); 222 TEST_CHECK_SUCCESS(close(sync_sks[1])); 223 // Parent function is complete. Now run the child function. 224 child(); 225 TEST_CHECK_MSG(!::testing::Test::HasFailure(), 226 "EXPECT*/ASSERT* failed. These are not async-signal-safe " 227 "and must not be called from fn."); 228 _exit(0); 229 } 230 MaybeSave(); 231 if (pid < 0) { 232 return PosixError(errno, "fork failed"); 233 } 234 235 close(sync_sks[1]); 236 char s; 237 // Wait for mount/user namespace setup to be complete. 238 TEST_CHECK_SUCCESS(read(sync_sks[0], &s, 1)); 239 parent(); 240 // Now start the child function. 241 TEST_CHECK_SUCCESS(close(sync_sks[0])); 242 243 int status; 244 if (waitpid(pid, &status, 0) < 0) { 245 return PosixError(errno, "waitpid failed"); 246 } 247 return status; 248 } 249 250 } // namespace testing 251 } // namespace gvisor