Home | History | Annotate | Download | only in ipc
      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 
     26 ChannelWin::State::State(ChannelWin* channel) : is_pending(false) {
     27   memset(&context.overlapped, 0, sizeof(context.overlapped));
     28   context.handler = channel;
     29 }
     30 
     31 ChannelWin::State::~State() {
     32   COMPILE_ASSERT(!offsetof(ChannelWin::State, context),
     33                  starts_with_io_context);
     34 }
     35 
     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 
     51 ChannelWin::~ChannelWin() {
     52   Close();
     53 }
     54 
     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 
     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 
    106 base::ProcessId ChannelWin::GetPeerPID() const {
    107   return peer_pid_;
    108 }
    109 
    110 // static
    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 
    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 
    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 
    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 
    184 bool ChannelWin::DidEmptyInputBuffers() {
    185   // We don't need to do anything here.
    186   return true;
    187 }
    188 
    189 // static
    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 
    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 
    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 
    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 
    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 
    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
    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
    480 bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
    481   return ChannelWin::IsNamedServerInitialized(channel_id);
    482 }
    483 
    484 // static
    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