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