job_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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