|
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)); |
|
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)); |
|
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)); |
|
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. |
|
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)); |
|
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. |
|
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)); |
|
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". |
|
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 |
|
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 |