blob: 8d2aebb7a5e553075b8bf448055d15f8f5570fbd [file] [log] [blame]
initial.commit09911bf2008-07-26 23:55:291// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include <windows.h>
31#include <stdio.h>
32#include <iostream>
33#include <string>
34#include <sstream>
35
36#include "chrome/common/ipc_tests.h"
37
38#include "chrome/common/ipc_channel.h"
39#include "chrome/common/ipc_channel_proxy.h"
40#include "chrome/common/ipc_message_utils.h"
41#include "testing/gtest/include/gtest/gtest.h"
42
43TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
44 //This was BUG 984408.
45 uint32 v1 = kuint32max - 1;
46 int v2 = 666;
47 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
48 EXPECT_TRUE(m.WriteInt(v1));
49 EXPECT_TRUE(m.WriteInt(v2));
50
51 void* iter = NULL;
52 std::string vs;
53 EXPECT_FALSE(m.ReadString(&iter, &vs));
54}
55
56TEST(IPCMessageIntegrity, ReadBeyondBufferWStr) {
57 //This was BUG 984408.
58 uint32 v1 = kuint32max - 1;
59 int v2 = 777;
60 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
61 EXPECT_TRUE(m.WriteInt(v1));
62 EXPECT_TRUE(m.WriteInt(v2));
63
64 void* iter = NULL;
65 std::wstring vs;
66 EXPECT_FALSE(m.ReadWString(&iter, &vs));
67}
68
69TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
70 // This was BUG 1035467.
71 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
72 EXPECT_TRUE(m.WriteInt(1));
73 EXPECT_TRUE(m.WriteInt(2));
74
75 void* iter = NULL;
76 const char* data = NULL;
77 EXPECT_FALSE(m.ReadBytes(&iter, &data, sizeof(int)));
78}
79
80TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
81 // A slight variation of BUG 984408. Note that the pickling of vector<char>
82 // has a specialized template which is not vulnerable to this bug. So here
83 // try to hit the non-specialized case vector<P>.
84 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
85 EXPECT_TRUE(m.WriteInt(-1)); // This is the count of elements.
86 EXPECT_TRUE(m.WriteInt(1));
87 EXPECT_TRUE(m.WriteInt(2));
88 EXPECT_TRUE(m.WriteInt(3));
89
90 std::vector<double> vec;
91 void* iter = 0;
92 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
93}
94
95TEST(IPCMessageIntegrity, ReadVectorTooLarge1) {
96 // This was BUG 1006367. This is the large but positive length case. Again
97 // we try to hit the non-specialized case vector<P>.
98 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
99 EXPECT_TRUE(m.WriteInt(0x21000003)); // This is the count of elements.
100 EXPECT_TRUE(m.WriteInt64(1));
101 EXPECT_TRUE(m.WriteInt64(2));
102
103 std::vector<int64> vec;
104 void* iter = 0;
105 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
106}
107
108TEST(IPCMessageIntegrity, ReadVectorTooLarge2) {
109 // This was BUG 1006367. This is the large but positive with an additional
110 // integer overflow when computing the actual byte size. Again we try to hit
111 // the non-specialized case vector<P>.
112 IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
113 EXPECT_TRUE(m.WriteInt(0x71000000)); // This is the count of elements.
114 EXPECT_TRUE(m.WriteInt64(1));
115 EXPECT_TRUE(m.WriteInt64(2));
116
117 std::vector<int64> vec;
118 void* iter = 0;
119 EXPECT_FALSE(ReadParam(&m, &iter, &vec));
120}
121
122// Typically the ipc_message_macros files is included twice but here we only
123// include it once in 'enum mode' because we want more control of the class
124// definitions.
125#define IPC_MESSAGE_MACROS_ENUMS
126#include "chrome/common/ipc_message_macros.h"
127
128enum IPCMessageIds {
129 UNUSED_IPC_TYPE,
130 SERVER_FIRST_IPC_TYPE, // 1st Test message tag.
131 SERVER_SECOND_IPC_TYPE, // 2nd Test message tag.
132 SERVER_THIRD_IPC_TYPE, // 3rd Test message tag.
133 CLIENT_MALFORMED_IPC, // Sent to client if server detects bad message.
134 CLIENT_UNHANDLED_IPC // Sent to client if server detects unhanded IPC.
135};
136
137// Generic message class that is an int followed by a wstring.
138class MsgClassIS : public IPC::MessageWithTuple< Tuple2<int, std::wstring> > {
139 public:
140 enum { ID = SERVER_FIRST_IPC_TYPE };
141 MsgClassIS(const int& arg1, const std::wstring& arg2)
142 : IPC::MessageWithTuple< Tuple2<int, std::wstring> >(
143 MSG_ROUTING_CONTROL, ID, MakeTuple(arg1, arg2)) {}
144};
145
146// Generic message class that is a wstring followed by an int.
147class MsgClassSI : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > {
148 public:
149 enum { ID = SERVER_SECOND_IPC_TYPE };
150 MsgClassSI(const std::wstring& arg1, const int& arg2)
151 : IPC::MessageWithTuple< Tuple2<std::wstring, int> >(
152 MSG_ROUTING_CONTROL, ID, MakeTuple(arg1, arg2)) {}
153};
154
155// Message to create a mutex in the IPC server, using the received name.
156class MsgDoMutex : public IPC::MessageWithTuple< Tuple2<std::wstring, int> > {
157 public:
158 enum { ID = SERVER_THIRD_IPC_TYPE };
159 MsgDoMutex(const std::wstring& mutex_name, const int& unused)
160 : IPC::MessageWithTuple< Tuple2<std::wstring, int> >(
161 MSG_ROUTING_CONTROL, ID, MakeTuple(mutex_name, unused)) {}
162};
163
164class SimpleListener : public IPC::Channel::Listener {
165 public:
166 SimpleListener() : other_(NULL) {
167 }
168 void Init(IPC::Message::Sender* s) {
169 other_ = s;
170 }
171 protected:
172 IPC::Message::Sender* other_;
173};
174
175enum {
176 FUZZER_ROUTING_ID = 5
177};
178
179// The fuzzer server class. It runs in a child process and expects
180// only two IPC calls; after that it exits the message loop which
181// terminates the child process.
182class FuzzerServerListener : public SimpleListener {
183 public:
184 FuzzerServerListener() : message_count_(2), pending_messages_(0) {
185 }
186 virtual void OnMessageReceived(const IPC::Message& msg) {
187 if (msg.routing_id() == MSG_ROUTING_CONTROL) {
188 ++pending_messages_;
189 IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg)
190 IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
191 IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
192 IPC_END_MESSAGE_MAP()
193 if (pending_messages_) {
194 // Probably a problem de-serializing the message.
195 ReplyMsgNotHandled(msg.type());
196 }
197 }
198 }
199
200 private:
201 void OnMsgClassISMessage(int value, const std::wstring& text) {
202 UseData(MsgClassIS::ID, value, text);
203 RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
204 Cleanup();
205 }
206
207 void OnMsgClassSIMessage(const std::wstring& text, int value) {
208 UseData(MsgClassSI::ID, value, text);
209 RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
210 Cleanup();
211 }
212
213 bool RoundtripAckReply(int routing, int type_id, int reply) {
214 IPC::Message* message = new IPC::Message(routing, type_id,
215 IPC::Message::PRIORITY_NORMAL);
216 message->WriteInt(reply + 1);
217 message->WriteInt(reply);
218 return other_->Send(message);
219 }
220
221 void Cleanup() {
222 --message_count_;
223 --pending_messages_;
224 if (0 == message_count_)
225 MessageLoop::current()->Quit();
226 }
227
228 void ReplyMsgNotHandled(int type_id) {
229 RoundtripAckReply(FUZZER_ROUTING_ID, CLIENT_UNHANDLED_IPC, type_id);
230 Cleanup();
231 }
232
233 void UseData(int caller, int value, const std::wstring& text) {
234 std::wostringstream wos;
235 wos << L"IPC fuzzer:" << caller << " [" << value << L" " << text << L"]\n";
236 std::wstring output = wos.str();
237 ::OutputDebugStringW(output.c_str());
238 };
239
240 int message_count_;
241 int pending_messages_;
242};
243
244class FuzzerClientListener : public SimpleListener {
245 public:
246 FuzzerClientListener() : last_msg_(NULL) {
247 }
248
249 virtual void OnMessageReceived(const IPC::Message& msg) {
250 last_msg_ = new IPC::Message(msg);
251 MessageLoop::current()->Quit();
252 }
253
254 bool ExpectMessage(int value, int type_id) {
255 if (!MsgHandlerInternal(type_id))
256 return false;
257 int msg_value1 = 0;
258 int msg_value2 = 0;
259 void* iter = NULL;
260 if (!last_msg_->ReadInt(&iter, &msg_value1))
261 return false;
262 if (!last_msg_->ReadInt(&iter, &msg_value2))
263 return false;
264 if ((msg_value2 + 1) != msg_value1)
265 return false;
266 if (msg_value2 != value)
267 return false;
268
269 delete last_msg_;
270 last_msg_ = NULL;
271 return true;
272 }
273
274 bool ExpectMsgNotHandled(int type_id) {
275 return ExpectMessage(type_id, CLIENT_UNHANDLED_IPC);
276 }
277
278 private:
279 bool MsgHandlerInternal(int type_id) {
280 MessageLoop::current()->Run();
281 if (NULL == last_msg_)
282 return false;
283 if (FUZZER_ROUTING_ID != last_msg_->routing_id())
284 return false;
285 return (type_id == last_msg_->type());
286 };
287
288 IPC::Message* last_msg_;
289};
290
291bool RunFuzzServer() {
292 FuzzerServerListener listener;
293 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_SERVER, &listener);
294 chan.Connect();
295 listener.Init(&chan);
296 MessageLoop::current()->Run();
297 return true;
298}
299
300// This test makes sure that the FuzzerClientListener and FuzzerServerListener
301// are working properly by generating two well formed IPC calls.
302TEST(IPCFuzzingTest, SanityTest) {
303 HANDLE server_process = SpawnChild(FUZZER_SERVER);
304 ASSERT_TRUE(server_process);
305 ::Sleep(1000);
306 FuzzerClientListener listener;
307 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT,
308 &listener);
309 ASSERT_TRUE(chan.Connect());
310 listener.Init(&chan);
311
312 IPC::Message* msg = NULL;
313 int value = 43;
314 msg = new MsgClassIS(value, L"expect 43");
315 chan.Send(msg);
316 EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
317
318 msg = new MsgClassSI(L"expect 44", ++value);
319 chan.Send(msg);
320 EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
321
322 ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000));
323}
324
325// This test uses a payload that is smaller than expected.
326// This generates an error while unpacking the IPC buffer which in
327// In debug this triggers an assertion and in release it is ignored(!!). Right
328// after we generate another valid IPC to make sure framing is working
329// properly.
330#ifdef NDEBUG
331TEST(IPCFuzzingTest, MsgBadPayloadShort) {
332 HANDLE server_process = SpawnChild(FUZZER_SERVER);
333 ASSERT_TRUE(server_process);
334 ::Sleep(1000);
335 FuzzerClientListener listener;
336 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT,
337 &listener);
338 ASSERT_TRUE(chan.Connect());
339 listener.Init(&chan);
340
341 IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
342 IPC::Message::PRIORITY_NORMAL);
343 msg->WriteInt(666);
344 chan.Send(msg);
345 EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
346
347 msg = new MsgClassSI(L"expect one", 1);
348 chan.Send(msg);
349 EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
350
351 ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000));
352}
353#endif // NDEBUG
354
355// This test uses a payload that has the wrong arguments, but so the payload
356// size is big enough so the unpacking routine does not generate an error as
357// in the case of MsgBadPayloadShort test.
358// This test does not pinpoint a flaw (per se) as by design we don't carry
359// type information on the IPC message.
360TEST(IPCFuzzingTest, MsgBadPayloadArgs) {
361 HANDLE server_process = SpawnChild(FUZZER_SERVER);
362 ASSERT_TRUE(server_process);
363 ::Sleep(1000);
364 FuzzerClientListener listener;
365 IPC::Channel chan(kFuzzerChannel, IPC::Channel::MODE_CLIENT,
366 &listener);
367 ASSERT_TRUE(chan.Connect());
368 listener.Init(&chan);
369
370 IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
371 IPC::Message::PRIORITY_NORMAL);
372 msg->WriteInt(2);
373 msg->WriteInt(0x64);
374 msg->WriteInt(0);
375 msg->WriteInt(0x65);
376 chan.Send(msg);
377 EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID));
378
379 msg = new MsgClassIS(3, L"expect three");
380 chan.Send(msg);
381 EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
382
383 ASSERT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(server_process, 5000));
384}
385
386// This class is for testing the IPC_BEGIN_MESSAGE_MAP_EX macros.
387class ServerMacroExTest {
388 public:
389 ServerMacroExTest() : unhandled_msgs_(0) {
390 }
391 virtual bool OnMessageReceived(const IPC::Message& msg) {
392 bool msg_is_ok = false;
393 IPC_BEGIN_MESSAGE_MAP_EX(ServerMacroExTest, msg, msg_is_ok)
394 IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
395 IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
396 IPC_MESSAGE_UNHANDLED(++unhandled_msgs_)
397 IPC_END_MESSAGE_MAP_EX()
398 return msg_is_ok;
399 }
400
401 int unhandled_msgs() const {
402 return unhandled_msgs_;
403 }
404
405 private:
406 void OnMsgClassISMessage(int value, const std::wstring& text) {
407 }
408 void OnMsgClassSIMessage(const std::wstring& text, int value) {
409 }
410
411 int unhandled_msgs_;
412};
413
414TEST(IPCFuzzingTest, MsgMapExMacro) {
415 IPC::Message* msg = NULL;
416 ServerMacroExTest server;
417
418 // Test the regular messages.
419 msg = new MsgClassIS(3, L"text3");
420 EXPECT_TRUE(server.OnMessageReceived(*msg));
421 delete msg;
422 msg = new MsgClassSI(L"text2", 2);
423 EXPECT_TRUE(server.OnMessageReceived(*msg));
424 delete msg;
425
426#ifdef NDEBUG
427 // Test a bad message.
428 msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
429 IPC::Message::PRIORITY_NORMAL);
430 msg->WriteInt(2);
431 EXPECT_FALSE(server.OnMessageReceived(*msg));
432 delete msg;
433
434 msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
435 IPC::Message::PRIORITY_NORMAL);
436 msg->WriteInt(0x64);
437 msg->WriteInt(0x32);
438 EXPECT_FALSE(server.OnMessageReceived(*msg));
439 delete msg;
440
441 EXPECT_EQ(0, server.unhandled_msgs());
442#endif
443}