| OLD | NEW |
| (Empty) |
| 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 #include <stddef.h> | |
| 9 #include <stdint.h> | |
| 10 | |
| 11 #include "base/auto_reset.h" | |
| 12 #include "base/bind.h" | |
| 13 #include "base/compiler_specific.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/memory/ptr_util.h" | |
| 16 #include "base/pickle.h" | |
| 17 #include "base/process/process_handle.h" | |
| 18 #include "base/rand_util.h" | |
| 19 #include "base/single_thread_task_runner.h" | |
| 20 #include "base/strings/string_number_conversions.h" | |
| 21 #include "base/strings/utf_string_conversions.h" | |
| 22 #include "base/threading/thread_checker.h" | |
| 23 #include "base/threading/thread_task_runner_handle.h" | |
| 24 #include "base/win/scoped_handle.h" | |
| 25 #include "ipc/attachment_broker.h" | |
| 26 #include "ipc/ipc_listener.h" | |
| 27 #include "ipc/ipc_logging.h" | |
| 28 #include "ipc/ipc_message_attachment_set.h" | |
| 29 #include "ipc/ipc_message_utils.h" | |
| 30 | |
| 31 namespace IPC { | |
| 32 | |
| 33 ChannelWin::State::State() = default; | |
| 34 | |
| 35 ChannelWin::State::~State() { | |
| 36 static_assert(offsetof(ChannelWin::State, context) == 0, | |
| 37 "ChannelWin::State should have context as its first data" | |
| 38 "member."); | |
| 39 } | |
| 40 | |
| 41 ChannelWin::ChannelWin(const IPC::ChannelHandle& channel_handle, | |
| 42 Mode mode, | |
| 43 Listener* listener) | |
| 44 : ChannelReader(listener), | |
| 45 peer_pid_(base::kNullProcessId), | |
| 46 waiting_connect_(mode & MODE_SERVER_FLAG), | |
| 47 processing_incoming_(false), | |
| 48 validate_client_(false), | |
| 49 client_secret_(0), | |
| 50 weak_factory_(this) { | |
| 51 CreatePipe(channel_handle, mode); | |
| 52 } | |
| 53 | |
| 54 ChannelWin::~ChannelWin() { | |
| 55 CleanUp(); | |
| 56 Close(); | |
| 57 } | |
| 58 | |
| 59 void ChannelWin::Close() { | |
| 60 if (thread_check_.get()) | |
| 61 DCHECK(thread_check_->CalledOnValidThread()); | |
| 62 | |
| 63 if (input_state_.is_pending || output_state_.is_pending) | |
| 64 CancelIo(pipe_.Get()); | |
| 65 | |
| 66 // Closing the handle at this point prevents us from issuing more requests | |
| 67 // form OnIOCompleted(). | |
| 68 if (pipe_.IsValid()) | |
| 69 pipe_.Close(); | |
| 70 | |
| 71 // Make sure all IO has completed. | |
| 72 while (input_state_.is_pending || output_state_.is_pending) { | |
| 73 base::MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this); | |
| 74 } | |
| 75 | |
| 76 while (!output_queue_.empty()) { | |
| 77 OutputElement* element = output_queue_.front(); | |
| 78 output_queue_.pop(); | |
| 79 delete element; | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 bool ChannelWin::Send(Message* message) { | |
| 84 DCHECK(thread_check_->CalledOnValidThread()); | |
| 85 DVLOG(2) << "sending message @" << message << " on channel @" << this | |
| 86 << " with type " << message->type() | |
| 87 << " (" << output_queue_.size() << " in queue)"; | |
| 88 | |
| 89 if (!prelim_queue_.empty()) { | |
| 90 prelim_queue_.push(message); | |
| 91 return true; | |
| 92 } | |
| 93 | |
| 94 if (message->HasBrokerableAttachments() && | |
| 95 peer_pid_ == base::kNullProcessId) { | |
| 96 prelim_queue_.push(message); | |
| 97 return true; | |
| 98 } | |
| 99 | |
| 100 return ProcessMessageForDelivery(message); | |
| 101 } | |
| 102 | |
| 103 bool ChannelWin::ProcessMessageForDelivery(Message* message) { | |
| 104 // Sending a brokerable attachment requires a call to Channel::Send(), so | |
| 105 // both Send() and ProcessMessageForDelivery() may be re-entrant. | |
| 106 if (message->HasBrokerableAttachments()) { | |
| 107 DCHECK(GetAttachmentBroker()); | |
| 108 DCHECK(peer_pid_ != base::kNullProcessId); | |
| 109 for (const scoped_refptr<IPC::BrokerableAttachment>& attachment : | |
| 110 message->attachment_set()->GetBrokerableAttachments()) { | |
| 111 if (!GetAttachmentBroker()->SendAttachmentToProcess(attachment, | |
| 112 peer_pid_)) { | |
| 113 delete message; | |
| 114 return false; | |
| 115 } | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 #ifdef IPC_MESSAGE_LOG_ENABLED | |
| 120 Logging::GetInstance()->OnSendMessage(message, ""); | |
| 121 #endif | |
| 122 | |
| 123 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("ipc.flow"), | |
| 124 "ChannelWin::ProcessMessageForDelivery", | |
| 125 message->flags(), | |
| 126 TRACE_EVENT_FLAG_FLOW_OUT); | |
| 127 | |
| 128 // |output_queue_| takes ownership of |message|. | |
| 129 OutputElement* element = new OutputElement(message); | |
| 130 output_queue_.push(element); | |
| 131 | |
| 132 #if USE_ATTACHMENT_BROKER | |
| 133 if (message->HasBrokerableAttachments()) { | |
| 134 // |output_queue_| takes ownership of |ids.buffer|. | |
| 135 Message::SerializedAttachmentIds ids = | |
| 136 message->SerializedIdsOfBrokerableAttachments(); | |
| 137 output_queue_.push(new OutputElement(ids.buffer, ids.size)); | |
| 138 } | |
| 139 #endif | |
| 140 | |
| 141 // ensure waiting to write | |
| 142 if (!waiting_connect_) { | |
| 143 if (!output_state_.is_pending) { | |
| 144 if (!ProcessOutgoingMessages(NULL, 0)) | |
| 145 return false; | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 return true; | |
| 150 } | |
| 151 | |
| 152 void ChannelWin::FlushPrelimQueue() { | |
| 153 DCHECK_NE(peer_pid_, base::kNullProcessId); | |
| 154 | |
| 155 // Due to the possibly re-entrant nature of ProcessMessageForDelivery(), it | |
| 156 // is critical that |prelim_queue_| appears empty. | |
| 157 std::queue<Message*> prelim_queue; | |
| 158 prelim_queue_.swap(prelim_queue); | |
| 159 | |
| 160 while (!prelim_queue.empty()) { | |
| 161 Message* m = prelim_queue.front(); | |
| 162 bool success = ProcessMessageForDelivery(m); | |
| 163 prelim_queue.pop(); | |
| 164 | |
| 165 if (!success) | |
| 166 break; | |
| 167 } | |
| 168 | |
| 169 // Delete any unprocessed messages. | |
| 170 while (!prelim_queue.empty()) { | |
| 171 Message* m = prelim_queue.front(); | |
| 172 delete m; | |
| 173 prelim_queue.pop(); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 AttachmentBroker* ChannelWin::GetAttachmentBroker() { | |
| 178 return AttachmentBroker::GetGlobal(); | |
| 179 } | |
| 180 | |
| 181 base::ProcessId ChannelWin::GetPeerPID() const { | |
| 182 return peer_pid_; | |
| 183 } | |
| 184 | |
| 185 base::ProcessId ChannelWin::GetSelfPID() const { | |
| 186 return GetCurrentProcessId(); | |
| 187 } | |
| 188 | |
| 189 // static | |
| 190 bool ChannelWin::IsNamedServerInitialized( | |
| 191 const std::string& channel_id) { | |
| 192 if (WaitNamedPipe(PipeName(channel_id, NULL).c_str(), 1)) | |
| 193 return true; | |
| 194 // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another | |
| 195 // connection. | |
| 196 return GetLastError() == ERROR_SEM_TIMEOUT; | |
| 197 } | |
| 198 | |
| 199 ChannelWin::ReadState ChannelWin::ReadData( | |
| 200 char* buffer, | |
| 201 int buffer_len, | |
| 202 int* /* bytes_read */) { | |
| 203 if (!pipe_.IsValid()) | |
| 204 return READ_FAILED; | |
| 205 | |
| 206 DWORD bytes_read = 0; | |
| 207 BOOL ok = ReadFile(pipe_.Get(), buffer, buffer_len, | |
| 208 &bytes_read, &input_state_.context.overlapped); | |
| 209 if (!ok) { | |
| 210 DWORD err = GetLastError(); | |
| 211 if (err == ERROR_IO_PENDING) { | |
| 212 input_state_.is_pending = true; | |
| 213 return READ_PENDING; | |
| 214 } | |
| 215 LOG(ERROR) << "pipe error: " << err; | |
| 216 return READ_FAILED; | |
| 217 } | |
| 218 | |
| 219 // We could return READ_SUCCEEDED here. But the way that this code is | |
| 220 // structured we instead go back to the message loop. Our completion port | |
| 221 // will be signalled even in the "synchronously completed" state. | |
| 222 // | |
| 223 // This allows us to potentially process some outgoing messages and | |
| 224 // interleave other work on this thread when we're getting hammered with | |
| 225 // input messages. Potentially, this could be tuned to be more efficient | |
| 226 // with some testing. | |
| 227 input_state_.is_pending = true; | |
| 228 return READ_PENDING; | |
| 229 } | |
| 230 | |
| 231 bool ChannelWin::ShouldDispatchInputMessage(Message* msg) { | |
| 232 // Make sure we get a hello when client validation is required. | |
| 233 if (validate_client_) | |
| 234 return IsHelloMessage(*msg); | |
| 235 return true; | |
| 236 } | |
| 237 | |
| 238 bool ChannelWin::GetNonBrokeredAttachments(Message* msg) { | |
| 239 return true; | |
| 240 } | |
| 241 | |
| 242 void ChannelWin::HandleInternalMessage(const Message& msg) { | |
| 243 DCHECK_EQ(msg.type(), static_cast<unsigned>(Channel::HELLO_MESSAGE_TYPE)); | |
| 244 // The hello message contains one parameter containing the PID. | |
| 245 base::PickleIterator it(msg); | |
| 246 int32_t claimed_pid; | |
| 247 bool failed = !it.ReadInt(&claimed_pid); | |
| 248 | |
| 249 if (!failed && validate_client_) { | |
| 250 int32_t secret; | |
| 251 failed = it.ReadInt(&secret) ? (secret != client_secret_) : true; | |
| 252 } | |
| 253 | |
| 254 if (failed) { | |
| 255 NOTREACHED(); | |
| 256 Close(); | |
| 257 listener()->OnChannelError(); | |
| 258 return; | |
| 259 } | |
| 260 | |
| 261 peer_pid_ = claimed_pid; | |
| 262 // Validation completed. | |
| 263 validate_client_ = false; | |
| 264 | |
| 265 listener()->OnChannelConnected(claimed_pid); | |
| 266 | |
| 267 FlushPrelimQueue(); | |
| 268 | |
| 269 if (IsAttachmentBrokerEndpoint() && | |
| 270 AttachmentBroker::GetGlobal()->IsPrivilegedBroker()) { | |
| 271 AttachmentBroker::GetGlobal()->ReceivedPeerPid(claimed_pid); | |
| 272 } | |
| 273 } | |
| 274 | |
| 275 base::ProcessId ChannelWin::GetSenderPID() { | |
| 276 return GetPeerPID(); | |
| 277 } | |
| 278 | |
| 279 bool ChannelWin::IsAttachmentBrokerEndpoint() { | |
| 280 return is_attachment_broker_endpoint(); | |
| 281 } | |
| 282 | |
| 283 bool ChannelWin::DidEmptyInputBuffers() { | |
| 284 // We don't need to do anything here. | |
| 285 return true; | |
| 286 } | |
| 287 | |
| 288 // static | |
| 289 const base::string16 ChannelWin::PipeName(const std::string& channel_id, | |
| 290 int32_t* secret) { | |
| 291 std::string name("\\\\.\\pipe\\chrome."); | |
| 292 | |
| 293 // Prevent the shared secret from ending up in the pipe name. | |
| 294 size_t index = channel_id.find_first_of('\\'); | |
| 295 if (index != std::string::npos) { | |
| 296 if (secret) // Retrieve the secret if asked for. | |
| 297 base::StringToInt(channel_id.substr(index + 1), secret); | |
| 298 return base::ASCIIToUTF16(name.append(channel_id.substr(0, index - 1))); | |
| 299 } | |
| 300 | |
| 301 // This case is here to support predictable named pipes in tests. | |
| 302 if (secret) | |
| 303 *secret = 0; | |
| 304 return base::ASCIIToUTF16(name.append(channel_id)); | |
| 305 } | |
| 306 | |
| 307 bool ChannelWin::CreatePipe(const IPC::ChannelHandle &channel_handle, | |
| 308 Mode mode) { | |
| 309 DCHECK(!pipe_.IsValid()); | |
| 310 base::string16 pipe_name; | |
| 311 // If we already have a valid pipe for channel just copy it. | |
| 312 if (channel_handle.pipe.handle) { | |
| 313 // TODO(rvargas) crbug.com/415294: ChannelHandle should either go away in | |
| 314 // favor of two independent entities (name/file), or it should be a move- | |
| 315 // only type with a base::File member. In any case, this code should not | |
| 316 // call DuplicateHandle. | |
| 317 DCHECK(channel_handle.name.empty()); | |
| 318 pipe_name = L"Not Available"; // Just used for LOG | |
| 319 // Check that the given pipe confirms to the specified mode. We can | |
| 320 // only check for PIPE_TYPE_MESSAGE & PIPE_SERVER_END flags since the | |
| 321 // other flags (PIPE_TYPE_BYTE, and PIPE_CLIENT_END) are defined as 0. | |
| 322 DWORD flags = 0; | |
| 323 GetNamedPipeInfo(channel_handle.pipe.handle, &flags, NULL, NULL, NULL); | |
| 324 DCHECK(!(flags & PIPE_TYPE_MESSAGE)); | |
| 325 if (((mode & MODE_SERVER_FLAG) && !(flags & PIPE_SERVER_END)) || | |
| 326 ((mode & MODE_CLIENT_FLAG) && (flags & PIPE_SERVER_END))) { | |
| 327 LOG(WARNING) << "Inconsistent open mode. Mode :" << mode; | |
| 328 return false; | |
| 329 } | |
| 330 HANDLE local_handle; | |
| 331 if (!DuplicateHandle(GetCurrentProcess(), | |
| 332 channel_handle.pipe.handle, | |
| 333 GetCurrentProcess(), | |
| 334 &local_handle, | |
| 335 0, | |
| 336 FALSE, | |
| 337 DUPLICATE_SAME_ACCESS)) { | |
| 338 LOG(WARNING) << "DuplicateHandle failed. Error :" << GetLastError(); | |
| 339 return false; | |
| 340 } | |
| 341 pipe_.Set(local_handle); | |
| 342 } else if (mode & MODE_SERVER_FLAG) { | |
| 343 DCHECK(!channel_handle.pipe.handle); | |
| 344 const DWORD open_mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | | |
| 345 FILE_FLAG_FIRST_PIPE_INSTANCE; | |
| 346 pipe_name = PipeName(channel_handle.name, &client_secret_); | |
| 347 validate_client_ = !!client_secret_; | |
| 348 pipe_.Set(CreateNamedPipeW(pipe_name.c_str(), | |
| 349 open_mode, | |
| 350 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, | |
| 351 1, | |
| 352 Channel::kReadBufferSize, | |
| 353 Channel::kReadBufferSize, | |
| 354 5000, | |
| 355 NULL)); | |
| 356 } else if (mode & MODE_CLIENT_FLAG) { | |
| 357 DCHECK(!channel_handle.pipe.handle); | |
| 358 pipe_name = PipeName(channel_handle.name, &client_secret_); | |
| 359 pipe_.Set(CreateFileW(pipe_name.c_str(), | |
| 360 GENERIC_READ | GENERIC_WRITE, | |
| 361 0, | |
| 362 NULL, | |
| 363 OPEN_EXISTING, | |
| 364 SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | | |
| 365 FILE_FLAG_OVERLAPPED, | |
| 366 NULL)); | |
| 367 } else { | |
| 368 NOTREACHED(); | |
| 369 } | |
| 370 | |
| 371 if (!pipe_.IsValid()) { | |
| 372 // If this process is being closed, the pipe may be gone already. | |
| 373 PLOG(WARNING) << "Unable to create pipe \"" << pipe_name << "\" in " | |
| 374 << (mode & MODE_SERVER_FLAG ? "server" : "client") << " mode"; | |
| 375 return false; | |
| 376 } | |
| 377 | |
| 378 // Create the Hello message to be sent when Connect is called | |
| 379 std::unique_ptr<Message> m(new Message(MSG_ROUTING_NONE, HELLO_MESSAGE_TYPE, | |
| 380 IPC::Message::PRIORITY_NORMAL)); | |
| 381 | |
| 382 // Don't send the secret to the untrusted process, and don't send a secret | |
| 383 // if the value is zero (for IPC backwards compatability). | |
| 384 int32_t secret = validate_client_ ? 0 : client_secret_; | |
| 385 if (!m->WriteInt(GetCurrentProcessId()) || | |
| 386 (secret && !m->WriteUInt32(secret))) { | |
| 387 pipe_.Close(); | |
| 388 return false; | |
| 389 } | |
| 390 | |
| 391 OutputElement* element = new OutputElement(m.release()); | |
| 392 output_queue_.push(element); | |
| 393 return true; | |
| 394 } | |
| 395 | |
| 396 bool ChannelWin::Connect() { | |
| 397 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
| 398 | |
| 399 WillConnect(); | |
| 400 | |
| 401 DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once"; | |
| 402 | |
| 403 if (!thread_check_.get()) | |
| 404 thread_check_.reset(new base::ThreadChecker()); | |
| 405 | |
| 406 if (!pipe_.IsValid()) | |
| 407 return false; | |
| 408 | |
| 409 base::MessageLoopForIO::current()->RegisterIOHandler(pipe_.Get(), this); | |
| 410 | |
| 411 // Check to see if there is a client connected to our pipe... | |
| 412 if (waiting_connect_) | |
| 413 ProcessConnection(); | |
| 414 | |
| 415 if (!input_state_.is_pending) { | |
| 416 // Complete setup asynchronously. By not setting input_state_.is_pending | |
| 417 // to true, we indicate to OnIOCompleted that this is the special | |
| 418 // initialization signal. | |
| 419 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
| 420 FROM_HERE, | |
| 421 base::Bind(&ChannelWin::OnIOCompleted, weak_factory_.GetWeakPtr(), | |
| 422 &input_state_.context, 0, 0)); | |
| 423 } | |
| 424 | |
| 425 if (!waiting_connect_) | |
| 426 ProcessOutgoingMessages(NULL, 0); | |
| 427 return true; | |
| 428 } | |
| 429 | |
| 430 bool ChannelWin::ProcessConnection() { | |
| 431 DCHECK(thread_check_->CalledOnValidThread()); | |
| 432 if (input_state_.is_pending) | |
| 433 input_state_.is_pending = false; | |
| 434 | |
| 435 // Do we have a client connected to our pipe? | |
| 436 if (!pipe_.IsValid()) | |
| 437 return false; | |
| 438 | |
| 439 BOOL ok = ConnectNamedPipe(pipe_.Get(), &input_state_.context.overlapped); | |
| 440 DWORD err = GetLastError(); | |
| 441 if (ok) { | |
| 442 // Uhm, the API documentation says that this function should never | |
| 443 // return success when used in overlapped mode. | |
| 444 NOTREACHED(); | |
| 445 return false; | |
| 446 } | |
| 447 | |
| 448 switch (err) { | |
| 449 case ERROR_IO_PENDING: | |
| 450 input_state_.is_pending = true; | |
| 451 break; | |
| 452 case ERROR_PIPE_CONNECTED: | |
| 453 waiting_connect_ = false; | |
| 454 break; | |
| 455 case ERROR_NO_DATA: | |
| 456 // The pipe is being closed. | |
| 457 return false; | |
| 458 default: | |
| 459 NOTREACHED(); | |
| 460 return false; | |
| 461 } | |
| 462 | |
| 463 return true; | |
| 464 } | |
| 465 | |
| 466 bool ChannelWin::ProcessOutgoingMessages( | |
| 467 base::MessageLoopForIO::IOContext* context, | |
| 468 DWORD bytes_written) { | |
| 469 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's | |
| 470 // no connection? | |
| 471 DCHECK(thread_check_->CalledOnValidThread()); | |
| 472 | |
| 473 if (output_state_.is_pending) { | |
| 474 DCHECK(context); | |
| 475 output_state_.is_pending = false; | |
| 476 if (!context || bytes_written == 0) { | |
| 477 DWORD err = GetLastError(); | |
| 478 LOG(ERROR) << "pipe error: " << err; | |
| 479 return false; | |
| 480 } | |
| 481 // Message was sent. | |
| 482 CHECK(!output_queue_.empty()); | |
| 483 OutputElement* element = output_queue_.front(); | |
| 484 output_queue_.pop(); | |
| 485 delete element; | |
| 486 } | |
| 487 | |
| 488 if (output_queue_.empty()) | |
| 489 return true; | |
| 490 | |
| 491 if (!pipe_.IsValid()) | |
| 492 return false; | |
| 493 | |
| 494 // Write to pipe... | |
| 495 OutputElement* element = output_queue_.front(); | |
| 496 DCHECK(element->size() <= INT_MAX); | |
| 497 BOOL ok = WriteFile(pipe_.Get(), | |
| 498 element->data(), | |
| 499 static_cast<uint32_t>(element->size()), | |
| 500 NULL, | |
| 501 &output_state_.context.overlapped); | |
| 502 if (!ok) { | |
| 503 DWORD write_error = GetLastError(); | |
| 504 if (write_error == ERROR_IO_PENDING) { | |
| 505 output_state_.is_pending = true; | |
| 506 | |
| 507 const Message* m = element->get_message(); | |
| 508 if (m) { | |
| 509 DVLOG(2) << "sent pending message @" << m << " on channel @" << this | |
| 510 << " with type " << m->type(); | |
| 511 } | |
| 512 | |
| 513 return true; | |
| 514 } | |
| 515 LOG(ERROR) << "pipe error: " << write_error; | |
| 516 return false; | |
| 517 } | |
| 518 | |
| 519 const Message* m = element->get_message(); | |
| 520 if (m) { | |
| 521 DVLOG(2) << "sent message @" << m << " on channel @" << this | |
| 522 << " with type " << m->type(); | |
| 523 } | |
| 524 | |
| 525 output_state_.is_pending = true; | |
| 526 return true; | |
| 527 } | |
| 528 | |
| 529 void ChannelWin::OnIOCompleted( | |
| 530 base::MessageLoopForIO::IOContext* context, | |
| 531 DWORD bytes_transfered, | |
| 532 DWORD error) { | |
| 533 bool ok = true; | |
| 534 DCHECK(thread_check_->CalledOnValidThread()); | |
| 535 if (context == &input_state_.context) { | |
| 536 if (waiting_connect_) { | |
| 537 if (!ProcessConnection()) | |
| 538 return; | |
| 539 // We may have some messages queued up to send... | |
| 540 if (!output_queue_.empty() && !output_state_.is_pending) | |
| 541 ProcessOutgoingMessages(NULL, 0); | |
| 542 if (input_state_.is_pending) | |
| 543 return; | |
| 544 // else, fall-through and look for incoming messages... | |
| 545 } | |
| 546 | |
| 547 // We don't support recursion through OnMessageReceived yet! | |
| 548 DCHECK(!processing_incoming_); | |
| 549 base::AutoReset<bool> auto_reset_processing_incoming( | |
| 550 &processing_incoming_, true); | |
| 551 | |
| 552 // Process the new data. | |
| 553 if (input_state_.is_pending) { | |
| 554 // This is the normal case for everything except the initialization step. | |
| 555 input_state_.is_pending = false; | |
| 556 if (!bytes_transfered) { | |
| 557 ok = false; | |
| 558 } else if (pipe_.IsValid()) { | |
| 559 ok = (AsyncReadComplete(bytes_transfered) != DISPATCH_ERROR); | |
| 560 } | |
| 561 } else { | |
| 562 DCHECK(!bytes_transfered); | |
| 563 } | |
| 564 | |
| 565 // Request more data. | |
| 566 if (ok) | |
| 567 ok = (ProcessIncomingMessages() != DISPATCH_ERROR); | |
| 568 } else { | |
| 569 DCHECK(context == &output_state_.context); | |
| 570 CHECK(output_state_.is_pending); | |
| 571 ok = ProcessOutgoingMessages(context, bytes_transfered); | |
| 572 } | |
| 573 if (!ok && pipe_.IsValid()) { | |
| 574 // We don't want to re-enter Close(). | |
| 575 Close(); | |
| 576 listener()->OnChannelError(); | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 //------------------------------------------------------------------------------ | |
| 581 // Channel's methods | |
| 582 | |
| 583 // static | |
| 584 std::unique_ptr<Channel> Channel::Create( | |
| 585 const IPC::ChannelHandle& channel_handle, | |
| 586 Mode mode, | |
| 587 Listener* listener) { | |
| 588 return base::WrapUnique(new ChannelWin(channel_handle, mode, listener)); | |
| 589 } | |
| 590 | |
| 591 // static | |
| 592 bool Channel::IsNamedServerInitialized(const std::string& channel_id) { | |
| 593 return ChannelWin::IsNamedServerInitialized(channel_id); | |
| 594 } | |
| 595 | |
| 596 // static | |
| 597 std::string Channel::GenerateVerifiedChannelID(const std::string& prefix) { | |
| 598 // Windows pipes can be enumerated by low-privileged processes. So, we | |
| 599 // append a strong random value after the \ character. This value is not | |
| 600 // included in the pipe name, but sent as part of the client hello, to | |
| 601 // hijacking the pipe name to spoof the client. | |
| 602 | |
| 603 std::string id = prefix; | |
| 604 if (!id.empty()) | |
| 605 id.append("."); | |
| 606 | |
| 607 int secret; | |
| 608 do { // Guarantee we get a non-zero value. | |
| 609 secret = base::RandInt(0, std::numeric_limits<int>::max()); | |
| 610 } while (secret == 0); | |
| 611 | |
| 612 id.append(GenerateUniqueRandomChannelID()); | |
| 613 return id.append(base::StringPrintf("\\%d", secret)); | |
| 614 } | |
| 615 | |
| 616 } // namespace IPC | |
| OLD | NEW |