Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 // This file implements the Windows service controlling Me2Me host processes | 5 // This file implements the Windows service controlling Me2Me host processes |
| 6 // running within user sessions. | 6 // running within user sessions. |
| 7 | 7 |
| 8 #include "remoting/host/win/wts_session_process_delegate.h" | 8 #include "remoting/host/win/wts_session_process_delegate.h" |
| 9 | 9 |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/macros.h" | 16 #include "base/macros.h" |
| 17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 18 #include "base/process/process_handle.h" | |
| 18 #include "base/single_thread_task_runner.h" | 19 #include "base/single_thread_task_runner.h" |
| 19 #include "base/strings/utf_string_conversions.h" | 20 #include "base/strings/utf_string_conversions.h" |
| 20 #include "base/threading/thread_task_runner_handle.h" | 21 #include "base/threading/thread_task_runner_handle.h" |
| 21 #include "base/win/scoped_handle.h" | 22 #include "base/win/scoped_handle.h" |
| 22 #include "ipc/attachment_broker.h" | 23 #include "ipc/attachment_broker.h" |
| 23 #include "ipc/ipc_channel.h" | 24 #include "ipc/ipc_channel.h" |
| 24 #include "ipc/ipc_channel_proxy.h" | 25 #include "ipc/ipc_channel_proxy.h" |
| 25 #include "ipc/ipc_listener.h" | 26 #include "ipc/ipc_listener.h" |
| 26 #include "ipc/ipc_message.h" | 27 #include "ipc/ipc_message.h" |
| 28 #include "mojo/edk/embedder/embedder.h" | |
| 29 #include "mojo/edk/embedder/named_platform_channel_pair.h" | |
| 30 #include "mojo/edk/embedder/platform_channel_pair.h" | |
| 31 #include "mojo/edk/embedder/platform_handle_utils.h" | |
| 32 #include "mojo/edk/embedder/scoped_platform_handle.h" | |
| 27 #include "remoting/host/host_main.h" | 33 #include "remoting/host/host_main.h" |
| 28 #include "remoting/host/ipc_constants.h" | 34 #include "remoting/host/ipc_constants.h" |
| 29 #include "remoting/host/ipc_util.h" | |
| 30 #include "remoting/host/switches.h" | 35 #include "remoting/host/switches.h" |
| 31 #include "remoting/host/win/launch_process_with_token.h" | 36 #include "remoting/host/win/launch_process_with_token.h" |
| 32 #include "remoting/host/win/security_descriptor.h" | 37 #include "remoting/host/win/security_descriptor.h" |
| 33 #include "remoting/host/win/worker_process_launcher.h" | 38 #include "remoting/host/win/worker_process_launcher.h" |
| 34 #include "remoting/host/win/wts_terminal_monitor.h" | 39 #include "remoting/host/win/wts_terminal_monitor.h" |
| 35 #include "remoting/host/worker_process_ipc_delegate.h" | 40 #include "remoting/host/worker_process_ipc_delegate.h" |
| 36 | 41 |
| 37 using base::win::ScopedHandle; | 42 using base::win::ScopedHandle; |
| 38 | 43 |
| 39 // Name of the default session desktop. | 44 // Name of the default session desktop. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 // Creates and initializes the job object that will sandbox the launched child | 99 // Creates and initializes the job object that will sandbox the launched child |
| 95 // processes. | 100 // processes. |
| 96 void InitializeJob(ScopedHandle job); | 101 void InitializeJob(ScopedHandle job); |
| 97 | 102 |
| 98 // Notified that the job object initialization is complete. | 103 // Notified that the job object initialization is complete. |
| 99 void InitializeJobCompleted(ScopedHandle job); | 104 void InitializeJobCompleted(ScopedHandle job); |
| 100 | 105 |
| 101 // Called when the number of processes running in the job reaches zero. | 106 // Called when the number of processes running in the job reaches zero. |
| 102 void OnActiveProcessZero(); | 107 void OnActiveProcessZero(); |
| 103 | 108 |
| 109 // Called when a process is launched in |job_|. | |
| 110 void OnProcessLaunchDetected(base::ProcessId pid); | |
| 111 | |
| 104 void ReportFatalError(); | 112 void ReportFatalError(); |
| 105 void ReportProcessLaunched(base::win::ScopedHandle worker_process); | 113 void ReportProcessLaunched(base::win::ScopedHandle worker_process, |
| 114 mojo::edk::ScopedPlatformHandle server_handle); | |
| 106 | 115 |
| 107 // The task runner all public methods of this class should be called on. | 116 // The task runner all public methods of this class should be called on. |
| 108 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; | 117 scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_; |
| 109 | 118 |
| 110 // The task runner serving job object notifications. | 119 // The task runner serving job object notifications. |
| 111 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | 120 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; |
| 112 | 121 |
| 113 // The server end of the IPC channel used to communicate to the worker | 122 // The server end of the IPC channel used to communicate to the worker |
| 114 // process. | 123 // process. |
| 115 std::unique_ptr<IPC::ChannelProxy> channel_; | 124 std::unique_ptr<IPC::ChannelProxy> channel_; |
| 116 | 125 |
| 117 // Security descriptor (as SDDL) to be applied to |channel_|. | 126 // Security descriptor (as SDDL) to be applied to |channel_|. |
| 118 std::string channel_security_; | 127 std::string channel_security_; |
| 119 | 128 |
| 120 // Security descriptor (as SDDL) to be applied to the newly created process. | 129 // Security descriptor (as SDDL) to be applied to the newly created process. |
| 121 std::string new_process_security_; | 130 std::string new_process_security_; |
| 122 | 131 |
| 123 WorkerProcessLauncher* event_handler_; | 132 WorkerProcessLauncher* event_handler_; |
| 124 | 133 |
| 125 // Pointer to GetNamedPipeClientProcessId() API if it is available. | |
| 126 typedef BOOL (WINAPI * GetNamedPipeClientProcessIdFn)(HANDLE, DWORD*); | |
| 127 GetNamedPipeClientProcessIdFn get_named_pipe_client_pid_; | |
| 128 | |
| 129 // The job object used to control the lifetime of child processes. | 134 // The job object used to control the lifetime of child processes. |
| 130 base::win::ScopedHandle job_; | 135 base::win::ScopedHandle job_; |
| 131 | 136 |
| 132 // True if the worker process should be launched elevated. | 137 // True if the worker process should be launched elevated. |
| 133 bool launch_elevated_; | 138 bool launch_elevated_; |
| 134 | 139 |
| 135 // True if a laucnh attemp is pending. | 140 // True if a laucnh attemp is pending. |
| 136 bool launch_pending_; | 141 bool launch_pending_; |
| 137 | 142 |
| 138 // The named pipe used as the transport by |channel_|. | |
| 139 base::win::ScopedHandle pipe_; | |
| 140 | |
| 141 // The token to be used to launch a process in a different session. | 143 // The token to be used to launch a process in a different session. |
| 142 base::win::ScopedHandle session_token_; | 144 base::win::ScopedHandle session_token_; |
| 143 | 145 |
| 144 // Command line of the launched process. | 146 // Command line of the launched process. |
| 145 std::unique_ptr<base::CommandLine> target_command_; | 147 std::unique_ptr<base::CommandLine> target_command_; |
| 146 | 148 |
| 147 // The handle of the worker process, if launched. | 149 // The handle of the worker process, if launched. |
| 148 base::win::ScopedHandle worker_process_; | 150 base::win::ScopedHandle worker_process_; |
| 149 | 151 |
| 152 // If launching elevated, this holds the server handle after launch, until | |
| 153 // the final process launches. | |
| 154 mojo::edk::ScopedPlatformHandle elevated_server_handle_; | |
| 155 | |
| 156 // If launching elevated, this is the pid of the launcher process. | |
| 157 base::ProcessId elevated_launcher_pid_ = base::kNullProcessId; | |
| 158 | |
| 159 // The mojo child token for the process being launched. | |
| 160 std::string mojo_child_token_; | |
| 161 | |
| 150 DISALLOW_COPY_AND_ASSIGN(Core); | 162 DISALLOW_COPY_AND_ASSIGN(Core); |
| 151 }; | 163 }; |
| 152 | 164 |
| 153 WtsSessionProcessDelegate::Core::Core( | 165 WtsSessionProcessDelegate::Core::Core( |
| 154 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | 166 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, |
| 155 std::unique_ptr<base::CommandLine> target_command, | 167 std::unique_ptr<base::CommandLine> target_command, |
| 156 bool launch_elevated, | 168 bool launch_elevated, |
| 157 const std::string& channel_security, | 169 const std::string& channel_security, |
| 158 const std::string& new_process_security) | 170 const std::string& new_process_security) |
| 159 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 171 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 160 io_task_runner_(io_task_runner), | 172 io_task_runner_(io_task_runner), |
| 161 channel_security_(channel_security), | 173 channel_security_(channel_security), |
| 162 new_process_security_(new_process_security), | 174 new_process_security_(new_process_security), |
| 163 event_handler_(nullptr), | 175 event_handler_(nullptr), |
| 164 get_named_pipe_client_pid_(nullptr), | |
| 165 launch_elevated_(launch_elevated), | 176 launch_elevated_(launch_elevated), |
| 166 launch_pending_(false), | 177 launch_pending_(false), |
| 167 target_command_(std::move(target_command)) {} | 178 target_command_(std::move(target_command)) {} |
| 168 | 179 |
| 169 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { | 180 bool WtsSessionProcessDelegate::Core::Initialize(uint32_t session_id) { |
| 170 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 181 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 171 | 182 |
| 172 if (launch_elevated_) { | 183 if (launch_elevated_) { |
| 173 // GetNamedPipeClientProcessId() is available starting from Vista. | 184 // GetNamedPipeClientProcessId() is available starting from Vista. |
| 174 HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); | 185 HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); |
| 175 CHECK(kernel32 != nullptr); | 186 CHECK(kernel32 != nullptr); |
| 176 | 187 |
| 177 get_named_pipe_client_pid_ = | |
| 178 reinterpret_cast<GetNamedPipeClientProcessIdFn>( | |
| 179 GetProcAddress(kernel32, "GetNamedPipeClientProcessId")); | |
| 180 CHECK(get_named_pipe_client_pid_ != nullptr); | |
| 181 | |
| 182 ScopedHandle job; | 188 ScopedHandle job; |
| 183 job.Set(CreateJobObject(nullptr, nullptr)); | 189 job.Set(CreateJobObject(nullptr, nullptr)); |
| 184 if (!job.IsValid()) { | 190 if (!job.IsValid()) { |
| 185 PLOG(ERROR) << "Failed to create a job object"; | 191 PLOG(ERROR) << "Failed to create a job object"; |
| 186 return false; | 192 return false; |
| 187 } | 193 } |
| 188 | 194 |
| 189 // Limit the number of active processes in the job to two (the helper | 195 // Limit the number of active processes in the job to two (the helper |
| 190 // process performing elevation and the worker process itself) and make sure | 196 // process performing elevation and the worker process itself) and make sure |
| 191 // that all processes will be killed once the job object is destroyed. | 197 // that all processes will be killed once the job object is destroyed. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 | 252 |
| 247 void WtsSessionProcessDelegate::Core::CloseChannel() { | 253 void WtsSessionProcessDelegate::Core::CloseChannel() { |
| 248 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 254 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 249 | 255 |
| 250 if (!channel_) | 256 if (!channel_) |
| 251 return; | 257 return; |
| 252 | 258 |
| 253 IPC::AttachmentBroker::GetGlobal()->DeregisterCommunicationChannel( | 259 IPC::AttachmentBroker::GetGlobal()->DeregisterCommunicationChannel( |
| 254 channel_.get()); | 260 channel_.get()); |
| 255 channel_.reset(); | 261 channel_.reset(); |
| 256 pipe_.Close(); | 262 elevated_server_handle_.reset(); |
| 263 elevated_launcher_pid_ = base::kNullProcessId; | |
| 264 if (!mojo_child_token_.empty()) { | |
| 265 mojo::edk::ChildProcessLaunchFailed(mojo_child_token_); | |
| 266 mojo_child_token_.clear(); | |
| 267 } | |
| 257 } | 268 } |
| 258 | 269 |
| 259 void WtsSessionProcessDelegate::Core::KillProcess() { | 270 void WtsSessionProcessDelegate::Core::KillProcess() { |
| 260 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 271 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 261 | 272 |
| 262 CloseChannel(); | 273 CloseChannel(); |
| 263 | 274 |
| 264 event_handler_ = nullptr; | 275 event_handler_ = nullptr; |
| 265 launch_pending_ = false; | 276 launch_pending_ = false; |
| 266 | 277 |
| 267 if (launch_elevated_) { | 278 if (launch_elevated_) { |
| 268 if (job_.IsValid()) | 279 if (job_.IsValid()) |
| 269 TerminateJobObject(job_.Get(), CONTROL_C_EXIT); | 280 TerminateJobObject(job_.Get(), CONTROL_C_EXIT); |
| 270 } else { | 281 } else { |
| 271 if (worker_process_.IsValid()) | 282 if (worker_process_.IsValid()) |
| 272 TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT); | 283 TerminateProcess(worker_process_.Get(), CONTROL_C_EXIT); |
| 273 } | 284 } |
| 274 | 285 |
| 275 worker_process_.Close(); | 286 worker_process_.Close(); |
| 276 } | 287 } |
| 277 | 288 |
| 278 WtsSessionProcessDelegate::Core::~Core() { | 289 WtsSessionProcessDelegate::Core::~Core() { |
| 279 DCHECK(!channel_); | 290 DCHECK(!channel_); |
| 280 DCHECK(!event_handler_); | 291 DCHECK(!event_handler_); |
| 281 DCHECK(!pipe_.IsValid()); | |
| 282 DCHECK(!worker_process_.IsValid()); | 292 DCHECK(!worker_process_.IsValid()); |
| 283 } | 293 } |
| 284 | 294 |
| 285 void WtsSessionProcessDelegate::Core::OnIOCompleted( | 295 void WtsSessionProcessDelegate::Core::OnIOCompleted( |
| 286 base::MessagePumpForIO::IOContext* context, | 296 base::MessagePumpForIO::IOContext* context, |
| 287 DWORD bytes_transferred, | 297 DWORD bytes_transferred, |
| 288 DWORD error) { | 298 DWORD error) { |
| 289 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 299 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 290 | 300 |
| 291 // |bytes_transferred| is used in job object notifications to supply | 301 // |bytes_transferred| is used in job object notifications to supply |
| 292 // the message ID; |context| carries process ID. | 302 // the message ID; |context| carries process ID. |
| 293 if (bytes_transferred == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { | 303 switch (bytes_transferred) { |
| 294 caller_task_runner_->PostTask(FROM_HERE, | 304 case JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO: { |
| 295 base::Bind(&Core::OnActiveProcessZero, this)); | 305 caller_task_runner_->PostTask( |
| 306 FROM_HERE, base::Bind(&Core::OnActiveProcessZero, this)); | |
| 307 break; | |
| 308 } | |
| 309 case JOB_OBJECT_MSG_NEW_PROCESS: { | |
| 310 caller_task_runner_->PostTask( | |
| 311 FROM_HERE, base::Bind(&Core::OnProcessLaunchDetected, this, | |
| 312 reinterpret_cast<base::ProcessId>(context))); | |
| 313 break; | |
| 314 } | |
| 296 } | 315 } |
| 297 } | 316 } |
| 298 | 317 |
| 299 bool WtsSessionProcessDelegate::Core::OnMessageReceived( | 318 bool WtsSessionProcessDelegate::Core::OnMessageReceived( |
| 300 const IPC::Message& message) { | 319 const IPC::Message& message) { |
| 301 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 320 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 302 | 321 |
| 303 return event_handler_->OnMessageReceived(message); | 322 return event_handler_->OnMessageReceived(message); |
| 304 } | 323 } |
| 305 | 324 |
| 306 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32_t peer_pid) { | 325 void WtsSessionProcessDelegate::Core::OnChannelConnected(int32_t peer_pid) { |
| 307 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 326 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 308 | 327 |
| 309 // Report the worker PID now if the worker process is launched indirectly. | |
| 310 // Note that in this case the pipe's security descriptor is the only | |
| 311 // protection against a malicious processed connecting to the pipe. | |
| 312 if (launch_elevated_) { | |
| 313 DWORD pid; | |
| 314 if (!get_named_pipe_client_pid_(pipe_.Get(), &pid)) { | |
| 315 PLOG(ERROR) << "Failed to retrive PID of the client"; | |
| 316 ReportFatalError(); | |
| 317 return; | |
| 318 } | |
| 319 | |
| 320 if (pid != static_cast<DWORD>(peer_pid)) { | |
| 321 LOG(ERROR) << "The actual client PID " << pid | |
| 322 << " does not match the one reported by the client: " | |
| 323 << peer_pid; | |
| 324 ReportFatalError(); | |
| 325 return; | |
| 326 } | |
| 327 | |
| 328 DWORD desired_access = | |
| 329 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | |
| 330 ScopedHandle worker_process(OpenProcess(desired_access, false, pid)); | |
| 331 if (!worker_process.IsValid()) { | |
| 332 PLOG(ERROR) << "Failed to open process " << pid; | |
| 333 ReportFatalError(); | |
| 334 return; | |
| 335 } | |
| 336 | |
| 337 ReportProcessLaunched(std::move(worker_process)); | |
| 338 } | |
| 339 | |
| 340 if (event_handler_) | 328 if (event_handler_) |
| 341 event_handler_->OnChannelConnected(peer_pid); | 329 event_handler_->OnChannelConnected(peer_pid); |
| 342 } | 330 } |
| 343 | 331 |
| 344 void WtsSessionProcessDelegate::Core::OnChannelError() { | 332 void WtsSessionProcessDelegate::Core::OnChannelError() { |
| 345 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 333 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 346 | 334 |
| 347 event_handler_->OnChannelError(); | 335 event_handler_->OnChannelError(); |
| 348 } | 336 } |
| 349 | 337 |
| 350 void WtsSessionProcessDelegate::Core::DoLaunchProcess() { | 338 void WtsSessionProcessDelegate::Core::DoLaunchProcess() { |
| 351 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 339 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 352 DCHECK(!channel_); | 340 DCHECK(!channel_); |
| 353 DCHECK(!pipe_.IsValid()); | |
| 354 DCHECK(!worker_process_.IsValid()); | 341 DCHECK(!worker_process_.IsValid()); |
| 355 | 342 |
| 356 base::CommandLine command_line(target_command_->argv()); | 343 base::CommandLine command_line(target_command_->argv()); |
| 357 if (launch_elevated_) { | 344 if (launch_elevated_) { |
| 358 // The job object is not ready. Retry starting the host process later. | 345 // The job object is not ready. Retry starting the host process later. |
| 359 if (!job_.IsValid()) { | 346 if (!job_.IsValid()) { |
| 360 launch_pending_ = true; | 347 launch_pending_ = true; |
| 361 return; | 348 return; |
| 362 } | 349 } |
| 363 | 350 |
| 364 // Construct the helper binary name. | 351 // Construct the helper binary name. |
| 365 base::FilePath helper_binary; | 352 base::FilePath helper_binary; |
| 366 if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) { | 353 if (!GetInstalledBinaryPath(kHostBinaryName, &helper_binary)) { |
| 367 ReportFatalError(); | 354 ReportFatalError(); |
| 368 return; | 355 return; |
| 369 } | 356 } |
| 370 | 357 |
| 371 // Create the command line passing the name of the IPC channel to use and | 358 // Create the command line passing the name of the IPC channel to use and |
| 372 // copying known switches from the caller's command line. | 359 // copying known switches from the caller's command line. |
| 373 command_line.SetProgram(helper_binary); | 360 command_line.SetProgram(helper_binary); |
| 374 command_line.AppendSwitchPath(kElevateSwitchName, | 361 command_line.AppendSwitchPath(kElevateSwitchName, |
| 375 target_command_->GetProgram()); | 362 target_command_->GetProgram()); |
| 376 } | 363 } |
| 377 | 364 |
| 378 // Create the server end of the IPC channel. | 365 const std::string mojo_message_pipe_token = mojo::edk::GenerateRandomToken(); |
| 379 std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID(); | 366 mojo_child_token_ = mojo::edk::GenerateRandomToken(); |
| 380 ScopedHandle pipe; | |
| 381 if (!CreateIpcChannel(channel_name, channel_security_, &pipe)) { | |
| 382 ReportFatalError(); | |
| 383 return; | |
| 384 } | |
| 385 | |
| 386 // Wrap the pipe into an IPC channel. | |
| 387 std::unique_ptr<IPC::ChannelProxy> channel( | 367 std::unique_ptr<IPC::ChannelProxy> channel( |
| 388 new IPC::ChannelProxy(this, io_task_runner_)); | 368 new IPC::ChannelProxy(this, io_task_runner_)); |
| 389 IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel( | 369 IPC::AttachmentBroker::GetGlobal()->RegisterCommunicationChannel( |
| 390 channel.get(), io_task_runner_); | 370 channel.get(), io_task_runner_); |
| 391 channel->Init(IPC::ChannelHandle(pipe.Get()), IPC::Channel::MODE_SERVER, | 371 channel->Init(mojo::edk::CreateParentMessagePipe(mojo_message_pipe_token, |
| 392 /*create_pipe_now=*/true); | 372 mojo_child_token_) |
| 373 .release(), | |
| 374 IPC::Channel::MODE_SERVER, /*create_pipe_now=*/true); | |
| 375 command_line.AppendSwitchASCII(kMojoPipeToken, mojo_message_pipe_token); | |
| 393 | 376 |
| 394 // Pass the name of the IPC channel to use. | 377 std::unique_ptr<mojo::edk::PlatformChannelPair> normal_mojo_channel; |
| 395 command_line.AppendSwitchNative(kDaemonPipeSwitchName, | 378 std::unique_ptr<mojo::edk::NamedPlatformChannelPair> elevated_mojo_channel; |
| 396 base::UTF8ToWide(channel_name)); | 379 base::HandlesToInheritVector handles_to_inherit; |
| 380 if (launch_elevated_) { | |
| 381 // Pass the name of the IPC channel to use. | |
| 382 mojo::edk::NamedPlatformChannelPair::Options options; | |
| 383 options.security_descriptor = base::UTF8ToUTF16(channel_security_); | |
| 384 elevated_mojo_channel = | |
| 385 base::MakeUnique<mojo::edk::NamedPlatformChannelPair>(options); | |
| 386 elevated_mojo_channel->PrepareToPassClientHandleToChildProcess( | |
| 387 &command_line); | |
| 388 } else { | |
| 389 normal_mojo_channel = base::MakeUnique<mojo::edk::PlatformChannelPair>(); | |
| 390 normal_mojo_channel->PrepareToPassClientHandleToChildProcess( | |
| 391 &command_line, &handles_to_inherit); | |
| 392 } | |
| 397 | 393 |
| 398 ScopedSd security_descriptor; | 394 ScopedSd security_descriptor; |
| 399 std::unique_ptr<SECURITY_ATTRIBUTES> security_attributes; | 395 std::unique_ptr<SECURITY_ATTRIBUTES> security_attributes; |
| 400 if (!new_process_security_.empty()) { | 396 if (!new_process_security_.empty()) { |
| 401 security_descriptor = ConvertSddlToSd(new_process_security_); | 397 security_descriptor = ConvertSddlToSd(new_process_security_); |
| 402 if (!security_descriptor) { | 398 if (!security_descriptor) { |
| 403 PLOG(ERROR) << "ConvertSddlToSd() failed."; | 399 PLOG(ERROR) << "ConvertSddlToSd() failed."; |
| 404 ReportFatalError(); | 400 ReportFatalError(); |
| 405 return; | 401 return; |
| 406 } | 402 } |
| 407 | 403 |
| 408 security_attributes.reset(new SECURITY_ATTRIBUTES()); | 404 security_attributes.reset(new SECURITY_ATTRIBUTES()); |
| 409 security_attributes->nLength = sizeof(SECURITY_ATTRIBUTES); | 405 security_attributes->nLength = sizeof(SECURITY_ATTRIBUTES); |
| 410 security_attributes->lpSecurityDescriptor = security_descriptor.get(); | 406 security_attributes->lpSecurityDescriptor = security_descriptor.get(); |
| 411 security_attributes->bInheritHandle = FALSE; | 407 security_attributes->bInheritHandle = FALSE; |
| 412 } | 408 } |
| 413 | 409 |
| 414 // Try to launch the process. | 410 // Try to launch the process. |
| 415 ScopedHandle worker_process; | 411 ScopedHandle worker_process; |
| 416 ScopedHandle worker_thread; | 412 ScopedHandle worker_thread; |
| 417 if (!LaunchProcessWithToken( | 413 if (!LaunchProcessWithToken( |
| 418 command_line.GetProgram(), command_line.GetCommandLineString(), | 414 command_line.GetProgram(), command_line.GetCommandLineString(), |
| 419 session_token_.Get(), security_attributes.get(), | 415 session_token_.Get(), security_attributes.get(), |
| 420 /* thread_attributes= */ nullptr, /* handles_to_inherit=*/{}, | 416 /* thread_attributes= */ nullptr, handles_to_inherit, |
| 421 /* creation_flags= */ CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, | 417 /* creation_flags= */ CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, |
| 422 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), &worker_process, | 418 base::UTF8ToUTF16(kDefaultDesktopName).c_str(), &worker_process, |
| 423 &worker_thread)) { | 419 &worker_thread)) { |
| 424 ReportFatalError(); | 420 ReportFatalError(); |
| 425 return; | 421 return; |
| 426 } | 422 } |
| 427 | 423 |
| 428 if (launch_elevated_) { | 424 if (launch_elevated_) { |
| 429 if (!AssignProcessToJobObject(job_.Get(), worker_process.Get())) { | 425 if (!AssignProcessToJobObject(job_.Get(), worker_process.Get())) { |
| 430 PLOG(ERROR) << "Failed to assign the worker to the job object"; | 426 PLOG(ERROR) << "Failed to assign the worker to the job object"; |
| 431 ReportFatalError(); | 427 ReportFatalError(); |
| 432 return; | 428 return; |
| 433 } | 429 } |
| 434 } | 430 } |
| 435 | 431 |
| 436 if (!ResumeThread(worker_thread.Get())) { | 432 if (!ResumeThread(worker_thread.Get())) { |
| 437 PLOG(ERROR) << "Failed to resume the worker thread"; | 433 PLOG(ERROR) << "Failed to resume the worker thread"; |
| 438 ReportFatalError(); | 434 ReportFatalError(); |
| 439 return; | 435 return; |
| 440 } | 436 } |
| 441 | 437 |
| 442 channel_ = std::move(channel); | 438 channel_ = std::move(channel); |
| 443 pipe_ = std::move(pipe); | |
| 444 | 439 |
| 445 // Report success if the worker process is lauched directly. Otherwise, PID of | 440 if (launch_elevated_) { |
| 446 // the client connected to the pipe will be used later. See | 441 // When launching an elevated worker process, an intermediate launcher |
| 447 // OnChannelConnected(). | 442 // process launches the worker process. Reporting the launch waits until the |
| 448 if (!launch_elevated_) | 443 // worker process launch is detected. Until then, store the values needed in |
| 449 ReportProcessLaunched(std::move(worker_process)); | 444 // fields. See OnProcessLaunchDetected for their use. |
| 445 elevated_server_handle_ = elevated_mojo_channel->PassServerHandle(); | |
| 446 elevated_launcher_pid_ = GetProcessId(worker_process.Get()); | |
| 447 DCHECK(elevated_server_handle_.is_valid()); | |
| 448 } else { | |
| 449 ReportProcessLaunched(std::move(worker_process), | |
| 450 normal_mojo_channel->PassServerHandle()); | |
| 451 } | |
| 450 } | 452 } |
| 451 | 453 |
| 452 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { | 454 void WtsSessionProcessDelegate::Core::DrainJobNotifications() { |
| 453 DCHECK(io_task_runner_->BelongsToCurrentThread()); | 455 DCHECK(io_task_runner_->BelongsToCurrentThread()); |
| 454 | 456 |
| 455 // DrainJobNotifications() is posted after the job object is destroyed, so | 457 // DrainJobNotifications() is posted after the job object is destroyed, so |
| 456 // by this time all notifications from the job object have been processed | 458 // by this time all notifications from the job object have been processed |
| 457 // already. Let the main thread know that the queue has been drained. | 459 // already. Let the main thread know that the queue has been drained. |
| 458 caller_task_runner_->PostTask(FROM_HERE, base::Bind( | 460 caller_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 459 &Core::DrainJobNotificationsCompleted, this)); | 461 &Core::DrainJobNotificationsCompleted, this)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 499 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { | 501 void WtsSessionProcessDelegate::Core::OnActiveProcessZero() { |
| 500 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 502 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 501 | 503 |
| 502 if (launch_pending_) { | 504 if (launch_pending_) { |
| 503 LOG(ERROR) << "The worker process exited before connecting via IPC."; | 505 LOG(ERROR) << "The worker process exited before connecting via IPC."; |
| 504 launch_pending_ = false; | 506 launch_pending_ = false; |
| 505 ReportFatalError(); | 507 ReportFatalError(); |
| 506 } | 508 } |
| 507 } | 509 } |
| 508 | 510 |
| 511 void WtsSessionProcessDelegate::Core::OnProcessLaunchDetected( | |
| 512 base::ProcessId pid) { | |
|
joedow
2016/10/26 21:48:20
Thanks for moving this out of the OnClientConnecte
Sam McNally
2016/10/27 00:43:46
Indeed, the connection will not be usable by anoth
| |
| 513 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | |
| 514 if (!elevated_server_handle_.is_valid()) | |
| 515 return; | |
| 516 | |
| 517 if (pid == elevated_launcher_pid_) | |
| 518 return; | |
| 519 | |
| 520 DWORD desired_access = | |
| 521 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | |
| 522 base::win::ScopedHandle worker_process( | |
| 523 OpenProcess(desired_access, false, pid)); | |
| 524 if (!worker_process.IsValid()) { | |
| 525 PLOG(ERROR) << "Failed to open process " << pid; | |
| 526 ReportFatalError(); | |
| 527 return; | |
| 528 } | |
| 529 elevated_launcher_pid_ = base::kNullProcessId; | |
| 530 ReportProcessLaunched(std::move(worker_process), | |
| 531 std::move(elevated_server_handle_)); | |
| 532 } | |
| 533 | |
| 509 void WtsSessionProcessDelegate::Core::ReportFatalError() { | 534 void WtsSessionProcessDelegate::Core::ReportFatalError() { |
| 510 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 535 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 511 | 536 |
| 512 CloseChannel(); | 537 CloseChannel(); |
| 513 | 538 |
| 514 WorkerProcessLauncher* event_handler = event_handler_; | 539 WorkerProcessLauncher* event_handler = event_handler_; |
| 515 event_handler_ = nullptr; | 540 event_handler_ = nullptr; |
| 516 event_handler->OnFatalError(); | 541 event_handler->OnFatalError(); |
| 517 } | 542 } |
| 518 | 543 |
| 519 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( | 544 void WtsSessionProcessDelegate::Core::ReportProcessLaunched( |
| 520 base::win::ScopedHandle worker_process) { | 545 base::win::ScopedHandle worker_process, |
| 546 mojo::edk::ScopedPlatformHandle server_handle) { | |
| 521 DCHECK(caller_task_runner_->BelongsToCurrentThread()); | 547 DCHECK(caller_task_runner_->BelongsToCurrentThread()); |
| 522 DCHECK(!worker_process_.IsValid()); | 548 DCHECK(!worker_process_.IsValid()); |
| 523 | 549 |
| 550 mojo::edk::ChildProcessLaunched(worker_process.Get(), | |
| 551 std::move(server_handle), | |
| 552 mojo_child_token_); | |
| 553 mojo_child_token_.clear(); | |
| 524 worker_process_ = std::move(worker_process); | 554 worker_process_ = std::move(worker_process); |
| 525 | 555 |
| 526 // Report a handle that can be used to wait for the worker process completion, | 556 // Report a handle that can be used to wait for the worker process completion, |
| 527 // query information about the process and duplicate handles. | 557 // query information about the process and duplicate handles. |
| 528 DWORD desired_access = | 558 DWORD desired_access = |
| 529 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; | 559 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION; |
| 530 HANDLE temp_handle; | 560 HANDLE temp_handle; |
| 531 if (!DuplicateHandle(GetCurrentProcess(), worker_process_.Get(), | 561 if (!DuplicateHandle(GetCurrentProcess(), worker_process_.Get(), |
| 532 GetCurrentProcess(), &temp_handle, desired_access, FALSE, | 562 GetCurrentProcess(), &temp_handle, desired_access, FALSE, |
| 533 0)) { | 563 0)) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 569 | 599 |
| 570 void WtsSessionProcessDelegate::CloseChannel() { | 600 void WtsSessionProcessDelegate::CloseChannel() { |
| 571 core_->CloseChannel(); | 601 core_->CloseChannel(); |
| 572 } | 602 } |
| 573 | 603 |
| 574 void WtsSessionProcessDelegate::KillProcess() { | 604 void WtsSessionProcessDelegate::KillProcess() { |
| 575 core_->KillProcess(); | 605 core_->KillProcess(); |
| 576 } | 606 } |
| 577 | 607 |
| 578 } // namespace remoting | 608 } // namespace remoting |
| OLD | NEW |