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