ipc_channel_win.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#include "ipc/ipc_channel_win.h" 6 7#include <windows.h> 8 9#include "base/auto_reset.h" 10#include "base/bind.h" 11#include "base/compiler_specific.h" 12#include "base/logging.h" 13#include "base/process_util.h" 14#include "base/rand_util.h" 15#include "base/string_number_conversions.h" 16#include "base/threading/thread_checker.h" 17#include "base/utf_string_conversions.h" 18#include "base/win/scoped_handle.h" 19#include "ipc/ipc_logging.h" 20#include "ipc/ipc_message_utils.h" 21 22namespace IPC { 23 24Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) { 25 memset(&context.overlapped, 0, sizeof(context.overlapped)); 26 context.handler = channel; 27} 28 29Channel::ChannelImpl::State::~State() { 30 COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context), 31 starts_with_io_context); 32} 33 34Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle, 35 Mode mode, Listener* listener) 36 : ChannelReader(listener), 37 ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)), 38 ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)), 39 pipe_(INVALID_HANDLE_VALUE), 40 peer_pid_(base::kNullProcessId), 41 waiting_connect_(mode & MODE_SERVER_FLAG), 42 processing_incoming_(false), 43 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 44 client_secret_(0), 45 validate_client_(false) { 46 CreatePipe(channel_handle, mode); 47} 48 49Channel::ChannelImpl::~ChannelImpl() { 50 Close(); 51} 52 53void Channel::ChannelImpl::Close() { 54 if (thread_check_.get()) { 55 DCHECK(thread_check_->CalledOnValidThread()); 56 } 57 58 if (input_state_.is_pending || output_state_.is_pending) 59 CancelIo(pipe_); 60 61 // Closing the handle at this point prevents us from issuing more requests 62 // form OnIOCompleted(). 63 if (pipe_ != INVALID_HANDLE_VALUE) { 64 CloseHandle(pipe_); 65 pipe_ = INVALID_HANDLE_VALUE; 66 } 67 68 // Make sure all IO has completed. 69 base::Time start = base::Time::Now(); 70 while (input_state_.is_pending || output_state_.is_pending) { 71 MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); 72 } 73 74 while (!output_queue_.empty()) { 75 Message* m = output_queue_.front(); 76 output_queue_.pop(); 77 delete m; 78 } 79} 80 81bool Channel::ChannelImpl::Send(Message* message) { 82 DCHECK(thread_check_->CalledOnValidThread()); 83 DVLOG(2) << "sending message @" << message << " on channel @" << this 84 << " with type " << message->type() 85 << " (" << output_queue_.size() << " in queue)"; 86 87#ifdef IPC_MESSAGE_LOG_ENABLED 88 Logging::GetInstance()->OnSendMessage(message, ""); 89#endif 90 91 message->TraceMessageBegin(); 92 output_queue_.push(message); 93 // ensure waiting to write 94 if (!waiting_connect_) { 95 if (!output_state_.is_pending) { 96 if (!ProcessOutgoingMessages(NULL, 0)) 97 return false; 98 } 99 } 100 101 return true; 102} 103 104// static 105bool Channel::ChannelImpl::IsNamedServerInitialized( 106 const std::string& channel_id) { 107 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1)) 108 return true; 109 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another 110 // connection. 111 return GetLastError() == ERROR_SEM_TIMEOUT; 112} 113 114Channel::ChannelImpl::ReadState Channel::ChannelImpl::ReadData( 115 char* buffer, 116 int buffer_len, 117 int* /* bytes_read */) { 118 if (INVALID_HANDLE_VALUE == pipe_) 119 return READ_FAILED; 120 121 DWORD bytes_read = 0; 122 BOOL ok = ReadFile(pipe_, buffer, buffer_len, 123 &bytes_read, &input_state_.context.overlapped); 124 if (!ok) { 125 DWORD err = GetLastError(); 126 if (err == ERROR_IO_PENDING) { 127 input_state_.is_pending = true; 128 return READ_PENDING; 129 } 130 LOG(ERROR) << "pipe error: " << err; 131 return READ_FAILED; 132 } 133 134 // We could return READ_SUCCEEDED here. But the way that this code is 135 // structured we instead go back to the message loop. Our completion port 136 // will be signalled even in the "synchronously completed" state. 137 // 138 // This allows us to potentially process some outgoing messages and 139 // interleave other work on this thread when we're getting hammered with 140 // input messages. Potentially, this could be tuned to be more efficient 141 // with some testing. 142 input_state_.is_pending = true; 143 return READ_PENDING; 144} 145 146bool Channel::ChannelImpl::WillDispatchInputMessage(Message* msg) { 147 // Make sure we get a hello when client validation is required. 148 if (validate_client_) 149 return IsHelloMessage(*msg); 150 return true; 151} 152 153void Channel::ChannelImpl::HandleHelloMessage(const Message& msg) { 154 // The hello message contains one parameter containing the PID. 155 MessageIterator it = MessageIterator(msg); 156 int32 claimed_pid = it.NextInt(); 157 if (validate_client_ && (it.NextInt() != client_secret_)) { 158 NOTREACHED(); 159 // Something went wrong. Abort connection. 160 Close(); 161 listener()->OnChannelError(); 162 return; 163 } 164 peer_pid_ = claimed_pid; 165 // validation completed. 166 validate_client_ = false; 167 listener()->OnChannelConnected(claimed_pid); 168} 169 170bool Channel::ChannelImpl::DidEmptyInputBuffers() { 171 // We don't need to do anything here. 172 return true; 173} 174 175// static 176const string16 Channel::ChannelImpl::PipeName( 177 const std::string& channel_id, int32* secret) { 178 std::string name("\\\\.\\pipe\\chrome."); 179 180 // Prevent the shared secret from ending up in the pipe name. 181 size_t index = channel_id.find_first_of('\\'); 182 if (index != std::string::npos) { 183 if (secret) // Retrieve the secret if asked for. 184 base::StringToInt(channel_id.substr(index + 1), secret); 185 return ASCIIToWide(name.append(channel_id.substr(0, index - 1))); 186 } 187 188 // This case is here to support predictable named pipes in tests. 189 if (secret) 190 *secret = 0; 191 return ASCIIToWide(name.append(channel_id)); 192} 193 194bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle, 195 Mode mode) { 196 DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_); 197 string16 pipe_name; 198 // If we already have a valid pipe for channel just copy it. 199 if (channel_handle.pipe.handle) { 200 DCHECK(channel_handle.name.empty()); 201 pipe_name = L"Not Available"; // Just used for LOG 202 // Check that the given pipe confirms to the specified mode. We can 203 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the 204 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0. 205 DWORD flags = 0; 206 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL); 207 DCHECK(!(flags & PIPE_TYPE_MESSAGE)); 208 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) || 209 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) { 210 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode; 211 return false; 212 } 213 if (!DuplicateHandle(GetCurrentProcess(), 214 channel_handle.pipe.handle, 215 GetCurrentProcess(), 216 &pipe_, 217 0, 218 FALSE, 219 DUPLICATE_SAME_ACCESS)) { 220 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError(); 221 return false; 222 } 223 } else if (mode & MODE_SERVER_FLAG) { 224 DCHECK(!channel_handle.pipe.handle); 225 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | 226 FILE_FLAG_FIRST_PIPE_INSTANCE; 227 pipe_name = PipeName(channel_handle.name, &client_secret_); 228 validate_client_ = !!client_secret_; 229 pipe_ = CreateNamedPipeW(pipe_name.c_str(), 230 open_mode, 231 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 232 1, 233 Channel::kReadBufferSize, 234 Channel::kReadBufferSize, 235 5000, 236 NULL); 237 } else if (mode & MODE_CLIENT_FLAG) { 238 DCHECK(!channel_handle.pipe.handle); 239 pipe_name = PipeName(channel_handle.name, &client_secret_); 240 pipe_ = CreateFileW(pipe_name.c_str(), 241 GENERIC_READ | GENERIC_WRITE, 242 0, 243 NULL, 244 OPEN_EXISTING, 245 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION | 246 FILE_FLAG_OVERLAPPED, 247 NULL); 248 } else { 249 NOTREACHED(); 250 } 251 252 if (pipe_ == INVALID_HANDLE_VALUE) { 253 // If this process is being closed, the pipe may be gone already. 254 LOG(WARNING) << "Unable to create pipe \"" << pipe_name << 255 "\" in " << (mode & MODE_SERVER_FLAG ? "server" : "client") 256 << " mode. Error :" << GetLastError(); 257 return false; 258 } 259 260 // Create the Hello message to be sent when Connect is called 261 scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE, 262 HELLO_MESSAGE_TYPE, 263 IPC::Message::PRIORITY_NORMAL)); 264 265 // Don't send the secret to the untrusted process, and don't send a secret 266 // if the value is zero (for IPC backwards compatability). 267 int32 secret = validate_client_ ? 0 : client_secret_; 268 if (!m->WriteInt(GetCurrentProcessId()) || 269 (secret && !m->WriteUInt32(secret))) { 270 CloseHandle(pipe_); 271 pipe_ = INVALID_HANDLE_VALUE; 272 return false; 273 } 274 275 output_queue_.push(m.release()); 276 return true; 277} 278 279bool Channel::ChannelImpl::Connect() { 280 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once"; 281 282 if (!thread_check_.get()) 283 thread_check_.reset(new base::ThreadChecker()); 284 285 if (pipe_ == INVALID_HANDLE_VALUE) 286 return false; 287 288 MessageLoopForIO::current()->RegisterIOHandler(pipe_, this); 289 290 // Check to see if there is a client connected to our pipe... 291 if (waiting_connect_) 292 ProcessConnection(); 293 294 if (!input_state_.is_pending) { 295 // Complete setup asynchronously. By not setting input_state_.is_pending 296 // to true, we indicate to OnIOCompleted that this is the special 297 // initialization signal. 298 MessageLoopForIO::current()->PostTask( 299 FROM_HERE, base::Bind(&Channel::ChannelImpl::OnIOCompleted, 300 weak_factory_.GetWeakPtr(), &input_state_.context, 301 0, 0)); 302 } 303 304 if (!waiting_connect_) 305 ProcessOutgoingMessages(NULL, 0); 306 return true; 307} 308 309bool Channel::ChannelImpl::ProcessConnection() { 310 DCHECK(thread_check_->CalledOnValidThread()); 311 if (input_state_.is_pending) 312 input_state_.is_pending = false; 313 314 // Do we have a client connected to our pipe? 315 if (INVALID_HANDLE_VALUE == pipe_) 316 return false; 317 318 BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped); 319 320 DWORD err = GetLastError(); 321 if (ok) { 322 // Uhm, the API documentation says that this function should never 323 // return success when used in overlapped mode. 324 NOTREACHED(); 325 return false; 326 } 327 328 switch (err) { 329 case ERROR_IO_PENDING: 330 input_state_.is_pending = true; 331 break; 332 case ERROR_PIPE_CONNECTED: 333 waiting_connect_ = false; 334 break; 335 case ERROR_NO_DATA: 336 // The pipe is being closed. 337 return false; 338 default: 339 NOTREACHED(); 340 return false; 341 } 342 343 return true; 344} 345 346bool Channel::ChannelImpl::ProcessOutgoingMessages( 347 MessageLoopForIO::IOContext* context, 348 DWORD bytes_written) { 349 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's 350 // no connection? 351 DCHECK(thread_check_->CalledOnValidThread()); 352 353 if (output_state_.is_pending) { 354 DCHECK(context); 355 output_state_.is_pending = false; 356 if (!context || bytes_written == 0) { 357 DWORD err = GetLastError(); 358 LOG(ERROR) << "pipe error: " << err; 359 return false; 360 } 361 // Message was sent. 362 DCHECK(!output_queue_.empty()); 363 Message* m = output_queue_.front(); 364 output_queue_.pop(); 365 delete m; 366 } 367 368 if (output_queue_.empty()) 369 return true; 370 371 if (INVALID_HANDLE_VALUE == pipe_) 372 return false; 373 374 // Write to pipe... 375 Message* m = output_queue_.front(); 376 DCHECK(m->size() <= INT_MAX); 377 BOOL ok = WriteFile(pipe_, 378 m->data(), 379 static_cast<int>(m->size()), 380 &bytes_written, 381 &output_state_.context.overlapped); 382 if (!ok) { 383 DWORD err = GetLastError(); 384 if (err == ERROR_IO_PENDING) { 385 output_state_.is_pending = true; 386 387 DVLOG(2) << "sent pending message @" << m << " on channel @" << this 388 << " with type " << m->type(); 389 390 return true; 391 } 392 LOG(ERROR) << "pipe error: " << err; 393 return false; 394 } 395 396 DVLOG(2) << "sent message @" << m << " on channel @" << this 397 << " with type " << m->type(); 398 399 output_state_.is_pending = true; 400 return true; 401} 402 403void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context, 404 DWORD bytes_transfered, 405 DWORD error) { 406 bool ok = true; 407 DCHECK(thread_check_->CalledOnValidThread()); 408 if (context == &input_state_.context) { 409 if (waiting_connect_) { 410 if (!ProcessConnection()) 411 return; 412 // We may have some messages queued up to send... 413 if (!output_queue_.empty() && !output_state_.is_pending) 414 ProcessOutgoingMessages(NULL, 0); 415 if (input_state_.is_pending) 416 return; 417 // else, fall-through and look for incoming messages... 418 } 419 420 // We don't support recursion through OnMessageReceived yet! 421 DCHECK(!processing_incoming_); 422 AutoReset<bool> auto_reset_processing_incoming(&processing_incoming_, true); 423 424 // Process the new data. 425 if (input_state_.is_pending) { 426 // This is the normal case for everything except the initialization step. 427 input_state_.is_pending = false; 428 if (!bytes_transfered) 429 ok = false; 430 else 431 ok = AsyncReadComplete(bytes_transfered); 432 } else { 433 DCHECK(!bytes_transfered); 434 } 435 436 // Request more data. 437 if (ok) 438 ok = ProcessIncomingMessages(); 439 } else { 440 DCHECK(context == &output_state_.context); 441 ok = ProcessOutgoingMessages(context, bytes_transfered); 442 } 443 if (!ok && INVALID_HANDLE_VALUE != pipe_) { 444 // We don't want to re-enter Close(). 445 Close(); 446 listener()->OnChannelError(); 447 } 448} 449 450//------------------------------------------------------------------------------ 451// Channel's methods simply call through to ChannelImpl. 452Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode, 453 Listener* listener) 454 : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) { 455} 456 457Channel::~Channel() { 458 delete channel_impl_; 459} 460 461bool Channel::Connect() { 462 return channel_impl_->Connect(); 463} 464 465void Channel::Close() { 466 if (channel_impl_) 467 channel_impl_->Close(); 468} 469 470void Channel::set_listener(Listener* listener) { 471 channel_impl_->set_listener(listener); 472} 473 474base::ProcessId Channel::peer_pid() const { 475 return channel_impl_->peer_pid(); 476} 477 478bool Channel::Send(Message* message) { 479 return channel_impl_->Send(message); 480} 481 482// static 483bool Channel::IsNamedServerInitialized(const std::string& channel_id) { 484 return ChannelImpl::IsNamedServerInitialized(channel_id); 485} 486 487// static 488std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { 489 // Windows pipes can be enumerated by low-privileged processes. So, we 490 // append a strong random value after the \ character. This value is not 491 // included in the pipe name, but sent as part of the client hello, to 492 // hijacking the pipe name to spoof the client. 493 494 std::string id = prefix; 495 if (!id.empty()) 496 id.append("."); 497 498 int secret; 499 do { // Guarantee we get a non-zero value. 500 secret = base::RandInt(0, std::numeric_limits<int>::max()); 501 } while (secret == 0); 502 503 id.append(GenerateUniqueRandomChannelID()); 504 return id.append(base::StringPrintf("\\%d", secret)); 505} 506 507} // namespace IPC 508