Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2012 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 // This file contains unit tests for the job object.
      6 
      7 #include "base/win/scoped_process_information.h"
      8 #include "sandbox/win/src/job.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace sandbox {
     12 
     13 // Tests the creation and destruction of the job.
     14 TEST(JobTest, TestCreation) {
     15   // Scope the creation of Job.
     16   {
     17     // Create the job.
     18     Job job;
     19     ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
     20 
     21     // check if the job exists.
     22     HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE,
     23                                          L"my_test_job_name");
     24     ASSERT_TRUE(job_handle != NULL);
     25 
     26     if (job_handle)
     27       CloseHandle(job_handle);
     28   }
     29 
     30   // Check if the job is destroyed when the object goes out of scope.
     31   HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
     32   ASSERT_TRUE(job_handle == NULL);
     33   ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
     34 }
     35 
     36 // Tests the method "Detach".
     37 TEST(JobTest, TestDetach) {
     38   HANDLE job_handle;
     39   // Scope the creation of Job.
     40   {
     41     // Create the job.
     42     Job job;
     43     ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
     44 
     45     job_handle = job.Detach();
     46     ASSERT_TRUE(job_handle != NULL);
     47   }
     48 
     49   // Check to be sure that the job is still alive even after the object is gone
     50   // out of scope.
     51   HANDLE job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, FALSE,
     52                                            L"my_test_job_name");
     53   ASSERT_TRUE(job_handle_dup != NULL);
     54 
     55   // Remove all references.
     56   if (job_handle_dup)
     57     ::CloseHandle(job_handle_dup);
     58 
     59   if (job_handle)
     60     ::CloseHandle(job_handle);
     61 
     62   // Check if the jbo is really dead.
     63   job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name");
     64   ASSERT_TRUE(job_handle == NULL);
     65   ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError());
     66 }
     67 
     68 // Tests the ui exceptions
     69 TEST(JobTest, TestExceptions) {
     70   HANDLE job_handle;
     71   // Scope the creation of Job.
     72   {
     73     // Create the job.
     74     Job job;
     75     ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name",
     76                                       JOB_OBJECT_UILIMIT_READCLIPBOARD, 0));
     77 
     78     job_handle = job.Detach();
     79     ASSERT_TRUE(job_handle != NULL);
     80 
     81     JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
     82     DWORD size = sizeof(jbur);
     83     BOOL result = ::QueryInformationJobObject(job_handle,
     84                                               JobObjectBasicUIRestrictions,
     85                                               &jbur, size, &size);
     86     ASSERT_TRUE(result);
     87 
     88     ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 0);
     89     ::CloseHandle(job_handle);
     90   }
     91 
     92   // Scope the creation of Job.
     93   {
     94     // Create the job.
     95     Job job;
     96     ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
     97 
     98     job_handle = job.Detach();
     99     ASSERT_TRUE(job_handle != NULL);
    100 
    101     JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0};
    102     DWORD size = sizeof(jbur);
    103     BOOL result = ::QueryInformationJobObject(job_handle,
    104                                               JobObjectBasicUIRestrictions,
    105                                               &jbur, size, &size);
    106     ASSERT_TRUE(result);
    107 
    108     ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD,
    109               JOB_OBJECT_UILIMIT_READCLIPBOARD);
    110     ::CloseHandle(job_handle);
    111   }
    112 }
    113 
    114 // Tests the error case when the job is initialized twice.
    115 TEST(JobTest, DoubleInit) {
    116   // Create the job.
    117   Job job;
    118   ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0, 0));
    119   ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0, 0));
    120 }
    121 
    122 // Tests the error case when we use a method and the object is not yet
    123 // initialized.
    124 TEST(JobTest, NoInit) {
    125   Job job;
    126   ASSERT_EQ(ERROR_NO_DATA, job.UserHandleGrantAccess(NULL));
    127   ASSERT_EQ(ERROR_NO_DATA, job.AssignProcessToJob(NULL));
    128   ASSERT_TRUE(job.Detach() == NULL);
    129 }
    130 
    131 // Tests the initialization of the job with different security level.
    132 TEST(JobTest, SecurityLevel) {
    133   Job job1;
    134   ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0, 0));
    135 
    136   Job job2;
    137   ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0, 0));
    138 
    139   Job job3;
    140   ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0, 0));
    141 
    142   Job job4;
    143   ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0, 0));
    144 
    145   Job job5;
    146   ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0, 0));
    147 
    148   // JOB_NONE means we run without a job object so Init should fail.
    149   Job job6;
    150   ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0, 0));
    151 
    152   Job job7;
    153   ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init(
    154       static_cast<JobLevel>(JOB_NONE+1), L"job7", 0, 0));
    155 }
    156 
    157 // Tests the method "AssignProcessToJob".
    158 TEST(JobTest, ProcessInJob) {
    159   // Create the job.
    160   Job job;
    161   ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0,
    162                                     0));
    163 
    164   BOOL result = FALSE;
    165 
    166   wchar_t notepad[] = L"notepad";
    167   STARTUPINFO si = { sizeof(si) };
    168   PROCESS_INFORMATION temp_process_info = {};
    169   result = ::CreateProcess(NULL, notepad, NULL, NULL, FALSE, 0, NULL, NULL, &si,
    170                            &temp_process_info);
    171   ASSERT_TRUE(result);
    172   base::win::ScopedProcessInformation pi(temp_process_info);
    173   ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle()));
    174 
    175   // Get the job handle.
    176   HANDLE job_handle = job.Detach();
    177 
    178   // Check if the process is in the job.
    179   JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0};
    180   DWORD size = sizeof(jbpidl);
    181   result = ::QueryInformationJobObject(job_handle,
    182                                        JobObjectBasicProcessIdList,
    183                                        &jbpidl, size, &size);
    184   EXPECT_TRUE(result);
    185 
    186   EXPECT_EQ(1, jbpidl.NumberOfAssignedProcesses);
    187   EXPECT_EQ(1, jbpidl.NumberOfProcessIdsInList);
    188   EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]);
    189 
    190   EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0));
    191 
    192   EXPECT_TRUE(::CloseHandle(job_handle));
    193 }
    194 
    195 }  // namespace sandbox
    196