Split the IPC code into ipc/

This splits the ipc code from the common project.  The 'common' project pulls in
all of webkit, the v8 bindings, skia, googleurl, and a number of other projects
which makes it very difficult to deal with especially for external projects
wanting just to use some of Chromium's infrastructure.  This puts the ipc code
into its top-level ipc/ directory with a dependency only on base.  The common
project depends on the new ipc/ipc.gyp:ipc target so that all projects currently
pulling common in to get the IPC code still have it available.  This mostly
follows agl's pre-gyp attempt to do this which was r13062.

Known issues:
- Currently a number of projects depend on chrome/chrome.gyp:common in order to
use the IPC infrastructure.  Rather than fixing all of these dependencies I have
made common depend on ipc/ipc.gyp:ipc and added "ipc" to the include_rules
section of DEPS so that checkdeps.py doesn't complain.  Over time projects that
need IPC should depend on the IPC project themselves and dependencies on common
removed, although I don't think many projects that need IPC will be able to get
away without common currently.
- ipc/ipc_message_macros.h still has #include "chrome/common/..." inside of a
ipc/ should not refer to files in chrome/... now.  I'm not sure how to resolve
this since it's really an IDE bug
- the named pipe name (windows+linux) and the logging event name (all) + env
variable (posix) refer explicitly to 'Chrome' which somewhat hurts the illusion
of ipc/ being an independent library.  I think this should be examined in a
subsequent, much smaller patch.
- I've eliminated the IPC.SendMsgCount counter since it was implemented in a way
to create a dependency from ipc/ to chrome/common/chrome_counters. This is the
same approach that r13062 took.

http://codereview.chromium.org/155905

(Patch from James Robinson)


git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21342 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 946d1b2c806795351598aeb9faaed797284a8ee3
diff --git a/ipc/ipc_fuzzing_tests.cc b/ipc/ipc_fuzzing_tests.cc
new file mode 100644
index 0000000..c79d05a
--- /dev/null
+++ b/ipc/ipc_fuzzing_tests.cc
@@ -0,0 +1,430 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#include "base/message_loop.h"
+#include "base/platform_thread.h"
+#include "base/process_util.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
+  //This was BUG 984408.
+  uint32 v1 = kuint32max - 1;
+  int v2 = 666;
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(v1));
+  EXPECT_TRUE(m.WriteInt(v2));
+
+  void* iter = NULL;
+  std::string vs;
+  EXPECT_FALSE(m.ReadString(&iter, &vs));
+}
+
+TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
+  //This was BUG 984408.
+  uint32 v1 = kuint32max - 1;
+  int v2 = 777;
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(v1));
+  EXPECT_TRUE(m.WriteInt(v2));
+
+  void* iter = NULL;
+  std::wstring vs;
+  EXPECT_FALSE(m.ReadWString(&iter, &vs));
+}
+
+TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
+  // This was BUG 1035467.
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(1));
+  EXPECT_TRUE(m.WriteInt(2));
+
+  void* iter = NULL;
+  const char* data = NULL;
+  EXPECT_FALSE(m.ReadBytes(&iter, &data, sizeof(int)));
+}
+
+TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
+  // A slight variation of BUG 984408. Note that the pickling of vector<char>
+  // has a specialized template which is not vulnerable to this bug. So here
+  // try to hit the non-specialized case vector<P>.
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(-1));   // This is the count of elements.
+  EXPECT_TRUE(m.WriteInt(1));
+  EXPECT_TRUE(m.WriteInt(2));
+  EXPECT_TRUE(m.WriteInt(3));
+
+  std::vector<double> vec;
+  void* iter = 0;
+  EXPECT_FALSE(ReadParam(&m, &iter, &vec));
+}
+
+TEST(IPCMessageIntegrity, ReadVectorTooLarge1) {
+  // This was BUG 1006367. This is the large but positive length case. Again
+  // we try to hit the non-specialized case vector<P>.
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(0x21000003));   // This is the count of elements.
+  EXPECT_TRUE(m.WriteInt64(1));
+  EXPECT_TRUE(m.WriteInt64(2));
+
+  std::vector<int64> vec;
+  void* iter = 0;
+  EXPECT_FALSE(ReadParam(&m, &iter, &vec));
+}
+
+TEST(IPCMessageIntegrity, ReadVectorTooLarge2) {
+  // This was BUG 1006367. This is the large but positive with an additional
+  // integer overflow when computing the actual byte size. Again we try to hit
+  // the non-specialized case vector<P>.
+  IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
+  EXPECT_TRUE(m.WriteInt(0x71000000));   // This is the count of elements.
+  EXPECT_TRUE(m.WriteInt64(1));
+  EXPECT_TRUE(m.WriteInt64(2));
+
+  std::vector<int64> vec;
+  void* iter = 0;
+  EXPECT_FALSE(ReadParam(&m, &iter, &vec));
+}
+
+// We don't actually use the messages defined in this file, but we do this
+// to get to the IPC macros.
+#define MESSAGES_INTERNAL_FILE "ipc/ipc_sync_message_unittest.h"
+#include "ipc/ipc_message_macros.h"
+
+enum IPCMessageIds {
+  UNUSED_IPC_TYPE,
+  SERVER_FIRST_IPC_TYPE,    // 1st Test message tag.
+  SERVER_SECOND_IPC_TYPE,   // 2nd Test message tag.
+  SERVER_THIRD_IPC_TYPE,    // 3rd Test message tag.
+  CLIENT_MALFORMED_IPC,     // Sent to client if server detects bad message.
+  CLIENT_UNHANDLED_IPC      // Sent to client if server detects unhanded IPC.
+};
+
+// Generic message class that is an int followed by a wstring.
+class MsgClassIS : public IPC::MessageWithTuple< Tuple2<int, std::wstring> > {
+ public:
+  enum { ID = SERVER_FIRST_IPC_TYPE };
+  MsgClassIS(const int& arg1, const std::wstring& arg2)
+      : IPC::MessageWithTuple< Tuple2<int, std::wstring> >(
+            MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1, arg2)) {}
+};
+
+// Generic message class that is a wstring followed by an int.
+class MsgClassSI : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > {
+ public:
+  enum { ID = SERVER_SECOND_IPC_TYPE };
+  MsgClassSI(const std::wstring& arg1, const int& arg2)
+      : IPC::MessageWithTuple< Tuple2<std::wstring, int> >(
+            MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1, arg2)) {}
+};
+
+// Message to create a mutex in the IPC server, using the received name.
+class MsgDoMutex : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > {
+ public:
+  enum { ID = SERVER_THIRD_IPC_TYPE };
+  MsgDoMutex(const std::wstring& mutex_name, const int& unused)
+      : IPC::MessageWithTuple< Tuple2<std::wstring, int> >(
+            MSG_ROUTING_CONTROL, ID, MakeRefTuple(mutex_name, unused)) {}
+};
+
+class SimpleListener : public IPC::Channel::Listener {
+ public:
+  SimpleListener() : other_(NULL) {
+  }
+  void Init(IPC::Message::Sender* s) {
+    other_ = s;
+  }
+ protected:
+  IPC::Message::Sender* other_;
+};
+
+enum {
+  FUZZER_ROUTING_ID = 5
+};
+
+// The fuzzer server class. It runs in a child process and expects
+// only two IPC calls; after that it exits the message loop which
+// terminates the child process.
+class FuzzerServerListener : public SimpleListener {
+ public:
+  FuzzerServerListener() : message_count_(2), pending_messages_(0) {
+  }
+  virtual void OnMessageReceived(const IPC::Message& msg) {
+    if (msg.routing_id() == MSG_ROUTING_CONTROL) {
+      ++pending_messages_;
+      IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg)
+        IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
+        IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
+      IPC_END_MESSAGE_MAP()
+      if (pending_messages_) {
+        // Probably a problem de-serializing the message.
+        ReplyMsgNotHandled(msg.type());
+      }
+    }
+  }
+
+ private:
+  void OnMsgClassISMessage(int value, const std::wstring& text) {
+    UseData(MsgClassIS::ID, value, text);
+    RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
+    Cleanup();
+  }
+
+  void OnMsgClassSIMessage(const std::wstring& text, int value) {
+    UseData(MsgClassSI::ID, value, text);
+    RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
+    Cleanup();
+  }
+
+  bool RoundtripAckReply(int routing, int type_id, int reply) {
+    IPC::Message* message = new IPC::Message(routing, type_id,
+                                             IPC::Message::PRIORITY_NORMAL);
+    message->WriteInt(reply + 1);
+    message->WriteInt(reply);
+    return other_->Send(message);
+  }
+
+  void Cleanup() {
+    --message_count_;
+    --pending_messages_;
+    if (0 == message_count_)
+      MessageLoop::current()->Quit();
+  }
+
+  void ReplyMsgNotHandled(int type_id) {
+    RoundtripAckReply(FUZZER_ROUTING_ID, CLIENT_UNHANDLED_IPC, type_id);
+    Cleanup();
+  }
+
+  void UseData(int caller, int value, const std::wstring& text) {
+    std::wostringstream wos;
+    wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n";
+    std::wstring output = wos.str();
+    LOG(WARNING) << output.c_str();
+  };
+
+  int message_count_;
+  int pending_messages_;
+};
+
+class FuzzerClientListener : public SimpleListener {
+ public:
+  FuzzerClientListener() : last_msg_(NULL) {
+  }
+
+  virtual void OnMessageReceived(const IPC::Message& msg) {
+    last_msg_ = new IPC::Message(msg);
+    MessageLoop::current()->Quit();
+  }
+
+  bool ExpectMessage(int value, int type_id) {
+    if (!MsgHandlerInternal(type_id))
+      return false;
+    int msg_value1 = 0;
+    int msg_value2 = 0;
+    void* iter = NULL;
+    if (!last_msg_->ReadInt(&iter, &msg_value1))
+      return false;
+    if (!last_msg_->ReadInt(&iter, &msg_value2))
+      return false;
+    if ((msg_value2 + 1) != msg_value1)
+      return false;
+    if (msg_value2 != value)
+      return false;
+
+    delete last_msg_;
+    last_msg_ = NULL;
+    return true;
+  }
+
+  bool ExpectMsgNotHandled(int type_id) {
+    return ExpectMessage(type_id, CLIENT_UNHANDLED_IPC);
+  }
+
+ private:
+  bool MsgHandlerInternal(int type_id) {
+    MessageLoop::current()->Run();
+    if (NULL == last_msg_)
+      return false;
+    if (FUZZER_ROUTING_ID != last_msg_->routing_id())
+      return false;
+    return (type_id == last_msg_->type());
+  };
+
+  IPC::Message* last_msg_;
+};
+
+// Runs the fuzzing server child mode. Returns when the preset number
+// of messages have been received.
+MULTIPROCESS_TEST_MAIN(RunFuzzServer) {
+  MessageLoopForIO main_message_loop;
+  FuzzerServerListener listener;
+  IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, &listener);
+  chan.Connect();
+  listener.Init(&chan);
+  MessageLoop::current()->Run();
+  return 0;
+}
+
+class IPCFuzzingTest : public IPCChannelTest {
+};
+
+// This test makes sure that the FuzzerClientListener and FuzzerServerListener
+// are working properly by generating two well formed IPC calls.
+TEST_F(IPCFuzzingTest, SanityTest) {
+  FuzzerClientListener listener;
+  IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
+                    &listener);
+  base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
+  ASSERT_TRUE(server_process);
+  PlatformThread::Sleep(1000);
+  ASSERT_TRUE(chan.Connect());
+  listener.Init(&chan);
+
+  IPC::Message* msg = NULL;
+  int value = 43;
+  msg = new MsgClassIS(value, L"expect 43");
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
+
+  msg = new MsgClassSI(L"expect 44", ++value);
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
+
+  EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000));
+  base::CloseProcessHandle(server_process);
+}
+
+// This test uses a payload that is smaller than expected.
+// This generates an error while unpacking the IPC buffer which in
+// In debug this triggers an assertion and in release it is ignored(!!). Right
+// after we generate another valid IPC to make sure framing is working
+// properly.
+#ifdef NDEBUG
+TEST_F(IPCFuzzingTest, MsgBadPayloadShort) {
+  FuzzerClientListener listener;
+  IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
+                    &listener);
+  base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
+  ASSERT_TRUE(server_process);
+  PlatformThread::Sleep(1000);
+  ASSERT_TRUE(chan.Connect());
+  listener.Init(&chan);
+
+  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
+                                       IPC::Message::PRIORITY_NORMAL);
+  msg->WriteInt(666);
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
+
+  msg = new MsgClassSI(L"expect one", 1);
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
+
+  EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000));
+  base::CloseProcessHandle(server_process);
+}
+#endif  // NDEBUG
+
+// This test uses a payload that has too many arguments, but so the payload
+// size is big enough so the unpacking routine does not generate an error as
+// in the case of MsgBadPayloadShort test.
+// This test does not pinpoint a flaw (per se) as by design we don't carry
+// type information on the IPC message.
+TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
+  FuzzerClientListener listener;
+  IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
+                    &listener);
+  base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
+  ASSERT_TRUE(server_process);
+  PlatformThread::Sleep(1000);
+  ASSERT_TRUE(chan.Connect());
+  listener.Init(&chan);
+
+  IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
+                                       IPC::Message::PRIORITY_NORMAL);
+  msg->WriteWString(L"d");
+  msg->WriteInt(0);
+  msg->WriteInt(0x65);  // Extra argument.
+
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID));
+
+  // Now send a well formed message to make sure the receiver wasn't
+  // thrown out of sync by the extra argument.
+  msg = new MsgClassIS(3, L"expect three");
+  chan.Send(msg);
+  EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
+
+  EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000));
+  base::CloseProcessHandle(server_process);
+}
+
+// This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros.
+class ServerMacroExTest {
+ public:
+  ServerMacroExTest() : unhandled_msgs_(0) {
+  }
+  virtual bool OnMessageReceived(const IPC::Message& msg) {
+    bool msg_is_ok = false;
+    IPC_BEGIN_MESSAGE_MAP_EX(ServerMacroExTest, msg, msg_is_ok)
+      IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
+      IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
+      IPC_MESSAGE_UNHANDLED(++unhandled_msgs_)
+    IPC_END_MESSAGE_MAP_EX()
+    return msg_is_ok;
+  }
+
+  int unhandled_msgs() const {
+    return unhandled_msgs_;
+  }
+
+ private:
+  void OnMsgClassISMessage(int value, const std::wstring& text) {
+  }
+  void OnMsgClassSIMessage(const std::wstring& text, int value) {
+  }
+
+  int unhandled_msgs_;
+};
+
+TEST_F(IPCFuzzingTest, MsgMapExMacro) {
+  IPC::Message* msg = NULL;
+  ServerMacroExTest server;
+
+  // Test the regular messages.
+  msg = new MsgClassIS(3, L"text3");
+  EXPECT_TRUE(server.OnMessageReceived(*msg));
+  delete msg;
+  msg = new MsgClassSI(L"text2", 2);
+  EXPECT_TRUE(server.OnMessageReceived(*msg));
+  delete msg;
+
+#ifdef NDEBUG
+  // Test a bad message.
+  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
+                         IPC::Message::PRIORITY_NORMAL);
+  msg->WriteInt(2);
+  EXPECT_FALSE(server.OnMessageReceived(*msg));
+  delete msg;
+
+  msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
+                         IPC::Message::PRIORITY_NORMAL);
+  msg->WriteInt(0x64);
+  msg->WriteInt(0x32);
+  EXPECT_FALSE(server.OnMessageReceived(*msg));
+  delete msg;
+
+  EXPECT_EQ(0, server.unhandled_msgs());
+#endif
+}