blob: 080c6432d0b2607268feeafe995737c6e6c28a3b [file] [log] [blame]
tedvessenes@gmail.com30dbbaa2012-01-13 09:11:01 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// 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>
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09006#include <string>
7#include <sstream>
8
9#include "base/message_loop.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090010#include "base/process_util.h"
brettw@google.com7c5cc672011-01-01 11:17:08 +090011#include "base/threading/platform_thread.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090012#include "ipc/ipc_channel.h"
13#include "ipc/ipc_channel_proxy.h"
jcivelli@chromium.orgc30c76f2012-06-27 10:12:24 +090014#include "ipc/ipc_multiprocess_test.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090015#include "ipc/ipc_test_base.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090016#include "testing/gtest/include/gtest/gtest.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090017
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090018// IPC messages for testing ----------------------------------------------------
darin@chromium.orgb4587d52011-08-27 06:27:30 +090019
20#define IPC_MESSAGE_IMPL
21#include "ipc/ipc_message_macros.h"
22
23#define IPC_MESSAGE_START TestMsgStart
24
25// Generic message class that is an int followed by a wstring.
26IPC_MESSAGE_CONTROL2(MsgClassIS, int, std::wstring)
27
28// Generic message class that is a wstring followed by an int.
29IPC_MESSAGE_CONTROL2(MsgClassSI, std::wstring, int)
30
31// Message to create a mutex in the IPC server, using the received name.
32IPC_MESSAGE_CONTROL2(MsgDoMutex, std::wstring, int)
33
34// Used to generate an ID for a message that should not exist.
35IPC_MESSAGE_CONTROL0(MsgUnhandled)
36
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090037// -----------------------------------------------------------------------------
38
39namespace {
darin@chromium.orgb4587d52011-08-27 06:27:30 +090040
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090041TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
42 //This was BUG 984408.
43 uint32 v1 = kuint32max - 1;
44 int v2 = 666;
45 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
46 EXPECT_TRUE(m.WriteInt(v1));
47 EXPECT_TRUE(m.WriteInt(v2));
48
jbates@chromium.org0fc87362012-03-08 05:42:56 +090049 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090050 std::string vs;
51 EXPECT_FALSE(m.ReadString(&iter, &vs));
52}
53
54TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
55 //This was BUG 984408.
56 uint32 v1 = kuint32max - 1;
57 int v2 = 777;
58 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
59 EXPECT_TRUE(m.WriteInt(v1));
60 EXPECT_TRUE(m.WriteInt(v2));
61
jbates@chromium.org0fc87362012-03-08 05:42:56 +090062 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090063 std::wstring vs;
64 EXPECT_FALSE(m.ReadWString(&iter, &vs));
65}
66
67TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
68 // This was BUG 1035467.
69 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
70 EXPECT_TRUE(m.WriteInt(1));
71 EXPECT_TRUE(m.WriteInt(2));
72
jbates@chromium.org0fc87362012-03-08 05:42:56 +090073 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090074 const char* data = NULL;
mpcomplete@chromium.org0409ecb2010-03-31 08:52:24 +090075 EXPECT_TRUE(m.ReadBytes(&iter, &data, sizeof(int)));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090076}
77
78TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
79 // A slight variation of BUG 984408. Note that the pickling of vector<char>
80 // has a specialized template which is not vulnerable to this bug. So here
81 // try to hit the non-specialized case vector<P>.
82 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
83 EXPECT_TRUE(m.WriteInt(-1)); // This is the count of elements.
84 EXPECT_TRUE(m.WriteInt(1));
85 EXPECT_TRUE(m.WriteInt(2));
86 EXPECT_TRUE(m.WriteInt(3));
87
88 std::vector<double> vec;
jbates@chromium.org0fc87362012-03-08 05:42:56 +090089 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090090 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
91}
92
93TEST(IPCMessageIntegrity, ReadVectorTooLarge1) {
94 // This was BUG 1006367. This is the large but positive length case. Again
95 // we try to hit the non-specialized case vector<P>.
96 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
97 EXPECT_TRUE(m.WriteInt(0x21000003)); // This is the count of elements.
98 EXPECT_TRUE(m.WriteInt64(1));
99 EXPECT_TRUE(m.WriteInt64(2));
100
101 std::vector<int64> vec;
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900102 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900103 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
104}
105
106TEST(IPCMessageIntegrity, ReadVectorTooLarge2) {
107 // This was BUG 1006367. This is the large but positive with an additional
108 // integer overflow when computing the actual byte size. Again we try to hit
109 // the non-specialized case vector<P>.
110 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
111 EXPECT_TRUE(m.WriteInt(0x71000000)); // This is the count of elements.
112 EXPECT_TRUE(m.WriteInt64(1));
113 EXPECT_TRUE(m.WriteInt64(2));
114
115 std::vector<int64> vec;
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900116 PickleIterator iter(m);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900117 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
118}
119
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900120class SimpleListener : public IPC::Listener {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900121 public:
122 SimpleListener() : other_(NULL) {
123 }
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900124 void Init(IPC::Sender* s) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900125 other_ = s;
126 }
127 protected:
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900128 IPC::Sender* other_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900129};
130
131enum {
132 FUZZER_ROUTING_ID = 5
133};
134
135// The fuzzer server class. It runs in a child process and expects
136// only two IPC calls; after that it exits the message loop which
137// terminates the child process.
138class FuzzerServerListener : public SimpleListener {
139 public:
140 FuzzerServerListener() : message_count_(2), pending_messages_(0) {
141 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900142 virtual bool OnMessageReceived(const IPC::Message& msg) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900143 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
144 ++pending_messages_;
145 IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg)
146 IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
147 IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
148 IPC_END_MESSAGE_MAP()
149 if (pending_messages_) {
150 // Probably a problem de-serializing the message.
151 ReplyMsgNotHandled(msg.type());
152 }
153 }
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900154 return true;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900155 }
156
157 private:
158 void OnMsgClassISMessage(int value, const std::wstring& text) {
159 UseData(MsgClassIS::ID, value, text);
160 RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
161 Cleanup();
162 }
163
164 void OnMsgClassSIMessage(const std::wstring& text, int value) {
165 UseData(MsgClassSI::ID, value, text);
166 RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
167 Cleanup();
168 }
169
thomasvl@google.com9a242072010-07-23 23:18:59 +0900170 bool RoundtripAckReply(int routing, uint32 type_id, int reply) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900171 IPC::Message* message = new IPC::Message(routing, type_id,
172 IPC::Message::PRIORITY_NORMAL);
173 message->WriteInt(reply + 1);
174 message->WriteInt(reply);
175 return other_->Send(message);
176 }
177
178 void Cleanup() {
179 --message_count_;
180 --pending_messages_;
181 if (0 == message_count_)
182 MessageLoop::current()->Quit();
183 }
184
thomasvl@google.com9a242072010-07-23 23:18:59 +0900185 void ReplyMsgNotHandled(uint32 type_id) {
darin@chromium.orgb4587d52011-08-27 06:27:30 +0900186 RoundtripAckReply(FUZZER_ROUTING_ID, MsgUnhandled::ID, type_id);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900187 Cleanup();
188 }
189
190 void UseData(int caller, int value, const std::wstring& text) {
191 std::wostringstream wos;
192 wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n";
193 std::wstring output = wos.str();
194 LOG(WARNING) << output.c_str();
195 };
196
197 int message_count_;
198 int pending_messages_;
199};
200
201class FuzzerClientListener : public SimpleListener {
202 public:
203 FuzzerClientListener() : last_msg_(NULL) {
204 }
205
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900206 virtual bool OnMessageReceived(const IPC::Message& msg) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900207 last_msg_ = new IPC::Message(msg);
208 MessageLoop::current()->Quit();
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900209 return true;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900210 }
211
thomasvl@google.com9a242072010-07-23 23:18:59 +0900212 bool ExpectMessage(int value, uint32 type_id) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900213 if (!MsgHandlerInternal(type_id))
214 return false;
215 int msg_value1 = 0;
216 int msg_value2 = 0;
jbates@chromium.org0fc87362012-03-08 05:42:56 +0900217 PickleIterator iter(*last_msg_);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900218 if (!last_msg_->ReadInt(&iter, &msg_value1))
219 return false;
220 if (!last_msg_->ReadInt(&iter, &msg_value2))
221 return false;
222 if ((msg_value2 + 1) != msg_value1)
223 return false;
224 if (msg_value2 != value)
225 return false;
226
227 delete last_msg_;
228 last_msg_ = NULL;
229 return true;
230 }
231
thomasvl@google.com9a242072010-07-23 23:18:59 +0900232 bool ExpectMsgNotHandled(uint32 type_id) {
darin@chromium.orgb4587d52011-08-27 06:27:30 +0900233 return ExpectMessage(type_id, MsgUnhandled::ID);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900234 }
235
236 private:
thomasvl@google.com9a242072010-07-23 23:18:59 +0900237 bool MsgHandlerInternal(uint32 type_id) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900238 MessageLoop::current()->Run();
239 if (NULL == last_msg_)
240 return false;
241 if (FUZZER_ROUTING_ID != last_msg_->routing_id())
242 return false;
243 return (type_id == last_msg_->type());
244 };
245
246 IPC::Message* last_msg_;
247};
248
249// Runs the fuzzing server child mode. Returns when the preset number
250// of messages have been received.
jcivelli@chromium.orgc30c76f2012-06-27 10:12:24 +0900251MULTIPROCESS_IPC_TEST_MAIN(RunFuzzServer) {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900252 MessageLoopForIO main_message_loop;
253 FuzzerServerListener listener;
254 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT, &listener);
evan@chromium.org1f3e46b2010-10-20 04:11:15 +0900255 CHECK(chan.Connect());
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900256 listener.Init(&chan);
257 MessageLoop::current()->Run();
258 return 0;
259}
260
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900261class IPCFuzzingTest : public IPCTestBase {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900262};
263
264// This test makes sure that the FuzzerClientListener and FuzzerServerListener
265// are working properly by generating two well formed IPC calls.
266TEST_F(IPCFuzzingTest, SanityTest) {
267 FuzzerClientListener listener;
268 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
269 &listener);
270 base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
271 ASSERT_TRUE(server_process);
tedvessenes@gmail.com30dbbaa2012-01-13 09:11:01 +0900272 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900273 ASSERT_TRUE(chan.Connect());
274 listener.Init(&chan);
275
276 IPC::Message* msg = NULL;
277 int value = 43;
278 msg = new MsgClassIS(value, L"expect 43");
279 chan.Send(msg);
280 EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
281
282 msg = new MsgClassSI(L"expect 44", ++value);
283 chan.Send(msg);
284 EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
285
tedvessenes@gmail.com5966b642012-07-12 00:41:43 +0900286 EXPECT_TRUE(base::WaitForSingleProcess(
287 server_process, base::TimeDelta::FromSeconds(5)));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900288 base::CloseProcessHandle(server_process);
289}
290
291// This test uses a payload that is smaller than expected.
292// This generates an error while unpacking the IPC buffer which in
293// In debug this triggers an assertion and in release it is ignored(!!). Right
294// after we generate another valid IPC to make sure framing is working
295// properly.
nsylvain@chromium.org675aad32011-09-21 05:59:01 +0900296#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900297TEST_F(IPCFuzzingTest, MsgBadPayloadShort) {
298 FuzzerClientListener listener;
299 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
300 &listener);
301 base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
302 ASSERT_TRUE(server_process);
tedvessenes@gmail.com30dbbaa2012-01-13 09:11:01 +0900303 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900304 ASSERT_TRUE(chan.Connect());
305 listener.Init(&chan);
306
307 IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
308 IPC::Message::PRIORITY_NORMAL);
309 msg->WriteInt(666);
310 chan.Send(msg);
311 EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
312
313 msg = new MsgClassSI(L"expect one", 1);
314 chan.Send(msg);
315 EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
316
tedvessenes@gmail.com5966b642012-07-12 00:41:43 +0900317 EXPECT_TRUE(base::WaitForSingleProcess(
318 server_process, base::TimeDelta::FromSeconds(5)));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900319 base::CloseProcessHandle(server_process);
320}
nsylvain@chromium.org675aad32011-09-21 05:59:01 +0900321#endif
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900322
323// This test uses a payload that has too many arguments, but so the payload
324// size is big enough so the unpacking routine does not generate an error as
325// in the case of MsgBadPayloadShort test.
326// This test does not pinpoint a flaw (per se) as by design we don't carry
327// type information on the IPC message.
328TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
329 FuzzerClientListener listener;
330 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER,
331 &listener);
332 base::ProcessHandle server_process = SpawnChild(FUZZER_SERVER, &chan);
333 ASSERT_TRUE(server_process);
tedvessenes@gmail.com30dbbaa2012-01-13 09:11:01 +0900334 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900335 ASSERT_TRUE(chan.Connect());
336 listener.Init(&chan);
337
338 IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
339 IPC::Message::PRIORITY_NORMAL);
340 msg->WriteWString(L"d");
341 msg->WriteInt(0);
342 msg->WriteInt(0x65); // Extra argument.
343
344 chan.Send(msg);
345 EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID));
346
347 // Now send a well formed message to make sure the receiver wasn't
348 // thrown out of sync by the extra argument.
349 msg = new MsgClassIS(3, L"expect three");
350 chan.Send(msg);
351 EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
352
tedvessenes@gmail.com5966b642012-07-12 00:41:43 +0900353 EXPECT_TRUE(base::WaitForSingleProcess(
354 server_process, base::TimeDelta::FromSeconds(5)));
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900355 base::CloseProcessHandle(server_process);
356}
357
358// This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros.
359class ServerMacroExTest {
360 public:
361 ServerMacroExTest() : unhandled_msgs_(0) {
362 }
jrg@chromium.org2eb192e2011-11-04 09:14:16 +0900363
ziadh@chromium.org7ebaeea2010-08-03 01:34:16 +0900364 virtual ~ServerMacroExTest() {
365 }
jrg@chromium.org2eb192e2011-11-04 09:14:16 +0900366
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900367 virtual bool OnMessageReceived(const IPC::Message& msg) {
368 bool msg_is_ok = false;
369 IPC_BEGIN_MESSAGE_MAP_EX(ServerMacroExTest, msg, msg_is_ok)
370 IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
371 IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
372 IPC_MESSAGE_UNHANDLED(++unhandled_msgs_)
373 IPC_END_MESSAGE_MAP_EX()
374 return msg_is_ok;
375 }
376
377 int unhandled_msgs() const {
378 return unhandled_msgs_;
379 }
380
381 private:
382 void OnMsgClassISMessage(int value, const std::wstring& text) {
383 }
384 void OnMsgClassSIMessage(const std::wstring& text, int value) {
385 }
386
387 int unhandled_msgs_;
jrg@chromium.org2eb192e2011-11-04 09:14:16 +0900388
389 DISALLOW_COPY_AND_ASSIGN(ServerMacroExTest);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900390};
391
392TEST_F(IPCFuzzingTest, MsgMapExMacro) {
393 IPC::Message* msg = NULL;
394 ServerMacroExTest server;
395
396 // Test the regular messages.
397 msg = new MsgClassIS(3, L"text3");
398 EXPECT_TRUE(server.OnMessageReceived(*msg));
399 delete msg;
400 msg = new MsgClassSI(L"text2", 2);
401 EXPECT_TRUE(server.OnMessageReceived(*msg));
402 delete msg;
403
nsylvain@chromium.org675aad32011-09-21 05:59:01 +0900404#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900405 // Test a bad message.
406 msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
407 IPC::Message::PRIORITY_NORMAL);
408 msg->WriteInt(2);
409 EXPECT_FALSE(server.OnMessageReceived(*msg));
410 delete msg;
411
412 msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
413 IPC::Message::PRIORITY_NORMAL);
414 msg->WriteInt(0x64);
415 msg->WriteInt(0x32);
416 EXPECT_FALSE(server.OnMessageReceived(*msg));
417 delete msg;
418
419 EXPECT_EQ(0, server.unhandled_msgs());
420#endif
421}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900422
423} // namespace