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