1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <procinfo/process_map.h> 18 19 #include <inttypes.h> 20 #include <sys/mman.h> 21 22 #include <string> 23 #include <vector> 24 25 #include <android-base/file.h> 26 #include <android-base/stringprintf.h> 27 28 #include <gtest/gtest.h> 29 30 TEST(process_map, ReadMapFile) { 31 std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps"; 32 std::vector<android::procinfo::MapInfo> maps; 33 ASSERT_TRUE(android::procinfo::ReadMapFile( 34 map_file, [&](const android::procinfo::MapInfo& mapinfo) { maps.emplace_back(mapinfo); })); 35 ASSERT_EQ(2043u, maps.size()); 36 ASSERT_EQ(maps[0].start, 0x12c00000ULL); 37 ASSERT_EQ(maps[0].end, 0x2ac00000ULL); 38 ASSERT_EQ(maps[0].flags, PROT_READ | PROT_WRITE); 39 ASSERT_EQ(maps[0].pgoff, 0ULL); 40 ASSERT_EQ(maps[0].inode, 10267643UL); 41 ASSERT_EQ(maps[0].name, "[anon:dalvik-main space (region space)]"); 42 ASSERT_EQ(maps[876].start, 0x70e6c4f000ULL); 43 ASSERT_EQ(maps[876].end, 0x70e6c6b000ULL); 44 ASSERT_EQ(maps[876].flags, PROT_READ | PROT_EXEC); 45 ASSERT_EQ(maps[876].pgoff, 0ULL); 46 ASSERT_EQ(maps[876].inode, 2407UL); 47 ASSERT_EQ(maps[876].name, "/system/lib64/libutils.so"); 48 ASSERT_EQ(maps[1260].start, 0x70e96fa000ULL); 49 ASSERT_EQ(maps[1260].end, 0x70e96fb000ULL); 50 ASSERT_EQ(maps[1260].flags, PROT_READ); 51 ASSERT_EQ(maps[1260].pgoff, 0ULL); 52 ASSERT_EQ(maps[1260].inode, 10266154UL); 53 ASSERT_EQ(maps[1260].name, 54 "[anon:dalvik-classes.dex extracted in memory from " 55 "/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk]"); 56 } 57 58 TEST(process_map, ReadProcessMaps) { 59 std::vector<android::procinfo::MapInfo> maps; 60 ASSERT_TRUE(android::procinfo::ReadProcessMaps( 61 getpid(), [&](const android::procinfo::MapInfo& mapinfo) { maps.emplace_back(mapinfo); })); 62 ASSERT_GT(maps.size(), 0u); 63 maps.clear(); 64 ASSERT_TRUE(android::procinfo::ReadProcessMaps(getpid(), &maps)); 65 ASSERT_GT(maps.size(), 0u); 66 } 67 68 extern "C" void malloc_disable(); 69 extern "C" void malloc_enable(); 70 71 struct TestMapInfo { 72 TestMapInfo() = default; 73 TestMapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode, 74 const char* new_name, bool isShared) 75 : start(start), end(end), flags(flags), pgoff(pgoff), inode(inode), isShared(isShared) { 76 strcpy(name, new_name); 77 } 78 uint64_t start = 0; 79 uint64_t end = 0; 80 uint16_t flags = 0; 81 uint64_t pgoff = 0; 82 ino_t inode = 0; 83 char name[100] = {}; 84 bool isShared = false; 85 }; 86 87 void VerifyReadMapFileAsyncSafe(const char* maps_data, 88 const std::vector<TestMapInfo>& expected_info) { 89 TemporaryFile tf; 90 ASSERT_TRUE(android::base::WriteStringToFd(maps_data, tf.fd)); 91 92 std::vector<TestMapInfo> saved_info(expected_info.size()); 93 size_t num_maps = 0; 94 95 auto callback = [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode, 96 const char* name, bool shared) { 97 if (num_maps != saved_info.size()) { 98 TestMapInfo& saved = saved_info[num_maps]; 99 saved.start = start; 100 saved.end = end; 101 saved.flags = flags; 102 saved.pgoff = pgoff; 103 saved.inode = inode; 104 strcpy(saved.name, name); 105 saved.isShared = shared; 106 } 107 num_maps++; 108 }; 109 110 std::vector<char> buffer(64 * 1024); 111 112 #if defined(__BIONIC__) 113 // Any allocations will block after this call. 114 malloc_disable(); 115 #endif 116 117 bool parsed = 118 android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer.data(), buffer.size(), callback); 119 120 #if defined(__BIONIC__) 121 malloc_enable(); 122 #endif 123 124 ASSERT_TRUE(parsed) << "Parsing of data failed:\n" << maps_data; 125 ASSERT_EQ(expected_info.size(), num_maps); 126 for (size_t i = 0; i < expected_info.size(); i++) { 127 const TestMapInfo& expected = expected_info[i]; 128 const TestMapInfo& saved = saved_info[i]; 129 EXPECT_EQ(expected.start, saved.start); 130 EXPECT_EQ(expected.end, saved.end); 131 EXPECT_EQ(expected.flags, saved.flags); 132 EXPECT_EQ(expected.pgoff, saved.pgoff); 133 EXPECT_EQ(expected.inode, saved.inode); 134 EXPECT_STREQ(expected.name, saved.name); 135 EXPECT_EQ(expected.isShared, saved.isShared); 136 } 137 } 138 139 TEST(process_map, ReadMapFileAsyncSafe_invalid) { 140 std::vector<TestMapInfo> expected_info; 141 142 VerifyReadMapFileAsyncSafe("12c00000-2ac00000", expected_info); 143 } 144 145 TEST(process_map, ReadMapFileAsyncSafe_single) { 146 std::vector<TestMapInfo> expected_info; 147 expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643, 148 "/lib/fake.so", false); 149 150 VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so", 151 expected_info); 152 } 153 154 TEST(process_map, ReadMapFileAsyncSafe_single_with_newline) { 155 std::vector<TestMapInfo> expected_info; 156 expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643, 157 "/lib/fake.so", false); 158 159 VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so\n", 160 expected_info); 161 } 162 163 TEST(process_map, ReadMapFileAsyncSafe_single_no_library) { 164 std::vector<TestMapInfo> expected_info; 165 expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 0xb00, 101, "", 166 false); 167 168 VerifyReadMapFileAsyncSafe("a0000-c0000 rwxp 00000b00 00:05 101", expected_info); 169 } 170 171 TEST(process_map, ReadMapFileAsyncSafe_multiple) { 172 std::vector<TestMapInfo> expected_info; 173 expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 1, 100, "", 174 false); 175 expected_info.emplace_back(0xd0000, 0xe0000, PROT_READ, 2, 101, "/lib/libsomething1.so", false); 176 expected_info.emplace_back(0xf0000, 0x100000, PROT_WRITE, 3, 102, "/lib/libsomething2.so", false); 177 expected_info.emplace_back(0x110000, 0x120000, PROT_EXEC, 4, 103, "[anon:something or another]", 178 false); 179 expected_info.emplace_back(0x130000, 0x140000, PROT_READ, 5, 104, "/lib/libsomething3.so", true); 180 181 std::string map_data = 182 "0a0000-0c0000 rwxp 00000001 00:05 100\n" 183 "0d0000-0e0000 r--p 00000002 00:05 101 /lib/libsomething1.so\n" 184 "0f0000-100000 -w-p 00000003 00:05 102 /lib/libsomething2.so\n" 185 "110000-120000 --xp 00000004 00:05 103 [anon:something or another]\n" 186 "130000-140000 r--s 00000005 00:05 104 /lib/libsomething3.so\n"; 187 188 VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info); 189 } 190 191 TEST(process_map, ReadMapFileAsyncSafe_multiple_reads) { 192 std::vector<TestMapInfo> expected_info; 193 std::string map_data; 194 uint64_t start = 0xa0000; 195 for (size_t i = 0; i < 10000; i++) { 196 map_data += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r--p %zx 01:20 %zu fake.so\n", 197 start, start + 0x1000, i, 1000 + i); 198 expected_info.emplace_back(start, start + 0x1000, PROT_READ, i, 1000 + i, "fake.so", false); 199 } 200 201 VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info); 202 } 203 204 TEST(process_map, ReadMapFileAsyncSafe_buffer_nullptr) { 205 size_t num_calls = 0; 206 auto callback = [&](const android::procinfo::MapInfo&) { num_calls++; }; 207 208 #if defined(__BIONIC__) 209 // Any allocations will block after this call. 210 malloc_disable(); 211 #endif 212 213 bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", nullptr, 10, callback); 214 215 #if defined(__BIONIC__) 216 malloc_enable(); 217 #endif 218 219 ASSERT_FALSE(parsed); 220 EXPECT_EQ(0UL, num_calls); 221 } 222 223 TEST(process_map, ReadMapFileAsyncSafe_buffer_size_zero) { 224 size_t num_calls = 0; 225 auto callback = [&](const android::procinfo::MapInfo&) { num_calls++; }; 226 227 #if defined(__BIONIC__) 228 // Any allocations will block after this call. 229 malloc_disable(); 230 #endif 231 232 char buffer[10]; 233 bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, 0, callback); 234 235 #if defined(__BIONIC__) 236 malloc_enable(); 237 #endif 238 239 ASSERT_FALSE(parsed); 240 EXPECT_EQ(0UL, num_calls); 241 } 242 243 TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_no_calls) { 244 size_t num_calls = 0; 245 auto callback = [&](const android::procinfo::MapInfo&) { num_calls++; }; 246 247 #if defined(__BIONIC__) 248 // Any allocations will block after this call. 249 malloc_disable(); 250 #endif 251 252 char buffer[10]; 253 bool parsed = 254 android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, sizeof(buffer), callback); 255 256 #if defined(__BIONIC__) 257 malloc_enable(); 258 #endif 259 260 ASSERT_FALSE(parsed); 261 EXPECT_EQ(0UL, num_calls); 262 } 263 264 TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_could_parse) { 265 TemporaryFile tf; 266 ASSERT_TRUE(android::base::WriteStringToFd( 267 "0a0000-0c0000 rwxp 00000001 00:05 100 /fake/lib.so\n", tf.fd)); 268 269 size_t num_calls = 0; 270 auto callback = [&](const android::procinfo::MapInfo&) { num_calls++; }; 271 272 #if defined(__BIONIC__) 273 // Any allocations will block after this call. 274 malloc_disable(); 275 #endif 276 277 char buffer[39]; 278 bool parsed = android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer, sizeof(buffer), callback); 279 280 #if defined(__BIONIC__) 281 malloc_enable(); 282 #endif 283 284 ASSERT_FALSE(parsed); 285 EXPECT_EQ(0UL, num_calls); 286 } 287