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 11namespace sandbox { 12 13// Tests the creation and destruction of the job. 14TEST(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)); 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". 37TEST(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)); 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 69TEST(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)); 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)); 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. 115TEST(JobTest, DoubleInit) { 116 // Create the job. 117 Job job; 118 ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0)); 119 ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0)); 120} 121 122// Tests the error case when we use a method and the object is not yet 123// initialized. 124TEST(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. 132TEST(JobTest, SecurityLevel) { 133 Job job1; 134 ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0)); 135 136 Job job2; 137 ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0)); 138 139 Job job3; 140 ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0)); 141 142 Job job4; 143 ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0)); 144 145 Job job5; 146 ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 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)); 151 152 Job job7; 153 ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init( 154 static_cast<JobLevel>(JOB_NONE+1), L"job7", 0)); 155} 156 157// Tests the method "AssignProcessToJob". 158TEST(JobTest, ProcessInJob) { 159 // Create the job. 160 Job job; 161 ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0)); 162 163 BOOL result = FALSE; 164 165 wchar_t notepad[] = L"notepad"; 166 STARTUPINFO si = { sizeof(si) }; 167 base::win::ScopedProcessInformation pi; 168 result = ::CreateProcess(NULL, notepad, NULL, NULL, FALSE, 0, NULL, NULL, &si, 169 pi.Receive()); 170 ASSERT_TRUE(result); 171 ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle())); 172 173 // Get the job handle. 174 HANDLE job_handle = job.Detach(); 175 176 // Check if the process is in the job. 177 JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0}; 178 DWORD size = sizeof(jbpidl); 179 result = ::QueryInformationJobObject(job_handle, 180 JobObjectBasicProcessIdList, 181 &jbpidl, size, &size); 182 EXPECT_TRUE(result); 183 184 EXPECT_EQ(1, jbpidl.NumberOfAssignedProcesses); 185 EXPECT_EQ(1, jbpidl.NumberOfProcessIdsInList); 186 EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]); 187 188 EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0)); 189 190 EXPECT_TRUE(::CloseHandle(job_handle)); 191} 192 193} // namespace sandbox 194