ipc_fuzzing_tests.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright (c) 2012 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. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <limits>
  7. #include <memory>
  8. #include <sstream>
  9. #include <string>
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/run_loop.h"
  12. #include "base/strings/utf_string_conversions.h"
  13. #include "base/threading/platform_thread.h"
  14. #include "build/build_config.h"
  15. #include "ipc/ipc_test_base.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. // IPC messages for testing ----------------------------------------------------
  18. #define IPC_MESSAGE_IMPL
  19. #include "ipc/ipc_message_macros.h"
  20. #include "ipc/ipc_message_start.h"
  21. #define IPC_MESSAGE_START TestMsgStart
  22. // Generic message class that is an int followed by a string16.
  23. IPC_MESSAGE_CONTROL2(MsgClassIS, int, std::u16string)
  24. // Generic message class that is a string16 followed by an int.
  25. IPC_MESSAGE_CONTROL2(MsgClassSI, std::u16string, int)
  26. // Message to create a mutex in the IPC server, using the received name.
  27. IPC_MESSAGE_CONTROL2(MsgDoMutex, std::u16string, int)
  28. // Used to generate an ID for a message that should not exist.
  29. IPC_MESSAGE_CONTROL0(MsgUnhandled)
  30. // -----------------------------------------------------------------------------
  31. namespace {
  32. TEST(IPCMessageIntegrity, ReadBeyondBufferStr) {
  33. // This was BUG 984408.
  34. uint32_t v1 = std::numeric_limits<uint32_t>::max() - 1;
  35. int v2 = 666;
  36. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  37. m.WriteInt(v1);
  38. m.WriteInt(v2);
  39. base::PickleIterator iter(m);
  40. std::string vs;
  41. EXPECT_FALSE(iter.ReadString(&vs));
  42. }
  43. TEST(IPCMessageIntegrity, ReadBeyondBufferStr16) {
  44. // This was BUG 984408.
  45. uint32_t v1 = std::numeric_limits<uint32_t>::max() - 1;
  46. int v2 = 777;
  47. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  48. m.WriteInt(v1);
  49. m.WriteInt(v2);
  50. base::PickleIterator iter(m);
  51. std::u16string vs;
  52. EXPECT_FALSE(iter.ReadString16(&vs));
  53. }
  54. TEST(IPCMessageIntegrity, ReadBytesBadIterator) {
  55. // This was BUG 1035467.
  56. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  57. m.WriteInt(1);
  58. m.WriteInt(2);
  59. base::PickleIterator iter(m);
  60. const char* data = nullptr;
  61. EXPECT_TRUE(iter.ReadBytes(&data, sizeof(int)));
  62. }
  63. TEST(IPCMessageIntegrity, ReadVectorNegativeSize) {
  64. // A slight variation of BUG 984408. Note that the pickling of vector<char>
  65. // has a specialized template which is not vulnerable to this bug. So here
  66. // try to hit the non-specialized case vector<P>.
  67. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  68. m.WriteInt(-1); // This is the count of elements.
  69. m.WriteInt(1);
  70. m.WriteInt(2);
  71. m.WriteInt(3);
  72. std::vector<double> vec;
  73. base::PickleIterator iter(m);
  74. EXPECT_FALSE(ReadParam(&m, &iter, &vec));
  75. }
  76. #if BUILDFLAG(IS_ANDROID)
  77. #define MAYBE_ReadVectorTooLarge1 DISABLED_ReadVectorTooLarge1
  78. #else
  79. #define MAYBE_ReadVectorTooLarge1 ReadVectorTooLarge1
  80. #endif
  81. TEST(IPCMessageIntegrity, MAYBE_ReadVectorTooLarge1) {
  82. // This was BUG 1006367. This is the large but positive length case. Again
  83. // we try to hit the non-specialized case vector<P>.
  84. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  85. m.WriteInt(0x21000003); // This is the count of elements.
  86. m.WriteInt64(1);
  87. m.WriteInt64(2);
  88. std::vector<int64_t> vec;
  89. base::PickleIterator iter(m);
  90. EXPECT_FALSE(ReadParam(&m, &iter, &vec));
  91. }
  92. TEST(IPCMessageIntegrity, ReadVectorTooLarge2) {
  93. // This was BUG 1006367. This is the large but positive with an additional
  94. // integer overflow when computing the actual byte size. Again we try to hit
  95. // the non-specialized case vector<P>.
  96. IPC::Message m(0, 1, IPC::Message::PRIORITY_NORMAL);
  97. m.WriteInt(0x71000000); // This is the count of elements.
  98. m.WriteInt64(1);
  99. m.WriteInt64(2);
  100. std::vector<int64_t> vec;
  101. base::PickleIterator iter(m);
  102. EXPECT_FALSE(ReadParam(&m, &iter, &vec));
  103. }
  104. // This test needs ~20 seconds in Debug mode, or ~4 seconds in Release mode.
  105. // See http://crbug.com/741866 for details.
  106. TEST(IPCMessageIntegrity, DISABLED_ReadVectorTooLarge3) {
  107. base::Pickle pickle;
  108. IPC::WriteParam(&pickle, 256 * 1024 * 1024);
  109. IPC::WriteParam(&pickle, 0);
  110. IPC::WriteParam(&pickle, 1);
  111. IPC::WriteParam(&pickle, 2);
  112. base::PickleIterator iter(pickle);
  113. std::vector<int> vec;
  114. EXPECT_FALSE(IPC::ReadParam(&pickle, &iter, &vec));
  115. }
  116. class SimpleListener : public IPC::Listener {
  117. public:
  118. SimpleListener() : other_(nullptr) {}
  119. void Init(IPC::Sender* s) {
  120. other_ = s;
  121. }
  122. protected:
  123. raw_ptr<IPC::Sender> other_;
  124. };
  125. enum {
  126. FUZZER_ROUTING_ID = 5
  127. };
  128. // The fuzzer server class. It runs in a child process and expects
  129. // only two IPC calls; after that it exits the message loop which
  130. // terminates the child process.
  131. class FuzzerServerListener : public SimpleListener {
  132. public:
  133. FuzzerServerListener() : message_count_(2), pending_messages_(0) {
  134. }
  135. bool OnMessageReceived(const IPC::Message& msg) override {
  136. if (msg.routing_id() == MSG_ROUTING_CONTROL) {
  137. ++pending_messages_;
  138. IPC_BEGIN_MESSAGE_MAP(FuzzerServerListener, msg)
  139. IPC_MESSAGE_HANDLER(MsgClassIS, OnMsgClassISMessage)
  140. IPC_MESSAGE_HANDLER(MsgClassSI, OnMsgClassSIMessage)
  141. IPC_END_MESSAGE_MAP()
  142. if (pending_messages_) {
  143. // Probably a problem de-serializing the message.
  144. ReplyMsgNotHandled(msg.type());
  145. }
  146. }
  147. return true;
  148. }
  149. private:
  150. void OnMsgClassISMessage(int value, const std::u16string& text) {
  151. UseData(MsgClassIS::ID, value, text);
  152. RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassIS::ID, value);
  153. Cleanup();
  154. }
  155. void OnMsgClassSIMessage(const std::u16string& text, int value) {
  156. UseData(MsgClassSI::ID, value, text);
  157. RoundtripAckReply(FUZZER_ROUTING_ID, MsgClassSI::ID, value);
  158. Cleanup();
  159. }
  160. bool RoundtripAckReply(int routing, uint32_t type_id, int reply) {
  161. IPC::Message* message = new IPC::Message(routing, type_id,
  162. IPC::Message::PRIORITY_NORMAL);
  163. message->WriteInt(reply + 1);
  164. message->WriteInt(reply);
  165. return other_->Send(message);
  166. }
  167. void Cleanup() {
  168. --message_count_;
  169. --pending_messages_;
  170. if (0 == message_count_)
  171. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  172. }
  173. void ReplyMsgNotHandled(uint32_t type_id) {
  174. RoundtripAckReply(FUZZER_ROUTING_ID, MsgUnhandled::ID, type_id);
  175. Cleanup();
  176. }
  177. void UseData(int caller, int value, const std::u16string& text) {
  178. std::ostringstream os;
  179. os << "IPC fuzzer:" << caller << " [" << value << " "
  180. << base::UTF16ToUTF8(text) << "]\n";
  181. std::string output = os.str();
  182. LOG(WARNING) << output;
  183. }
  184. int message_count_;
  185. int pending_messages_;
  186. };
  187. class FuzzerClientListener : public SimpleListener {
  188. public:
  189. FuzzerClientListener() : last_msg_(nullptr) {}
  190. bool OnMessageReceived(const IPC::Message& msg) override {
  191. last_msg_ = new IPC::Message(msg);
  192. base::RunLoop::QuitCurrentWhenIdleDeprecated();
  193. return true;
  194. }
  195. bool ExpectMessage(int value, uint32_t type_id) {
  196. if (!MsgHandlerInternal(type_id))
  197. return false;
  198. int msg_value1 = 0;
  199. int msg_value2 = 0;
  200. base::PickleIterator iter(*last_msg_);
  201. if (!iter.ReadInt(&msg_value1))
  202. return false;
  203. if (!iter.ReadInt(&msg_value2))
  204. return false;
  205. if ((msg_value2 + 1) != msg_value1)
  206. return false;
  207. if (msg_value2 != value)
  208. return false;
  209. delete last_msg_;
  210. last_msg_ = nullptr;
  211. return true;
  212. }
  213. bool ExpectMsgNotHandled(uint32_t type_id) {
  214. return ExpectMessage(type_id, MsgUnhandled::ID);
  215. }
  216. private:
  217. bool MsgHandlerInternal(uint32_t type_id) {
  218. base::RunLoop().Run();
  219. if (!last_msg_)
  220. return false;
  221. if (FUZZER_ROUTING_ID != last_msg_->routing_id())
  222. return false;
  223. return (type_id == last_msg_->type());
  224. }
  225. raw_ptr<IPC::Message> last_msg_;
  226. };
  227. // Runs the fuzzing server child mode. Returns when the preset number of
  228. // messages have been received.
  229. DEFINE_IPC_CHANNEL_MOJO_TEST_CLIENT(FuzzServerClient) {
  230. FuzzerServerListener listener;
  231. Connect(&listener);
  232. listener.Init(channel());
  233. base::RunLoop().Run();
  234. Close();
  235. }
  236. using IPCFuzzingTest = IPCChannelMojoTestBase;
  237. // This test makes sure that the FuzzerClientListener and FuzzerServerListener
  238. // are working properly by generating two well formed IPC calls.
  239. TEST_F(IPCFuzzingTest, SanityTest) {
  240. Init("FuzzServerClient");
  241. FuzzerClientListener listener;
  242. CreateChannel(&listener);
  243. listener.Init(channel());
  244. ASSERT_TRUE(ConnectChannel());
  245. IPC::Message* msg = nullptr;
  246. int value = 43;
  247. msg = new MsgClassIS(value, u"expect 43");
  248. sender()->Send(msg);
  249. EXPECT_TRUE(listener.ExpectMessage(value, MsgClassIS::ID));
  250. msg = new MsgClassSI(u"expect 44", ++value);
  251. sender()->Send(msg);
  252. EXPECT_TRUE(listener.ExpectMessage(value, MsgClassSI::ID));
  253. EXPECT_TRUE(WaitForClientShutdown());
  254. DestroyChannel();
  255. }
  256. // This test uses a payload that is smaller than expected. This generates an
  257. // error while unpacking the IPC buffer. Right after we generate another valid
  258. // IPC to make sure framing is working properly.
  259. TEST_F(IPCFuzzingTest, MsgBadPayloadShort) {
  260. Init("FuzzServerClient");
  261. FuzzerClientListener listener;
  262. CreateChannel(&listener);
  263. listener.Init(channel());
  264. ASSERT_TRUE(ConnectChannel());
  265. IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassIS::ID,
  266. IPC::Message::PRIORITY_NORMAL);
  267. msg->WriteInt(666);
  268. sender()->Send(msg);
  269. EXPECT_TRUE(listener.ExpectMsgNotHandled(MsgClassIS::ID));
  270. msg = new MsgClassSI(u"expect one", 1);
  271. sender()->Send(msg);
  272. EXPECT_TRUE(listener.ExpectMessage(1, MsgClassSI::ID));
  273. EXPECT_TRUE(WaitForClientShutdown());
  274. DestroyChannel();
  275. }
  276. // This test uses a payload that has too many arguments, but so the payload size
  277. // is big enough so the unpacking routine does not generate an error as in the
  278. // case of MsgBadPayloadShort test. This test does not pinpoint a flaw (per se)
  279. // as by design we don't carry type information on the IPC message.
  280. TEST_F(IPCFuzzingTest, MsgBadPayloadArgs) {
  281. Init("FuzzServerClient");
  282. FuzzerClientListener listener;
  283. CreateChannel(&listener);
  284. listener.Init(channel());
  285. ASSERT_TRUE(ConnectChannel());
  286. IPC::Message* msg = new IPC::Message(MSG_ROUTING_CONTROL, MsgClassSI::ID,
  287. IPC::Message::PRIORITY_NORMAL);
  288. msg->WriteString16(u"d");
  289. msg->WriteInt(0);
  290. msg->WriteInt(0x65); // Extra argument.
  291. sender()->Send(msg);
  292. EXPECT_TRUE(listener.ExpectMessage(0, MsgClassSI::ID));
  293. // Now send a well formed message to make sure the receiver wasn't
  294. // thrown out of sync by the extra argument.
  295. msg = new MsgClassIS(3, u"expect three");
  296. sender()->Send(msg);
  297. EXPECT_TRUE(listener.ExpectMessage(3, MsgClassIS::ID));
  298. EXPECT_TRUE(WaitForClientShutdown());
  299. DestroyChannel();
  300. }
  301. } // namespace