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 <stdio.h>
      6 #include <string>
      7 #include <sstream>
      8 
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/threading/platform_thread.h"
     11 #include "ipc/ipc_test_base.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 // IPC messages for testing ----------------------------------------------------
     15 
     16 #define IPC_MESSAGE_IMPL
     17 #include "ipc/ipc_message_macros.h"
     18 
     19 #define IPC_MESSAGE_START TestMsgStart
     20 
     21 // Generic message class that is an int followed by a wstring.
     22 IPC_MESSAGE_CONTROL2(MsgClassIS, int, std::wstring)
     23 
     24 // Generic message class that is a wstring followed by an int.
     25 IPC_MESSAGE_CONTROL2(MsgClassSI, std::wstring, int)
     26 
     27 // Message to create a mutex in the IPC server, using the received name.
     28 IPC_MESSAGE_CONTROL2(MsgDoMutex, std::wstring, int)
     29 
     30 // Used to generate an ID for a message that should not exist.
     31 IPC_MESSAGE_CONTROL0(MsgUnhandled)
     32 
     33 // -----------------------------------------------------------------------------
     34 
     35 namespace {
     36 
     37 TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
     38   //This was BUG 984408.
     39   uint32 v1 = kuint32max - 1;
     40   int v2 = 666;
     41   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
     42   EXPECT_TRUE(m.WriteInt(v1));
     43   EXPECT_TRUE(m.WriteInt(v2));
     44 
     45   PickleIterator iter(m);
     46   std::string vs;
     47   EXPECT_FALSE(m.ReadString(&iter, &vs));
     48 }
     49 
     50 TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
     51   //This was BUG 984408.
     52   uint32 v1 = kuint32max - 1;
     53   int v2 = 777;
     54   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
     55   EXPECT_TRUE(m.WriteInt(v1));
     56   EXPECT_TRUE(m.WriteInt(v2));
     57 
     58   PickleIterator iter(m);
     59   std::wstring vs;
     60   EXPECT_FALSE(m.ReadWString(&iter, &vs));
     61 }
     62 
     63 TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
     64   // This was BUG 1035467.
     65   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
     66   EXPECT_TRUE(m.WriteInt(1));
     67   EXPECT_TRUE(m.WriteInt(2));
     68 
     69   PickleIterator iter(m);
     70   const char* data = NULL;
     71   EXPECT_TRUE(m.ReadBytes(&iter, &data, sizeof(int)));
     72 }
     73 
     74 TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
     75   // A slight variation of BUG 984408. Note that the pickling of vector<char>
     76   // has a specialized template which is not vulnerable to this bug. So here
     77   // try to hit the non-specialized case vector<P>.
     78   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
     79   EXPECT_TRUE(m.WriteInt(-1));   // This is the count of elements.
     80   EXPECT_TRUE(m.WriteInt(1));
     81   EXPECT_TRUE(m.WriteInt(2));
     82   EXPECT_TRUE(m.WriteInt(3));
     83 
     84   std::vector<double> vec;
     85   PickleIterator iter(m);
     86   EXPECT_FALSE(ReadParam(&m, &iter, &vec));
     87 }
     88 
     89 TEST(IPCMessageIntegrity, ReadVectorTooLarge1) {
     90   // This was BUG 1006367. This is the large but positive length case. Again
     91   // we try to hit the non-specialized case vector<P>.
     92   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
     93   EXPECT_TRUE(m.WriteInt(0x21000003));   // This is the count of elements.
     94   EXPECT_TRUE(m.WriteInt64(1));
     95   EXPECT_TRUE(m.WriteInt64(2));
     96 
     97   std::vector<int64> vec;
     98   PickleIterator iter(m);
     99   EXPECT_FALSE(ReadParam(&m, &iter, &vec));
    100 }
    101 
    102 TEST(IPCMessageIntegrity, ReadVectorTooLarge2) {
    103   // This was BUG 1006367. This is the large but positive with an additional
    104   // integer overflow when computing the actual byte size. Again we try to hit
    105   // the non-specialized case vector<P>.
    106   IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
    107   EXPECT_TRUE(m.WriteInt(0x71000000));   // This is the count of elements.
    108   EXPECT_TRUE(m.WriteInt64(1));
    109   EXPECT_TRUE(m.WriteInt64(2));
    110 
    111   std::vector<int64> vec;
    112   PickleIterator iter(m);
    113   EXPECT_FALSE(ReadParam(&m, &iter, &vec));
    114 }
    115 
    116 class SimpleListener : public IPC::Listener {
    117  public:
    118   SimpleListener() : other_(NULL) {
    119   }
    120   void Init(IPC::Sender* s) {
    121     other_ = s;
    122   }
    123  protected:
    124   IPC::Sender* other_;
    125 };
    126 
    127 enum {
    128   FUZZER_ROUTING_ID = 5
    129 };
    130 
    131 // The fuzzer server class. It runs in a child process and expects
    132 // only two IPC calls; after that it exits the message loop which
    133 // terminates the child process.
    134 class FuzzerServerListener : public SimpleListener {
    135  public:
    136   FuzzerServerListener() : message_count_(2), pending_messages_(0) {
    137   }
    138   virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
    139     if (msg.routing_id() == MSG_ROUTING_CONTROL) {
    140       ++pending_messages_;
    141       IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg)
    142         IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
    143         IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
    144       IPC_END_MESSAGE_MAP()
    145       if (pending_messages_) {
    146         // Probably a problem de-serializing the message.
    147         ReplyMsgNotHandled(msg.type());
    148       }
    149     }
    150     return true;
    151   }
    152 
    153  private:
    154   void OnMsgClassISMessage(int value, const std::wstring& text) {
    155     UseData(MsgClassIS::ID, value, text);
    156     RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
    157     Cleanup();
    158   }
    159 
    160   void OnMsgClassSIMessage(const std::wstring& text, int value) {
    161     UseData(MsgClassSI::ID, value, text);
    162     RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
    163     Cleanup();
    164   }
    165 
    166   bool RoundtripAckReply(int routing, uint32 type_id, int reply) {
    167     IPC::Message* message = new IPC::Message(routing, type_id,
    168                                              IPC::Message::PRIORITY_NORMAL);
    169     message->WriteInt(reply + 1);
    170     message->WriteInt(reply);
    171     return other_->Send(message);
    172   }
    173 
    174   void Cleanup() {
    175     --message_count_;
    176     --pending_messages_;
    177     if (0 == message_count_)
    178       base::MessageLoop::current()->Quit();
    179   }
    180 
    181   void ReplyMsgNotHandled(uint32 type_id) {
    182     RoundtripAckReply(FUZZER_ROUTING_ID, MsgUnhandled::ID, type_id);
    183     Cleanup();
    184   }
    185 
    186   void UseData(int caller, int value, const std::wstring& text) {
    187     std::wostringstream wos;
    188     wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n";
    189     std::wstring output = wos.str();
    190     LOG(WARNING) << output.c_str();
    191   };
    192 
    193   int message_count_;
    194   int pending_messages_;
    195 };
    196 
    197 class FuzzerClientListener : public SimpleListener {
    198  public:
    199   FuzzerClientListener() : last_msg_(NULL) {
    200   }
    201 
    202   virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE {
    203     last_msg_ = new IPC::Message(msg);
    204     base::MessageLoop::current()->Quit();
    205     return true;
    206   }
    207 
    208   bool ExpectMessage(int value, uint32 type_id) {
    209     if (!MsgHandlerInternal(type_id))
    210       return false;
    211     int msg_value1 = 0;
    212     int msg_value2 = 0;
    213     PickleIterator iter(*last_msg_);
    214     if (!last_msg_->ReadInt(&iter, &msg_value1))
    215       return false;
    216     if (!last_msg_->ReadInt(&iter, &msg_value2))
    217       return false;
    218     if ((msg_value2 + 1) != msg_value1)
    219       return false;
    220     if (msg_value2 != value)
    221       return false;
    222 
    223     delete last_msg_;
    224     last_msg_ = NULL;
    225     return true;
    226   }
    227 
    228   bool ExpectMsgNotHandled(uint32 type_id) {
    229     return ExpectMessage(type_id, MsgUnhandled::ID);
    230   }
    231 
    232  private:
    233   bool MsgHandlerInternal(uint32 type_id) {
    234     base::MessageLoop::current()->Run();
    235     if (NULL == last_msg_)
    236       return false;
    237     if (FUZZER_ROUTING_ID != last_msg_->routing_id())
    238       return false;
    239     return (type_id == last_msg_->type());
    240   };
    241 
    242   IPC::Message* last_msg_;
    243 };
    244 
    245 // Runs the fuzzing server child mode. Returns when the preset number of
    246 // messages have been received.
    247 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(FuzzServerClient) {
    248   base::MessageLoopForIO main_message_loop;
    249   FuzzerServerListener listener;
    250   IPC::Channel channel(IPCTestBase::GetChannelName("FuzzServerClient"),
    251                        IPC::Channel::MODE_CLIENT,
    252                        &listener);
    253   CHECK(channel.Connect());
    254   listener.Init(&channel);
    255   base::MessageLoop::current()->Run();
    256   return 0;
    257 }
    258 
    259 class IPCFuzzingTest : public IPCTestBase {
    260 };
    261 
    262 // This test makes sure that the FuzzerClientListener and FuzzerServerListener
    263 // are working properly by generating two well formed IPC calls.
    264 TEST_F(IPCFuzzingTest, SanityTest) {
    265   Init("FuzzServerClient");
    266 
    267   FuzzerClientListener listener;
    268   CreateChannel(&listener);
    269   listener.Init(channel());
    270   ASSERT_TRUE(ConnectChannel());
    271   ASSERT_TRUE(StartClient());
    272 
    273   IPC::Message* msg = NULL;
    274   int value = 43;
    275   msg = new MsgClassIS(value, L"expect 43");
    276   sender()->Send(msg);
    277   EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
    278 
    279   msg = new MsgClassSI(L"expect 44", ++value);
    280   sender()->Send(msg);
    281   EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
    282 
    283   EXPECT_TRUE(WaitForClientShutdown());
    284   DestroyChannel();
    285 }
    286 
    287 // This test uses a payload that is smaller than expected. This generates an
    288 // error while unpacking the IPC buffer which in debug trigger an assertion and
    289 // in release is ignored (!). Right after we generate another valid IPC to make
    290 // sure framing is working properly.
    291 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
    292 TEST_F(IPCFuzzingTest, MsgBadPayloadShort) {
    293   Init("FuzzServerClient");
    294 
    295   FuzzerClientListener listener;
    296   CreateChannel(&listener);
    297   listener.Init(channel());
    298   ASSERT_TRUE(ConnectChannel());
    299   ASSERT_TRUE(StartClient());
    300 
    301   IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
    302                                        IPC::Message::PRIORITY_NORMAL);
    303   msg->WriteInt(666);
    304   sender()->Send(msg);
    305   EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
    306 
    307   msg = new MsgClassSI(L"expect one", 1);
    308   sender()->Send(msg);
    309   EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
    310 
    311   EXPECT_TRUE(WaitForClientShutdown());
    312   DestroyChannel();
    313 }
    314 #endif
    315 
    316 // This test uses a payload that has too many arguments, but so the payload size
    317 // is big enough so the unpacking routine does not generate an error as in the
    318 // case of MsgBadPayloadShort test. This test does not pinpoint a flaw (per se)
    319 // as by design we don't carry type information on the IPC message.
    320 TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
    321   Init("FuzzServerClient");
    322 
    323   FuzzerClientListener listener;
    324   CreateChannel(&listener);
    325   listener.Init(channel());
    326   ASSERT_TRUE(ConnectChannel());
    327   ASSERT_TRUE(StartClient());
    328 
    329   IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
    330                                        IPC::Message::PRIORITY_NORMAL);
    331   msg->WriteWString(L"d");
    332   msg->WriteInt(0);
    333   msg->WriteInt(0x65);  // Extra argument.
    334 
    335   sender()->Send(msg);
    336   EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID));
    337 
    338   // Now send a well formed message to make sure the receiver wasn't
    339   // thrown out of sync by the extra argument.
    340   msg = new MsgClassIS(3, L"expect three");
    341   sender()->Send(msg);
    342   EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
    343 
    344   EXPECT_TRUE(WaitForClientShutdown());
    345   DestroyChannel();
    346 }
    347 
    348 // This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros.
    349 class ServerMacroExTest {
    350  public:
    351   ServerMacroExTest() : unhandled_msgs_(0) {
    352   }
    353 
    354   virtual ~ServerMacroExTest() {
    355   }
    356 
    357   virtual bool OnMessageReceived(const IPC::Message& msg) {
    358     bool msg_is_ok = false;
    359     IPC_BEGIN_MESSAGE_MAP_EX(ServerMacroExTest, msg, msg_is_ok)
    360       IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
    361       IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
    362       IPC_MESSAGE_UNHANDLED(++unhandled_msgs_)
    363     IPC_END_MESSAGE_MAP_EX()
    364     return msg_is_ok;
    365   }
    366 
    367   int unhandled_msgs() const {
    368     return unhandled_msgs_;
    369   }
    370 
    371  private:
    372   void OnMsgClassISMessage(int value, const std::wstring& text) {
    373   }
    374   void OnMsgClassSIMessage(const std::wstring& text, int value) {
    375   }
    376 
    377   int unhandled_msgs_;
    378 
    379   DISALLOW_COPY_AND_ASSIGN(ServerMacroExTest);
    380 };
    381 
    382 TEST_F(IPCFuzzingTest, MsgMapExMacro) {
    383   IPC::Message* msg = NULL;
    384   ServerMacroExTest server;
    385 
    386   // Test the regular messages.
    387   msg = new MsgClassIS(3, L"text3");
    388   EXPECT_TRUE(server.OnMessageReceived(*msg));
    389   delete msg;
    390   msg = new MsgClassSI(L"text2", 2);
    391   EXPECT_TRUE(server.OnMessageReceived(*msg));
    392   delete msg;
    393 
    394 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
    395   // Test a bad message.
    396   msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
    397                          IPC::Message::PRIORITY_NORMAL);
    398   msg->WriteInt(2);
    399   EXPECT_FALSE(server.OnMessageReceived(*msg));
    400   delete msg;
    401 
    402   msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
    403                          IPC::Message::PRIORITY_NORMAL);
    404   msg->WriteInt(0x64);
    405   msg->WriteInt(0x32);
    406   EXPECT_FALSE(server.OnMessageReceived(*msg));
    407   delete msg;
    408 
    409   EXPECT_EQ(0, server.unhandled_msgs());
    410 #endif
    411 }
    412 
    413 }  // namespace
    414