Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(732)

Side by Side Diff: sandbox/win/src/target_process.cc

Issue 1263603002: Rework target process creation to minimize creation routes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Renamed token variables to reflect their lowbox status Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sandbox/win/src/target_process.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "sandbox/win/src/target_process.h" 5 #include "sandbox/win/src/target_process.h"
6 6
7 #include "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/macros.h" 8 #include "base/macros.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "base/win/pe_image.h" 10 #include "base/win/pe_image.h"
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 return exe; 58 return exe;
59 } 59 }
60 PIMAGE_NT_HEADERS nt_header = pe.GetNTHeaders(); 60 PIMAGE_NT_HEADERS nt_header = pe.GetNTHeaders();
61 char* base = reinterpret_cast<char*>(entry_point) - 61 char* base = reinterpret_cast<char*>(entry_point) -
62 nt_header->OptionalHeader.AddressOfEntryPoint; 62 nt_header->OptionalHeader.AddressOfEntryPoint;
63 63
64 ::FreeLibrary(exe); 64 ::FreeLibrary(exe);
65 return base; 65 return base;
66 } 66 }
67 67
68
69 TargetProcess::TargetProcess(base::win::ScopedHandle initial_token, 68 TargetProcess::TargetProcess(base::win::ScopedHandle initial_token,
70 base::win::ScopedHandle lockdown_token, 69 base::win::ScopedHandle lockdown_token,
71 HANDLE job, ThreadProvider* thread_pool) 70 base::win::ScopedHandle lowbox_token,
72 // This object owns everything initialized here except thread_pool and 71 HANDLE job,
73 // the job_ handle. The Job handle is closed by BrokerServices and results 72 ThreadProvider* thread_pool)
74 // eventually in a call to our dtor. 73 // This object owns everything initialized here except thread_pool and
74 // the job_ handle. The Job handle is closed by BrokerServices and results
75 // eventually in a call to our dtor.
75 : lockdown_token_(lockdown_token.Pass()), 76 : lockdown_token_(lockdown_token.Pass()),
76 initial_token_(initial_token.Pass()), 77 initial_token_(initial_token.Pass()),
78 lowbox_token_(lowbox_token.Pass()),
77 job_(job), 79 job_(job),
78 thread_pool_(thread_pool), 80 thread_pool_(thread_pool),
79 base_address_(NULL) { 81 base_address_(NULL) {}
80 }
81 82
82 TargetProcess::~TargetProcess() { 83 TargetProcess::~TargetProcess() {
83 DWORD exit_code = 0; 84 DWORD exit_code = 0;
84 // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE 85 // Give a chance to the process to die. In most cases the JOB_KILL_ON_CLOSE
85 // will take effect only when the context changes. As far as the testing went, 86 // will take effect only when the context changes. As far as the testing went,
86 // this wait was enough to switch context and kill the processes in the job. 87 // this wait was enough to switch context and kill the processes in the job.
87 // If this process is already dead, the function will return without waiting. 88 // If this process is already dead, the function will return without waiting.
88 // TODO(nsylvain): If the process is still alive at the end, we should kill 89 // TODO(nsylvain): If the process is still alive at the end, we should kill
89 // it. http://b/893891 90 // it. http://b/893891
90 // For now, this wait is there only to do a best effort to prevent some leaks 91 // For now, this wait is there only to do a best effort to prevent some leaks
(...skipping 18 matching lines...) Expand all
109 // ipc_server_ references our process handle, so make sure the former is shut 110 // ipc_server_ references our process handle, so make sure the former is shut
110 // down before the latter is closed (by ScopedProcessInformation). 111 // down before the latter is closed (by ScopedProcessInformation).
111 ipc_server_.reset(); 112 ipc_server_.reset();
112 } 113 }
113 114
114 // Creates the target (child) process suspended and assigns it to the job 115 // Creates the target (child) process suspended and assigns it to the job
115 // object. 116 // object.
116 DWORD TargetProcess::Create(const wchar_t* exe_path, 117 DWORD TargetProcess::Create(const wchar_t* exe_path,
117 const wchar_t* command_line, 118 const wchar_t* command_line,
118 bool inherit_handles, 119 bool inherit_handles,
119 bool set_lockdown_token_after_create,
120 const base::win::StartupInformation& startup_info, 120 const base::win::StartupInformation& startup_info,
121 base::win::ScopedProcessInformation* target_info) { 121 base::win::ScopedProcessInformation* target_info) {
122 if (set_lockdown_token_after_create && 122 if (lowbox_token_.IsValid() &&
123 base::win::GetVersion() < base::win::VERSION_WIN8) { 123 base::win::GetVersion() < base::win::VERSION_WIN8) {
124 // We don't allow set_lockdown_token_after_create below Windows 8. 124 // We don't allow lowbox_token below Windows 8.
125 return ERROR_INVALID_PARAMETER; 125 return ERROR_INVALID_PARAMETER;
126 } 126 }
127 127
128 exe_name_.reset(_wcsdup(exe_path)); 128 exe_name_.reset(_wcsdup(exe_path));
129 129
130 // the command line needs to be writable by CreateProcess(). 130 // the command line needs to be writable by CreateProcess().
131 scoped_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line)); 131 scoped_ptr<wchar_t, base::FreeDeleter> cmd_line(_wcsdup(command_line));
132 132
133 // Start the target process suspended. 133 // Start the target process suspended.
134 DWORD flags = 134 DWORD flags =
135 CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS; 135 CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS;
136 136
137 if (startup_info.has_extended_startup_info()) 137 if (startup_info.has_extended_startup_info())
138 flags |= EXTENDED_STARTUPINFO_PRESENT; 138 flags |= EXTENDED_STARTUPINFO_PRESENT;
139 139
140 if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) { 140 if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) {
141 // Windows 8 implements nested jobs, but for older systems we need to 141 // Windows 8 implements nested jobs, but for older systems we need to
142 // break out of any job we're in to enforce our restrictions. 142 // break out of any job we're in to enforce our restrictions.
143 flags |= CREATE_BREAKAWAY_FROM_JOB; 143 flags |= CREATE_BREAKAWAY_FROM_JOB;
144 } 144 }
145 145
146 base::win::ScopedHandle scoped_lockdown_token(lockdown_token_.Take());
147 PROCESS_INFORMATION temp_process_info = {}; 146 PROCESS_INFORMATION temp_process_info = {};
148 if (set_lockdown_token_after_create) { 147 if (!::CreateProcessAsUserW(lockdown_token_.Get(), exe_path, cmd_line.get(),
149 // First create process with a default token and then replace it later, 148 NULL, // No security attribute.
150 // after setting primary thread token. This is required for setting 149 NULL, // No thread attribute.
151 // an AppContainer token along with an impersonation token. 150 inherit_handles, flags,
152 if (!::CreateProcess(exe_path, 151 NULL, // Use the environment of the caller.
153 cmd_line.get(), 152 NULL, // Use current directory of the caller.
154 NULL, // No security attribute. 153 startup_info.startup_info(),
155 NULL, // No thread attribute. 154 &temp_process_info)) {
156 inherit_handles, 155 return ::GetLastError();
157 flags,
158 NULL, // Use the environment of the caller.
159 NULL, // Use current directory of the caller.
160 startup_info.startup_info(),
161 &temp_process_info)) {
162 return ::GetLastError();
163 }
164 } else {
165 if (!::CreateProcessAsUserW(scoped_lockdown_token.Get(),
166 exe_path,
167 cmd_line.get(),
168 NULL, // No security attribute.
169 NULL, // No thread attribute.
170 inherit_handles,
171 flags,
172 NULL, // Use the environment of the caller.
173 NULL, // Use current directory of the caller.
174 startup_info.startup_info(),
175 &temp_process_info)) {
176 return ::GetLastError();
177 }
178 } 156 }
179 base::win::ScopedProcessInformation process_info(temp_process_info); 157 base::win::ScopedProcessInformation process_info(temp_process_info);
180 158
181 DWORD win_result = ERROR_SUCCESS; 159 DWORD win_result = ERROR_SUCCESS;
182 160
183 if (job_) { 161 if (job_) {
184 // Assign the suspended target to the windows job object. 162 // Assign the suspended target to the windows job object.
185 if (!::AssignProcessToJobObject(job_, process_info.process_handle())) { 163 if (!::AssignProcessToJobObject(job_, process_info.process_handle())) {
186 win_result = ::GetLastError(); 164 win_result = ::GetLastError();
187 ::TerminateProcess(process_info.process_handle(), 0); 165 ::TerminateProcess(process_info.process_handle(), 0);
188 return win_result; 166 return win_result;
189 } 167 }
190 } 168 }
191 169
192 if (initial_token_.IsValid()) { 170 if (initial_token_.IsValid()) {
193 // Change the token of the main thread of the new process for the 171 // Change the token of the main thread of the new process for the
194 // impersonation token with more rights. This allows the target to start; 172 // impersonation token with more rights. This allows the target to start;
195 // otherwise it will crash too early for us to help. 173 // otherwise it will crash too early for us to help.
196 HANDLE temp_thread = process_info.thread_handle(); 174 HANDLE temp_thread = process_info.thread_handle();
197 if (!::SetThreadToken(&temp_thread, initial_token_.Get())) { 175 if (!::SetThreadToken(&temp_thread, initial_token_.Get())) {
198 win_result = ::GetLastError(); 176 win_result = ::GetLastError();
199 // It might be a security breach if we let the target run outside the job 177 // It might be a security breach if we let the target run outside the job
200 // so kill it before it causes damage. 178 // so kill it before it causes damage.
201 ::TerminateProcess(process_info.process_handle(), 0); 179 ::TerminateProcess(process_info.process_handle(), 0);
202 return win_result; 180 return win_result;
203 } 181 }
204 initial_token_.Close(); 182 initial_token_.Close();
205 } 183 }
206 184
207 if (set_lockdown_token_after_create) {
208 PROCESS_ACCESS_TOKEN process_access_token;
209 process_access_token.thread = process_info.thread_handle();
210 process_access_token.token = scoped_lockdown_token.Get();
211
212 NtSetInformationProcess SetInformationProcess = NULL;
213 ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess);
214
215 NTSTATUS status = SetInformationProcess(
216 process_info.process_handle(),
217 static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken),
218 &process_access_token,
219 sizeof(process_access_token));
220 if (!NT_SUCCESS(status)) {
221 win_result = ::GetLastError();
222 ::TerminateProcess(process_info.process_handle(), 0); // exit code
223 return win_result;
224 }
225 }
226
227 CONTEXT context; 185 CONTEXT context;
228 context.ContextFlags = CONTEXT_ALL; 186 context.ContextFlags = CONTEXT_ALL;
229 if (!::GetThreadContext(process_info.thread_handle(), &context)) { 187 if (!::GetThreadContext(process_info.thread_handle(), &context)) {
230 win_result = ::GetLastError(); 188 win_result = ::GetLastError();
231 ::TerminateProcess(process_info.process_handle(), 0); 189 ::TerminateProcess(process_info.process_handle(), 0);
232 return win_result; 190 return win_result;
233 } 191 }
234 192
235 #if defined(_WIN64) 193 #if defined(_WIN64)
236 void* entry_point = reinterpret_cast<void*>(context.Rcx); 194 void* entry_point = reinterpret_cast<void*>(context.Rcx);
237 #else 195 #else
238 #pragma warning(push) 196 #pragma warning(push)
239 #pragma warning(disable: 4312) 197 #pragma warning(disable: 4312)
240 // This cast generates a warning because it is 32 bit specific. 198 // This cast generates a warning because it is 32 bit specific.
241 void* entry_point = reinterpret_cast<void*>(context.Eax); 199 void* entry_point = reinterpret_cast<void*>(context.Eax);
242 #pragma warning(pop) 200 #pragma warning(pop)
243 #endif // _WIN64 201 #endif // _WIN64
244 202
245 if (!target_info->DuplicateFrom(process_info)) { 203 if (!target_info->DuplicateFrom(process_info)) {
246 win_result = ::GetLastError(); // This may or may not be correct. 204 win_result = ::GetLastError(); // This may or may not be correct.
247 ::TerminateProcess(process_info.process_handle(), 0); 205 ::TerminateProcess(process_info.process_handle(), 0);
248 return win_result; 206 return win_result;
249 } 207 }
250 208
209 if (lowbox_token_.IsValid()) {
210 PROCESS_ACCESS_TOKEN process_access_token;
211 process_access_token.thread = process_info.thread_handle();
212 process_access_token.token = lowbox_token_.Get();
213
214 NtSetInformationProcess SetInformationProcess = NULL;
215 ResolveNTFunctionPtr("NtSetInformationProcess", &SetInformationProcess);
216
217 NTSTATUS status = SetInformationProcess(
218 process_info.process_handle(),
219 static_cast<PROCESS_INFORMATION_CLASS>(NtProcessInformationAccessToken),
220 &process_access_token, sizeof(process_access_token));
221 if (!NT_SUCCESS(status)) {
222 win_result = ERROR_INVALID_TOKEN;
223 ::TerminateProcess(process_info.process_handle(), 0); // exit code
224 return win_result;
225 }
226 }
227
251 base_address_ = GetBaseAddress(exe_path, entry_point); 228 base_address_ = GetBaseAddress(exe_path, entry_point);
252 sandbox_process_info_.Set(process_info.Take()); 229 sandbox_process_info_.Set(process_info.Take());
253 return win_result; 230 return win_result;
254 } 231 }
255 232
256 ResultCode TargetProcess::TransferVariable(const char* name, void* address, 233 ResultCode TargetProcess::TransferVariable(const char* name, void* address,
257 size_t size) { 234 size_t size) {
258 if (!sandbox_process_info_.IsValid()) 235 if (!sandbox_process_info_.IsValid())
259 return SBOX_ERROR_UNEXPECTED_CALL; 236 return SBOX_ERROR_UNEXPECTED_CALL;
260 237
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
367 } 344 }
368 345
369 void TargetProcess::Terminate() { 346 void TargetProcess::Terminate() {
370 if (!sandbox_process_info_.IsValid()) 347 if (!sandbox_process_info_.IsValid())
371 return; 348 return;
372 349
373 ::TerminateProcess(sandbox_process_info_.process_handle(), 0); 350 ::TerminateProcess(sandbox_process_info_.process_handle(), 0);
374 } 351 }
375 352
376 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) { 353 TargetProcess* MakeTestTargetProcess(HANDLE process, HMODULE base_address) {
377 TargetProcess* target = new TargetProcess(base::win::ScopedHandle(), 354 TargetProcess* target =
378 base::win::ScopedHandle(), 355 new TargetProcess(base::win::ScopedHandle(), base::win::ScopedHandle(),
379 NULL, NULL); 356 base::win::ScopedHandle(), NULL, NULL);
380 PROCESS_INFORMATION process_info = {}; 357 PROCESS_INFORMATION process_info = {};
381 process_info.hProcess = process; 358 process_info.hProcess = process;
382 target->sandbox_process_info_.Set(process_info); 359 target->sandbox_process_info_.Set(process_info);
383 target->base_address_ = base_address; 360 target->base_address_ = base_address;
384 return target; 361 return target;
385 } 362 }
386 363
387 } // namespace sandbox 364 } // namespace sandbox
OLDNEW
« no previous file with comments | « sandbox/win/src/target_process.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698