| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // Some tests for the framework itself. | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "sandbox/win/src/sandbox.h" | |
| 10 #include "sandbox/win/src/sandbox_factory.h" | |
| 11 #include "sandbox/win/src/target_services.h" | |
| 12 #include "sandbox/win/tests/common/controller.h" | |
| 13 #include "testing/gtest/include/gtest/gtest.h" | |
| 14 | |
| 15 namespace sandbox { | |
| 16 | |
| 17 // Returns the current process state. | |
| 18 SBOX_TESTS_COMMAND int IntegrationTestsTest_state(int argc, wchar_t **argv) { | |
| 19 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) | |
| 20 return BEFORE_INIT; | |
| 21 | |
| 22 if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) | |
| 23 return BEFORE_REVERT; | |
| 24 | |
| 25 return AFTER_REVERT; | |
| 26 } | |
| 27 | |
| 28 // Returns the current process state, keeping track of it. | |
| 29 SBOX_TESTS_COMMAND int IntegrationTestsTest_state2(int argc, wchar_t **argv) { | |
| 30 static SboxTestsState state = MIN_STATE; | |
| 31 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) { | |
| 32 if (MIN_STATE == state) | |
| 33 state = BEFORE_INIT; | |
| 34 return state; | |
| 35 } | |
| 36 | |
| 37 if (!SandboxFactory::GetTargetServices()->GetState()->RevertedToSelf()) { | |
| 38 if (BEFORE_INIT == state) | |
| 39 state = BEFORE_REVERT; | |
| 40 return state; | |
| 41 } | |
| 42 | |
| 43 if (BEFORE_REVERT == state) | |
| 44 state = AFTER_REVERT; | |
| 45 return state; | |
| 46 } | |
| 47 | |
| 48 // Blocks the process for argv[0] milliseconds simulating stuck child. | |
| 49 SBOX_TESTS_COMMAND int IntegrationTestsTest_stuck(int argc, wchar_t **argv) { | |
| 50 int timeout = 500; | |
| 51 if (argc > 0) { | |
| 52 timeout = _wtoi(argv[0]); | |
| 53 } | |
| 54 | |
| 55 ::Sleep(timeout); | |
| 56 return 1; | |
| 57 } | |
| 58 | |
| 59 // Returns the number of arguments | |
| 60 SBOX_TESTS_COMMAND int IntegrationTestsTest_args(int argc, wchar_t **argv) { | |
| 61 for (int i = 0; i < argc; i++) { | |
| 62 wchar_t argument[20]; | |
| 63 size_t argument_bytes = wcslen(argv[i]) * sizeof(wchar_t); | |
| 64 memcpy(argument, argv[i], __min(sizeof(argument), argument_bytes)); | |
| 65 } | |
| 66 | |
| 67 return argc; | |
| 68 } | |
| 69 | |
| 70 // Creates a job and tries to run a process inside it. The function can be | |
| 71 // called with up to two parameters. The first one if set to "none" means that | |
| 72 // the child process should be run with the JOB_NONE JobLevel else it is run | |
| 73 // with JOB_LOCKDOWN level. The second if present specifies that the | |
| 74 // JOB_OBJECT_LIMIT_BREAKAWAY_OK flag should be set on the job object created | |
| 75 // in this function. The return value is either SBOX_TEST_SUCCEEDED if the test | |
| 76 // has passed or a value between 0 and 4 indicating which part of the test has | |
| 77 // failed. | |
| 78 SBOX_TESTS_COMMAND int IntegrationTestsTest_job(int argc, wchar_t **argv) { | |
| 79 HANDLE job = ::CreateJobObject(NULL, NULL); | |
| 80 if (!job) | |
| 81 return 0; | |
| 82 | |
| 83 JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limits; | |
| 84 if (!::QueryInformationJobObject(job, JobObjectExtendedLimitInformation, | |
| 85 &job_limits, sizeof(job_limits), NULL)) { | |
| 86 return 1; | |
| 87 } | |
| 88 // We cheat here and assume no 2-nd parameter means no breakaway flag and any | |
| 89 // value for the second param means with breakaway flag. | |
| 90 if (argc > 1) { | |
| 91 job_limits.BasicLimitInformation.LimitFlags |= | |
| 92 JOB_OBJECT_LIMIT_BREAKAWAY_OK; | |
| 93 } else { | |
| 94 job_limits.BasicLimitInformation.LimitFlags &= | |
| 95 ~JOB_OBJECT_LIMIT_BREAKAWAY_OK; | |
| 96 } | |
| 97 if (!::SetInformationJobObject(job, JobObjectExtendedLimitInformation, | |
| 98 &job_limits, sizeof(job_limits))) { | |
| 99 return 2; | |
| 100 } | |
| 101 if (!::AssignProcessToJobObject(job, ::GetCurrentProcess())) | |
| 102 return 3; | |
| 103 | |
| 104 JobLevel job_level = JOB_LOCKDOWN; | |
| 105 if (argc > 0 && wcscmp(argv[0], L"none") == 0) | |
| 106 job_level = JOB_NONE; | |
| 107 | |
| 108 TestRunner runner(job_level, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); | |
| 109 runner.SetTimeout(2000); | |
| 110 | |
| 111 if (1 != runner.RunTest(L"IntegrationTestsTest_args 1")) | |
| 112 return 4; | |
| 113 | |
| 114 // Terminate the job now. | |
| 115 ::TerminateJobObject(job, SBOX_TEST_SUCCEEDED); | |
| 116 // We should not make it to here but it doesn't mean our test failed. | |
| 117 return SBOX_TEST_SUCCEEDED; | |
| 118 } | |
| 119 | |
| 120 TEST(IntegrationTestsTest, CallsBeforeInit) { | |
| 121 TestRunner runner; | |
| 122 runner.SetTimeout(2000); | |
| 123 runner.SetTestState(BEFORE_INIT); | |
| 124 ASSERT_EQ(BEFORE_INIT, runner.RunTest(L"IntegrationTestsTest_state")); | |
| 125 } | |
| 126 | |
| 127 TEST(IntegrationTestsTest, CallsBeforeRevert) { | |
| 128 TestRunner runner; | |
| 129 runner.SetTimeout(2000); | |
| 130 runner.SetTestState(BEFORE_REVERT); | |
| 131 ASSERT_EQ(BEFORE_REVERT, runner.RunTest(L"IntegrationTestsTest_state")); | |
| 132 } | |
| 133 | |
| 134 TEST(IntegrationTestsTest, CallsAfterRevert) { | |
| 135 TestRunner runner; | |
| 136 runner.SetTimeout(2000); | |
| 137 runner.SetTestState(AFTER_REVERT); | |
| 138 ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state")); | |
| 139 } | |
| 140 | |
| 141 TEST(IntegrationTestsTest, CallsEveryState) { | |
| 142 TestRunner runner; | |
| 143 runner.SetTimeout(2000); | |
| 144 runner.SetTestState(EVERY_STATE); | |
| 145 ASSERT_EQ(AFTER_REVERT, runner.RunTest(L"IntegrationTestsTest_state2")); | |
| 146 } | |
| 147 | |
| 148 TEST(IntegrationTestsTest, ForwardsArguments) { | |
| 149 TestRunner runner; | |
| 150 runner.SetTimeout(2000); | |
| 151 runner.SetTestState(BEFORE_INIT); | |
| 152 ASSERT_EQ(1, runner.RunTest(L"IntegrationTestsTest_args first")); | |
| 153 ASSERT_EQ(4, runner.RunTest(L"IntegrationTestsTest_args first second third " | |
| 154 L"fourth")); | |
| 155 } | |
| 156 | |
| 157 TEST(IntegrationTestsTest, WaitForStuckChild) { | |
| 158 TestRunner runner; | |
| 159 runner.SetTimeout(2000); | |
| 160 runner.SetAsynchronous(true); | |
| 161 runner.SetKillOnDestruction(false); | |
| 162 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 163 runner.RunTest(L"IntegrationTestsTest_stuck 100")); | |
| 164 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 165 } | |
| 166 | |
| 167 TEST(IntegrationTestsTest, NoWaitForStuckChildNoJob) { | |
| 168 TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); | |
| 169 runner.SetTimeout(2000); | |
| 170 runner.SetAsynchronous(true); | |
| 171 runner.SetKillOnDestruction(false); | |
| 172 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 173 runner.RunTest(L"IntegrationTestsTest_stuck 2000")); | |
| 174 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 175 // In this case the processes are not tracked by the broker and should be | |
| 176 // still active. | |
| 177 DWORD exit_code; | |
| 178 ASSERT_TRUE(::GetExitCodeProcess(runner.process(), &exit_code)); | |
| 179 ASSERT_EQ(STILL_ACTIVE, exit_code); | |
| 180 // Terminate the test process now. | |
| 181 ::TerminateProcess(runner.process(), 0); | |
| 182 } | |
| 183 | |
| 184 TEST(IntegrationTestsTest, TwoStuckChildrenSecondOneHasNoJob) { | |
| 185 TestRunner runner; | |
| 186 runner.SetTimeout(2000); | |
| 187 runner.SetAsynchronous(true); | |
| 188 runner.SetKillOnDestruction(false); | |
| 189 TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); | |
| 190 runner2.SetTimeout(2000); | |
| 191 runner2.SetAsynchronous(true); | |
| 192 runner2.SetKillOnDestruction(false); | |
| 193 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 194 runner.RunTest(L"IntegrationTestsTest_stuck 100")); | |
| 195 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 196 runner2.RunTest(L"IntegrationTestsTest_stuck 2000")); | |
| 197 // Actually both runners share the same singleton broker. | |
| 198 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 199 // In this case the processes are not tracked by the broker and should be | |
| 200 // still active. | |
| 201 DWORD exit_code; | |
| 202 // Checking the exit code for |runner| is flaky on the slow bots but at | |
| 203 // least we know that the wait above has succeeded if we are here. | |
| 204 ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code)); | |
| 205 ASSERT_EQ(STILL_ACTIVE, exit_code); | |
| 206 // Terminate the test process now. | |
| 207 ::TerminateProcess(runner2.process(), 0); | |
| 208 } | |
| 209 | |
| 210 TEST(IntegrationTestsTest, TwoStuckChildrenFirstOneHasNoJob) { | |
| 211 TestRunner runner; | |
| 212 runner.SetTimeout(2000); | |
| 213 runner.SetAsynchronous(true); | |
| 214 runner.SetKillOnDestruction(false); | |
| 215 TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); | |
| 216 runner2.SetTimeout(2000); | |
| 217 runner2.SetAsynchronous(true); | |
| 218 runner2.SetKillOnDestruction(false); | |
| 219 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 220 runner2.RunTest(L"IntegrationTestsTest_stuck 2000")); | |
| 221 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 222 runner.RunTest(L"IntegrationTestsTest_stuck 100")); | |
| 223 // Actually both runners share the same singleton broker. | |
| 224 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 225 // In this case the processes are not tracked by the broker and should be | |
| 226 // still active. | |
| 227 DWORD exit_code; | |
| 228 // Checking the exit code for |runner| is flaky on the slow bots but at | |
| 229 // least we know that the wait above has succeeded if we are here. | |
| 230 ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code)); | |
| 231 ASSERT_EQ(STILL_ACTIVE, exit_code); | |
| 232 // Terminate the test process now. | |
| 233 ::TerminateProcess(runner2.process(), 0); | |
| 234 } | |
| 235 | |
| 236 TEST(IntegrationTestsTest, MultipleStuckChildrenSequential) { | |
| 237 TestRunner runner; | |
| 238 runner.SetTimeout(2000); | |
| 239 runner.SetAsynchronous(true); | |
| 240 runner.SetKillOnDestruction(false); | |
| 241 TestRunner runner2(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_LOCKDOWN); | |
| 242 runner2.SetTimeout(2000); | |
| 243 runner2.SetAsynchronous(true); | |
| 244 runner2.SetKillOnDestruction(false); | |
| 245 | |
| 246 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 247 runner.RunTest(L"IntegrationTestsTest_stuck 100")); | |
| 248 // Actually both runners share the same singleton broker. | |
| 249 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 250 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 251 runner2.RunTest(L"IntegrationTestsTest_stuck 2000")); | |
| 252 // Actually both runners share the same singleton broker. | |
| 253 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 254 | |
| 255 DWORD exit_code; | |
| 256 // Checking the exit code for |runner| is flaky on the slow bots but at | |
| 257 // least we know that the wait above has succeeded if we are here. | |
| 258 ASSERT_TRUE(::GetExitCodeProcess(runner2.process(), &exit_code)); | |
| 259 ASSERT_EQ(STILL_ACTIVE, exit_code); | |
| 260 // Terminate the test process now. | |
| 261 ::TerminateProcess(runner2.process(), 0); | |
| 262 | |
| 263 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 264 runner.RunTest(L"IntegrationTestsTest_stuck 100")); | |
| 265 // Actually both runners share the same singleton broker. | |
| 266 ASSERT_EQ(SBOX_ALL_OK, runner.broker()->WaitForAllTargets()); | |
| 267 } | |
| 268 | |
| 269 // Running from inside job that allows us to escape from it should be ok. | |
| 270 TEST(IntegrationTestsTest, RunChildFromInsideJob) { | |
| 271 TestRunner runner; | |
| 272 runner.SetUnsandboxed(true); | |
| 273 runner.SetTimeout(2000); | |
| 274 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 275 runner.RunTest(L"IntegrationTestsTest_job with_job escape_flag")); | |
| 276 } | |
| 277 | |
| 278 // Running from inside job that doesn't allow us to escape from it should fail | |
| 279 // on any windows prior to 8. | |
| 280 TEST(IntegrationTestsTest, RunChildFromInsideJobNoEscape) { | |
| 281 int expect_result = 4; // Means the runner has failed to execute the child. | |
| 282 // Check if we are on Win8 or newer and expect a success as newer windows | |
| 283 // versions support nested jobs. | |
| 284 OSVERSIONINFOEX version_info = { sizeof version_info }; | |
| 285 ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info)); | |
| 286 if (version_info.dwMajorVersion > 6 || | |
| 287 (version_info.dwMajorVersion == 6 && version_info.dwMinorVersion >= 2)) { | |
| 288 expect_result = SBOX_TEST_SUCCEEDED; | |
| 289 } | |
| 290 | |
| 291 TestRunner runner; | |
| 292 runner.SetUnsandboxed(true); | |
| 293 runner.SetTimeout(2000); | |
| 294 ASSERT_EQ(expect_result, | |
| 295 runner.RunTest(L"IntegrationTestsTest_job with_job")); | |
| 296 } | |
| 297 | |
| 298 // Running without a job object should be ok regardless of the fact that we are | |
| 299 // running inside an outter job. | |
| 300 TEST(IntegrationTestsTest, RunJoblessChildFromInsideJob) { | |
| 301 TestRunner runner; | |
| 302 runner.SetUnsandboxed(true); | |
| 303 runner.SetTimeout(2000); | |
| 304 ASSERT_EQ(SBOX_TEST_SUCCEEDED, | |
| 305 runner.RunTest(L"IntegrationTestsTest_job none")); | |
| 306 } | |
| 307 | |
| 308 } // namespace sandbox | |
| OLD | NEW |