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