proc_maps_linux_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright (c) 2013 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 "base/debug/proc_maps_linux.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include "base/files/file_path.h"
  8. #include "base/path_service.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "base/threading/platform_thread.h"
  11. #include "build/build_config.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. namespace base {
  14. namespace debug {
  15. TEST(ProcMapsTest, Empty) {
  16. std::vector<MappedMemoryRegion> regions;
  17. EXPECT_TRUE(ParseProcMaps("", &regions));
  18. EXPECT_EQ(0u, regions.size());
  19. }
  20. TEST(ProcMapsTest, NoSpaces) {
  21. static const char kNoSpaces[] =
  22. "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n";
  23. std::vector<MappedMemoryRegion> regions;
  24. ASSERT_TRUE(ParseProcMaps(kNoSpaces, &regions));
  25. ASSERT_EQ(1u, regions.size());
  26. EXPECT_EQ(0x00400000u, regions[0].start);
  27. EXPECT_EQ(0x0040b000u, regions[0].end);
  28. EXPECT_EQ(0x00002200u, regions[0].offset);
  29. EXPECT_EQ("/bin/cat", regions[0].path);
  30. }
  31. TEST(ProcMapsTest, Spaces) {
  32. static const char kSpaces[] =
  33. "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n";
  34. std::vector<MappedMemoryRegion> regions;
  35. ASSERT_TRUE(ParseProcMaps(kSpaces, &regions));
  36. ASSERT_EQ(1u, regions.size());
  37. EXPECT_EQ(0x00400000u, regions[0].start);
  38. EXPECT_EQ(0x0040b000u, regions[0].end);
  39. EXPECT_EQ(0x00002200u, regions[0].offset);
  40. EXPECT_EQ("/bin/space cat", regions[0].path);
  41. }
  42. TEST(ProcMapsTest, NoNewline) {
  43. static const char kNoSpaces[] =
  44. "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat";
  45. std::vector<MappedMemoryRegion> regions;
  46. ASSERT_FALSE(ParseProcMaps(kNoSpaces, &regions));
  47. }
  48. TEST(ProcMapsTest, NoPath) {
  49. static const char kNoPath[] =
  50. "00400000-0040b000 rw-p 00000000 00:00 0 \n";
  51. std::vector<MappedMemoryRegion> regions;
  52. ASSERT_TRUE(ParseProcMaps(kNoPath, &regions));
  53. ASSERT_EQ(1u, regions.size());
  54. EXPECT_EQ(0x00400000u, regions[0].start);
  55. EXPECT_EQ(0x0040b000u, regions[0].end);
  56. EXPECT_EQ(0x00000000u, regions[0].offset);
  57. EXPECT_EQ("", regions[0].path);
  58. }
  59. TEST(ProcMapsTest, Heap) {
  60. static const char kHeap[] =
  61. "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n";
  62. std::vector<MappedMemoryRegion> regions;
  63. ASSERT_TRUE(ParseProcMaps(kHeap, &regions));
  64. ASSERT_EQ(1u, regions.size());
  65. EXPECT_EQ(0x022ac000u, regions[0].start);
  66. EXPECT_EQ(0x022cd000u, regions[0].end);
  67. EXPECT_EQ(0x00000000u, regions[0].offset);
  68. EXPECT_EQ("[heap]", regions[0].path);
  69. }
  70. #if defined(ARCH_CPU_32_BITS)
  71. TEST(ProcMapsTest, Stack32) {
  72. static const char kStack[] =
  73. "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n";
  74. std::vector<MappedMemoryRegion> regions;
  75. ASSERT_TRUE(ParseProcMaps(kStack, &regions));
  76. ASSERT_EQ(1u, regions.size());
  77. EXPECT_EQ(0xbeb04000u, regions[0].start);
  78. EXPECT_EQ(0xbeb25000u, regions[0].end);
  79. EXPECT_EQ(0x00000000u, regions[0].offset);
  80. EXPECT_EQ("[stack]", regions[0].path);
  81. }
  82. #elif defined(ARCH_CPU_64_BITS)
  83. TEST(ProcMapsTest, Stack64) {
  84. static const char kStack[] =
  85. "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n";
  86. std::vector<MappedMemoryRegion> regions;
  87. ASSERT_TRUE(ParseProcMaps(kStack, &regions));
  88. ASSERT_EQ(1u, regions.size());
  89. EXPECT_EQ(0x7fff69c5b000u, regions[0].start);
  90. EXPECT_EQ(0x7fff69c7d000u, regions[0].end);
  91. EXPECT_EQ(0x00000000u, regions[0].offset);
  92. EXPECT_EQ("[stack]", regions[0].path);
  93. }
  94. #endif
  95. TEST(ProcMapsTest, Multiple) {
  96. static const char kMultiple[] =
  97. "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n"
  98. "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n"
  99. "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n";
  100. std::vector<MappedMemoryRegion> regions;
  101. ASSERT_TRUE(ParseProcMaps(kMultiple, &regions));
  102. ASSERT_EQ(3u, regions.size());
  103. EXPECT_EQ(0x00400000u, regions[0].start);
  104. EXPECT_EQ(0x0040b000u, regions[0].end);
  105. EXPECT_EQ(0x00000000u, regions[0].offset);
  106. EXPECT_EQ("/bin/cat", regions[0].path);
  107. EXPECT_EQ(0x0060a000u, regions[1].start);
  108. EXPECT_EQ(0x0060b000u, regions[1].end);
  109. EXPECT_EQ(0x0000a000u, regions[1].offset);
  110. EXPECT_EQ("/bin/cat", regions[1].path);
  111. EXPECT_EQ(0x0060b000u, regions[2].start);
  112. EXPECT_EQ(0x0060c000u, regions[2].end);
  113. EXPECT_EQ(0x0000b000u, regions[2].offset);
  114. EXPECT_EQ("/bin/cat", regions[2].path);
  115. }
  116. TEST(ProcMapsTest, Permissions) {
  117. static struct {
  118. const char* input;
  119. uint8_t permissions;
  120. } kTestCases[] = {
  121. {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
  122. {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
  123. {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n",
  124. MappedMemoryRegion::READ},
  125. {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n",
  126. MappedMemoryRegion::WRITE},
  127. {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n",
  128. MappedMemoryRegion::EXECUTE},
  129. {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n",
  130. MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
  131. MappedMemoryRegion::EXECUTE},
  132. {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n",
  133. MappedMemoryRegion::PRIVATE},
  134. {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n",
  135. MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE},
  136. {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n",
  137. MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE},
  138. {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n",
  139. MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
  140. {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
  141. MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
  142. MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
  143. };
  144. for (size_t i = 0; i < std::size(kTestCases); ++i) {
  145. SCOPED_TRACE(
  146. base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input));
  147. std::vector<MappedMemoryRegion> regions;
  148. EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, &regions));
  149. EXPECT_EQ(1u, regions.size());
  150. if (regions.empty())
  151. continue;
  152. EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions);
  153. }
  154. }
  155. // AddressSanitizer may move local variables to a dedicated "fake stack" which
  156. // is outside the stack region listed in /proc/self/maps. We disable ASan
  157. // instrumentation for this function to force the variable to be local.
  158. //
  159. // Similarly, HWAddressSanitizer may add a tag to all stack pointers which may
  160. // move it outside of the stack regions in /proc/self/maps.
  161. __attribute__((no_sanitize("address", "hwaddress"))) void CheckProcMapsRegions(
  162. const std::vector<MappedMemoryRegion>& regions) {
  163. // We should be able to find both the current executable as well as the stack
  164. // mapped into memory. Use the address of |exe_path| as a way of finding the
  165. // stack.
  166. FilePath exe_path;
  167. EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
  168. uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
  169. bool found_exe = false;
  170. bool found_stack = false;
  171. bool found_address = false;
  172. for (const auto& i : regions) {
  173. if (i.path == exe_path.value()) {
  174. // It's OK to find the executable mapped multiple times as there'll be
  175. // multiple sections (e.g., text, data).
  176. found_exe = true;
  177. }
  178. if (i.path == "[stack]") {
  179. // On Android the test is run on a background thread, since [stack] is for
  180. // the main thread, we cannot test this.
  181. #if !BUILDFLAG(IS_ANDROID)
  182. EXPECT_GE(address, i.start);
  183. EXPECT_LT(address, i.end);
  184. #endif
  185. EXPECT_TRUE(i.permissions & MappedMemoryRegion::READ);
  186. EXPECT_TRUE(i.permissions & MappedMemoryRegion::WRITE);
  187. EXPECT_FALSE(i.permissions & MappedMemoryRegion::EXECUTE);
  188. EXPECT_TRUE(i.permissions & MappedMemoryRegion::PRIVATE);
  189. EXPECT_FALSE(found_stack) << "Found duplicate stacks";
  190. found_stack = true;
  191. }
  192. if (address >= i.start && address < i.end) {
  193. EXPECT_FALSE(found_address) << "Found same address in multiple regions";
  194. found_address = true;
  195. }
  196. }
  197. EXPECT_TRUE(found_exe);
  198. EXPECT_TRUE(found_stack);
  199. EXPECT_TRUE(found_address);
  200. }
  201. TEST(ProcMapsTest, ReadProcMaps) {
  202. std::string proc_maps;
  203. ASSERT_TRUE(ReadProcMaps(&proc_maps));
  204. std::vector<MappedMemoryRegion> regions;
  205. ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
  206. ASSERT_FALSE(regions.empty());
  207. CheckProcMapsRegions(regions);
  208. }
  209. TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
  210. std::string old_string("I forgot to clear the string");
  211. std::string proc_maps(old_string);
  212. ASSERT_TRUE(ReadProcMaps(&proc_maps));
  213. EXPECT_EQ(std::string::npos, proc_maps.find(old_string));
  214. }
  215. TEST(ProcMapsTest, MissingFields) {
  216. static const char* const kTestCases[] = {
  217. "00400000\n", // Missing end + beyond.
  218. "00400000-0040b000\n", // Missing perms + beyond.
  219. "00400000-0040b000 r-xp\n", // Missing offset + beyond.
  220. "00400000-0040b000 r-xp 00000000\n", // Missing device + beyond.
  221. "00400000-0040b000 r-xp 00000000 fc:00\n", // Missing inode + beyond.
  222. "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n", // Missing perms.
  223. "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n", // Missing offset.
  224. "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n", // Missing inode.
  225. "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing end.
  226. "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n", // Missing start.
  227. "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n", // Missing device.
  228. };
  229. for (size_t i = 0; i < std::size(kTestCases); ++i) {
  230. SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
  231. std::vector<MappedMemoryRegion> regions;
  232. EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
  233. }
  234. }
  235. TEST(ProcMapsTest, InvalidInput) {
  236. static const char* const kTestCases[] = {
  237. "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
  238. "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n",
  239. "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n",
  240. "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n",
  241. "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n",
  242. "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n",
  243. };
  244. for (size_t i = 0; i < std::size(kTestCases); ++i) {
  245. SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
  246. std::vector<MappedMemoryRegion> regions;
  247. EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
  248. }
  249. }
  250. TEST(ProcMapsTest, ParseProcMapsEmptyString) {
  251. std::vector<MappedMemoryRegion> regions;
  252. EXPECT_TRUE(ParseProcMaps("", &regions));
  253. EXPECT_EQ(0ULL, regions.size());
  254. }
  255. // Testing a couple of remotely possible weird things in the input:
  256. // - Line ending with \r\n or \n\r.
  257. // - File name contains quotes.
  258. // - File name has whitespaces.
  259. TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) {
  260. std::vector<MappedMemoryRegion> regions;
  261. const std::string kContents =
  262. "00400000-0040b000 r-xp 00000000 fc:00 2106562 "
  263. " /bin/cat\r\n"
  264. "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 "
  265. " /lib/x86_64-linux-gnu/libc-2.15.so\n\r"
  266. "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 "
  267. " /lib/x86_64-linux-gnu/ld-2.15.so\n"
  268. "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 "
  269. " \"vd so\"\n"
  270. "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
  271. " [vsys call]\n";
  272. EXPECT_TRUE(ParseProcMaps(kContents, &regions));
  273. EXPECT_EQ(5ULL, regions.size());
  274. EXPECT_EQ("/bin/cat", regions[0].path);
  275. EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path);
  276. EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path);
  277. EXPECT_EQ("\"vd so\"", regions[3].path);
  278. EXPECT_EQ("[vsys call]", regions[4].path);
  279. }
  280. } // namespace debug
  281. } // namespace base