github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/vfork.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 <errno.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <unistd.h> 19 20 #include <string> 21 #include <utility> 22 23 #include "gmock/gmock.h" 24 #include "gtest/gtest.h" 25 #include "absl/flags/flag.h" 26 #include "absl/time/time.h" 27 #include "test/util/logging.h" 28 #include "test/util/multiprocess_util.h" 29 #include "test/util/test_util.h" 30 #include "test/util/time_util.h" 31 32 ABSL_FLAG(bool, vfork_test_child, false, 33 "If true, run the VforkTest child workload."); 34 35 namespace gvisor { 36 namespace testing { 37 38 namespace { 39 40 // We don't test with raw CLONE_VFORK to avoid interacting with glibc's use of 41 // TLS. 42 // 43 // Even with vfork(2), we must be careful to do little more in the child than 44 // call execve(2). We use the simplest sleep function possible, though this is 45 // still precarious, as we're officially only allowed to call execve(2) and 46 // _exit(2). 47 constexpr absl::Duration kChildDelay = absl::Seconds(10); 48 49 // Exit code for successful child subprocesses. We don't want to use 0 since 50 // it's too common, and an execve(2) failure causes the child to exit with the 51 // errno, so kChildExitCode is chosen to be an unlikely errno: 52 constexpr int kChildExitCode = 118; // ENOTNAM: Not a XENIX named type file 53 54 int64_t MonotonicNow() { 55 struct timespec now; 56 TEST_PCHECK(clock_gettime(CLOCK_MONOTONIC, &now) == 0); 57 return now.tv_sec * 1000000000ll + now.tv_nsec; 58 } 59 60 TEST(VforkTest, ParentStopsUntilChildExits) { 61 const auto test = [] { 62 // N.B. Run the test in a single-threaded subprocess because 63 // vfork is not safe in a multi-threaded process. 64 65 const int64_t start = MonotonicNow(); 66 67 pid_t pid = vfork(); 68 if (pid == 0) { 69 SleepSafe(kChildDelay); 70 _exit(kChildExitCode); 71 } 72 TEST_PCHECK_MSG(pid > 0, "vfork failed"); 73 MaybeSave(); 74 75 const int64_t end = MonotonicNow(); 76 77 absl::Duration dur = absl::Nanoseconds(end - start); 78 79 TEST_CHECK(dur >= kChildDelay); 80 81 int status = 0; 82 TEST_PCHECK(RetryEINTR(waitpid)(pid, &status, 0)); 83 TEST_CHECK(WIFEXITED(status)); 84 TEST_CHECK(WEXITSTATUS(status) == kChildExitCode); 85 }; 86 87 EXPECT_THAT(InForkedProcess(test), IsPosixErrorOkAndHolds(0)); 88 } 89 90 TEST(VforkTest, ParentStopsUntilChildExecves) { 91 ExecveArray const owned_child_argv = {"/proc/self/exe", "--vfork_test_child"}; 92 char* const* const child_argv = owned_child_argv.get(); 93 94 const auto test = [&] { 95 const int64_t start = MonotonicNow(); 96 97 pid_t pid = vfork(); 98 if (pid == 0) { 99 SleepSafe(kChildDelay); 100 execve(child_argv[0], child_argv, /* envp = */ nullptr); 101 _exit(errno); 102 } 103 // Don't attempt save/restore until after recording end_time, 104 // since the test expects an upper bound on the time spent 105 // stopped. 106 int saved_errno = errno; 107 const int64_t end = MonotonicNow(); 108 errno = saved_errno; 109 TEST_PCHECK_MSG(pid > 0, "vfork failed"); 110 MaybeSave(); 111 112 absl::Duration dur = absl::Nanoseconds(end - start); 113 114 // The parent should resume execution after execve, but before 115 // the post-execve test child exits. 116 TEST_CHECK(dur >= kChildDelay); 117 TEST_CHECK(dur <= 2 * kChildDelay); 118 119 int status = 0; 120 TEST_PCHECK(RetryEINTR(waitpid)(pid, &status, 0)); 121 TEST_CHECK(WIFEXITED(status)); 122 TEST_CHECK(WEXITSTATUS(status) == kChildExitCode); 123 }; 124 125 EXPECT_THAT(InForkedProcess(test), IsPosixErrorOkAndHolds(0)); 126 } 127 128 // A vfork child does not unstop the parent a second time when it exits after 129 // exec. 130 TEST(VforkTest, ExecedChildExitDoesntUnstopParent) { 131 ExecveArray const owned_child_argv = {"/proc/self/exe", "--vfork_test_child"}; 132 char* const* const child_argv = owned_child_argv.get(); 133 134 const auto test = [&] { 135 pid_t pid1 = vfork(); 136 if (pid1 == 0) { 137 execve(child_argv[0], child_argv, /* envp = */ nullptr); 138 _exit(errno); 139 } 140 TEST_PCHECK_MSG(pid1 > 0, "vfork failed"); 141 MaybeSave(); 142 143 // pid1 exec'd and is now sleeping. 144 SleepSafe(kChildDelay / 2); 145 146 const int64_t start = MonotonicNow(); 147 148 pid_t pid2 = vfork(); 149 if (pid2 == 0) { 150 SleepSafe(kChildDelay); 151 _exit(kChildExitCode); 152 } 153 TEST_PCHECK_MSG(pid2 > 0, "vfork failed"); 154 MaybeSave(); 155 156 const int64_t end = MonotonicNow(); 157 158 absl::Duration dur = absl::Nanoseconds(end - start); 159 160 // The parent should resume execution only after pid2 exits, not 161 // when pid1 exits. 162 TEST_CHECK(dur >= kChildDelay); 163 164 int status = 0; 165 TEST_PCHECK(RetryEINTR(waitpid)(pid1, &status, 0)); 166 TEST_CHECK(WIFEXITED(status)); 167 TEST_CHECK(WEXITSTATUS(status) == kChildExitCode); 168 169 TEST_PCHECK(RetryEINTR(waitpid)(pid2, &status, 0)); 170 TEST_CHECK(WIFEXITED(status)); 171 TEST_CHECK(WEXITSTATUS(status) == kChildExitCode); 172 }; 173 174 EXPECT_THAT(InForkedProcess(test), IsPosixErrorOkAndHolds(0)); 175 } 176 177 int RunChild() { 178 SleepSafe(kChildDelay); 179 return kChildExitCode; 180 } 181 182 } // namespace 183 184 } // namespace testing 185 } // namespace gvisor 186 187 int main(int argc, char** argv) { 188 gvisor::testing::TestInit(&argc, &argv); 189 190 if (absl::GetFlag(FLAGS_vfork_test_child)) { 191 return gvisor::testing::RunChild(); 192 } 193 194 return gvisor::testing::RunAllTests(); 195 }