1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/win/src/job_unittest.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,193 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +// This file contains unit tests for the job object. 1.9 + 1.10 +#include "base/win/scoped_process_information.h" 1.11 +#include "sandbox/win/src/job.h" 1.12 +#include "testing/gtest/include/gtest/gtest.h" 1.13 + 1.14 +namespace sandbox { 1.15 + 1.16 +// Tests the creation and destruction of the job. 1.17 +TEST(JobTest, TestCreation) { 1.18 + // Scope the creation of Job. 1.19 + { 1.20 + // Create the job. 1.21 + Job job; 1.22 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0)); 1.23 + 1.24 + // check if the job exists. 1.25 + HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, 1.26 + L"my_test_job_name"); 1.27 + ASSERT_TRUE(job_handle != NULL); 1.28 + 1.29 + if (job_handle) 1.30 + CloseHandle(job_handle); 1.31 + } 1.32 + 1.33 + // Check if the job is destroyed when the object goes out of scope. 1.34 + HANDLE job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name"); 1.35 + ASSERT_TRUE(job_handle == NULL); 1.36 + ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); 1.37 +} 1.38 + 1.39 +// Tests the method "Detach". 1.40 +TEST(JobTest, TestDetach) { 1.41 + HANDLE job_handle; 1.42 + // Scope the creation of Job. 1.43 + { 1.44 + // Create the job. 1.45 + Job job; 1.46 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0)); 1.47 + 1.48 + job_handle = job.Detach(); 1.49 + ASSERT_TRUE(job_handle != NULL); 1.50 + } 1.51 + 1.52 + // Check to be sure that the job is still alive even after the object is gone 1.53 + // out of scope. 1.54 + HANDLE job_handle_dup = ::OpenJobObjectW(GENERIC_ALL, FALSE, 1.55 + L"my_test_job_name"); 1.56 + ASSERT_TRUE(job_handle_dup != NULL); 1.57 + 1.58 + // Remove all references. 1.59 + if (job_handle_dup) 1.60 + ::CloseHandle(job_handle_dup); 1.61 + 1.62 + if (job_handle) 1.63 + ::CloseHandle(job_handle); 1.64 + 1.65 + // Check if the jbo is really dead. 1.66 + job_handle = ::OpenJobObjectW(GENERIC_ALL, FALSE, L"my_test_job_name"); 1.67 + ASSERT_TRUE(job_handle == NULL); 1.68 + ASSERT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); 1.69 +} 1.70 + 1.71 +// Tests the ui exceptions 1.72 +TEST(JobTest, TestExceptions) { 1.73 + HANDLE job_handle; 1.74 + // Scope the creation of Job. 1.75 + { 1.76 + // Create the job. 1.77 + Job job; 1.78 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 1.79 + JOB_OBJECT_UILIMIT_READCLIPBOARD)); 1.80 + 1.81 + job_handle = job.Detach(); 1.82 + ASSERT_TRUE(job_handle != NULL); 1.83 + 1.84 + JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0}; 1.85 + DWORD size = sizeof(jbur); 1.86 + BOOL result = ::QueryInformationJobObject(job_handle, 1.87 + JobObjectBasicUIRestrictions, 1.88 + &jbur, size, &size); 1.89 + ASSERT_TRUE(result); 1.90 + 1.91 + ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 0); 1.92 + ::CloseHandle(job_handle); 1.93 + } 1.94 + 1.95 + // Scope the creation of Job. 1.96 + { 1.97 + // Create the job. 1.98 + Job job; 1.99 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0)); 1.100 + 1.101 + job_handle = job.Detach(); 1.102 + ASSERT_TRUE(job_handle != NULL); 1.103 + 1.104 + JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {0}; 1.105 + DWORD size = sizeof(jbur); 1.106 + BOOL result = ::QueryInformationJobObject(job_handle, 1.107 + JobObjectBasicUIRestrictions, 1.108 + &jbur, size, &size); 1.109 + ASSERT_TRUE(result); 1.110 + 1.111 + ASSERT_EQ(jbur.UIRestrictionsClass & JOB_OBJECT_UILIMIT_READCLIPBOARD, 1.112 + JOB_OBJECT_UILIMIT_READCLIPBOARD); 1.113 + ::CloseHandle(job_handle); 1.114 + } 1.115 +} 1.116 + 1.117 +// Tests the error case when the job is initialized twice. 1.118 +TEST(JobTest, DoubleInit) { 1.119 + // Create the job. 1.120 + Job job; 1.121 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_LOCKDOWN, L"my_test_job_name", 0)); 1.122 + ASSERT_EQ(ERROR_ALREADY_INITIALIZED, job.Init(JOB_LOCKDOWN, L"test", 0)); 1.123 +} 1.124 + 1.125 +// Tests the error case when we use a method and the object is not yet 1.126 +// initialized. 1.127 +TEST(JobTest, NoInit) { 1.128 + Job job; 1.129 + ASSERT_EQ(ERROR_NO_DATA, job.UserHandleGrantAccess(NULL)); 1.130 + ASSERT_EQ(ERROR_NO_DATA, job.AssignProcessToJob(NULL)); 1.131 + ASSERT_TRUE(job.Detach() == NULL); 1.132 +} 1.133 + 1.134 +// Tests the initialization of the job with different security level. 1.135 +TEST(JobTest, SecurityLevel) { 1.136 + Job job1; 1.137 + ASSERT_EQ(ERROR_SUCCESS, job1.Init(JOB_LOCKDOWN, L"job1", 0)); 1.138 + 1.139 + Job job2; 1.140 + ASSERT_EQ(ERROR_SUCCESS, job2.Init(JOB_RESTRICTED, L"job2", 0)); 1.141 + 1.142 + Job job3; 1.143 + ASSERT_EQ(ERROR_SUCCESS, job3.Init(JOB_LIMITED_USER, L"job3", 0)); 1.144 + 1.145 + Job job4; 1.146 + ASSERT_EQ(ERROR_SUCCESS, job4.Init(JOB_INTERACTIVE, L"job4", 0)); 1.147 + 1.148 + Job job5; 1.149 + ASSERT_EQ(ERROR_SUCCESS, job5.Init(JOB_UNPROTECTED, L"job5", 0)); 1.150 + 1.151 + // JOB_NONE means we run without a job object so Init should fail. 1.152 + Job job6; 1.153 + ASSERT_EQ(ERROR_BAD_ARGUMENTS, job6.Init(JOB_NONE, L"job6", 0)); 1.154 + 1.155 + Job job7; 1.156 + ASSERT_EQ(ERROR_BAD_ARGUMENTS, job7.Init( 1.157 + static_cast<JobLevel>(JOB_NONE+1), L"job7", 0)); 1.158 +} 1.159 + 1.160 +// Tests the method "AssignProcessToJob". 1.161 +TEST(JobTest, ProcessInJob) { 1.162 + // Create the job. 1.163 + Job job; 1.164 + ASSERT_EQ(ERROR_SUCCESS, job.Init(JOB_UNPROTECTED, L"job_test_process", 0)); 1.165 + 1.166 + BOOL result = FALSE; 1.167 + 1.168 + wchar_t notepad[] = L"notepad"; 1.169 + STARTUPINFO si = { sizeof(si) }; 1.170 + base::win::ScopedProcessInformation pi; 1.171 + result = ::CreateProcess(NULL, notepad, NULL, NULL, FALSE, 0, NULL, NULL, &si, 1.172 + pi.Receive()); 1.173 + ASSERT_TRUE(result); 1.174 + ASSERT_EQ(ERROR_SUCCESS, job.AssignProcessToJob(pi.process_handle())); 1.175 + 1.176 + // Get the job handle. 1.177 + HANDLE job_handle = job.Detach(); 1.178 + 1.179 + // Check if the process is in the job. 1.180 + JOBOBJECT_BASIC_PROCESS_ID_LIST jbpidl = {0}; 1.181 + DWORD size = sizeof(jbpidl); 1.182 + result = ::QueryInformationJobObject(job_handle, 1.183 + JobObjectBasicProcessIdList, 1.184 + &jbpidl, size, &size); 1.185 + EXPECT_TRUE(result); 1.186 + 1.187 + EXPECT_EQ(1, jbpidl.NumberOfAssignedProcesses); 1.188 + EXPECT_EQ(1, jbpidl.NumberOfProcessIdsInList); 1.189 + EXPECT_EQ(pi.process_id(), jbpidl.ProcessIdList[0]); 1.190 + 1.191 + EXPECT_TRUE(::TerminateProcess(pi.process_handle(), 0)); 1.192 + 1.193 + EXPECT_TRUE(::CloseHandle(job_handle)); 1.194 +} 1.195 + 1.196 +} // namespace sandbox