diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/common/ipc_fuzzing_tests.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/ipc_fuzzing_tests.cc')
-rw-r--r-- | chrome/common/ipc_fuzzing_tests.cc | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/chrome/common/ipc_fuzzing_tests.cc b/chrome/common/ipc_fuzzing_tests.cc new file mode 100644 index 0000000..8d2aebb --- /dev/null +++ b/chrome/common/ipc_fuzzing_tests.cc @@ -0,0 +1,443 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <windows.h> +#include <stdio.h> +#include <iostream> +#include <string> +#include <sstream> + +#include "chrome/common/ipc_tests.h" + +#include "chrome/common/ipc_channel.h" +#include "chrome/common/ipc_channel_proxy.h" +#include "chrome/common/ipc_message_utils.h" +#include "testing/gtest/include/gtest/gtest.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)); +} + +// Typically the ipc_message_macros files is included twice but here we only +// include it once in 'enum mode' because we want more control of the class +// definitions. +#define IPC_MESSAGE_MACROS_ENUMS +#include "chrome/common/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, MakeTuple(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, MakeTuple(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, MakeTuple(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(); + ::OutputDebugStringW(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_; +}; + +bool RunFuzzServer() { + FuzzerServerListener listener; + IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, &listener); + chan.Connect(); + listener.Init(&chan); + MessageLoop::current()->Run(); + return true; +} + +// This test makes sure that the FuzzerClientListener and FuzzerServerListener +// are working properly by generating two well formed IPC calls. +TEST(IPCFuzzingTest, SanityTest) { + HANDLE server_process = SpawnChild(FUZZER_SERVER); + ASSERT_TRUE(server_process); + ::Sleep(1000); + FuzzerClientListener listener; + IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, + &listener); + 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)); + + ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000)); +} + +// 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(IPCFuzzingTest, MsgBadPayloadShort) { + HANDLE server_process = SpawnChild(FUZZER_SERVER); + ASSERT_TRUE(server_process); + ::Sleep(1000); + FuzzerClientListener listener; + IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, + &listener); + 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)); + + ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000)); +} +#endif // NDEBUG + +// This test uses a payload that has the wrong 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(IPCFuzzingTest, MsgBadPayloadArgs) { + HANDLE server_process = SpawnChild(FUZZER_SERVER); + ASSERT_TRUE(server_process); + ::Sleep(1000); + FuzzerClientListener listener; + IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, + &listener); + ASSERT_TRUE(chan.Connect()); + listener.Init(&chan); + + IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID, + IPC::Message::PRIORITY_NORMAL); + msg->WriteInt(2); + msg->WriteInt(0x64); + msg->WriteInt(0); + msg->WriteInt(0x65); + chan.Send(msg); + EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID)); + + msg = new MsgClassIS(3, L"expect three"); + chan.Send(msg); + EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID)); + + ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000)); +} + +// 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(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 +} |