 Chromium Code Reviews
 Chromium Code Reviews Issue 2446053002:
  Use ChannelMojo between the remoting daemon and desktop processes.  (Closed)
    
  
    Issue 2446053002:
  Use ChannelMojo between the remoting daemon and desktop processes.  (Closed) 
  | 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 |