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