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