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