1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <dlfcn.h> 17 #include <fcntl.h> 18 #include <hwext/gtest-ext.h> 19 #include <hwext/gtest-tag.h> 20 #include <vector> 21 #include <sys/syscall.h> 22 23 #include "buffer_splitter.h" 24 #include "logging.h" 25 26 #pragma clang optimize off 27 28 using namespace testing::ext; 29 30 namespace { 31 const int DEFAULT_MALLOC_SIZE = 10; 32 const int DEFAULT_CALLOC_SIZE = 100; 33 const int DEFAULT_REALLOC_SIZE = 1000; 34 const int DATA_SIZE = 50; 35 const int SLEEP_TIME = 5; 36 37 const std::string DEFAULT_NATIVE_DAEMON_PATH("/system/bin/native_daemon"); 38 std::string DEFAULT_PATH("/data/local/tmp/"); 39 const int g_shareMemorySize = 1000 * 4096; 40 const int g_bufferSize = 100 * 1024; 41 const int g_defaultDepth = 30; 42 const int g_callocDepth = 18; 43 const int g_mallocVecSize = 5; 44 const int g_freeVecSize = 4; 45 const int g_mallocGetDataSize = 3; 46 const int g_freeGetDataSize = 2; 47 std::unique_ptr<uint8_t[]> g_buffer = std::make_unique<uint8_t[]>(g_bufferSize); 48 49 using StaticSpace = struct { 50 int data[DATA_SIZE]; 51 } ; 52 53 class CheckHookDataTest : public ::testing::Test { 54 public: SetUpTestCase()55 static void SetUpTestCase() {} TearDownTestCase()56 static void TearDownTestCase() {} 57 StartDaemonProcessArgs(int pid,std::string outFile)58 void StartDaemonProcessArgs(int pid, std::string outFile) 59 { 60 int processNum = fork(); 61 if (processNum == 0) { 62 // start running native_daemon -o -s -p 63 execl(DEFAULT_NATIVE_DAEMON_PATH.c_str(), DEFAULT_NATIVE_DAEMON_PATH.c_str(), "-o", outFile.c_str(), 64 "-s", std::to_string(g_shareMemorySize).c_str(), "-p", std::to_string(pid).c_str(), nullptr); 65 _exit(1); 66 } else { 67 g_daemonPid = processNum; 68 } 69 } 70 StartDaemonProcessArgsDepth(int pid,int setHookDepth,std::string outFile)71 void StartDaemonProcessArgsDepth(int pid, int setHookDepth, std::string outFile) 72 { 73 int processNum = fork(); 74 if (processNum == 0) { 75 // start running native_daemon -o -s -p -d 76 execl(DEFAULT_NATIVE_DAEMON_PATH.c_str(), DEFAULT_NATIVE_DAEMON_PATH.c_str(), "-o", outFile.c_str(), 77 "-s", std::to_string(g_shareMemorySize).c_str(), "-p", std::to_string(pid).c_str(), 78 "-d", std::to_string(setHookDepth).c_str(), nullptr); 79 _exit(1); 80 } else { 81 g_daemonSetDepthPid = processNum; 82 } 83 } 84 StopProcess(int processNum)85 void StopProcess(int processNum) 86 { 87 std::string stopCmd = "kill -9 " + std::to_string(processNum); 88 system(stopCmd.c_str()); 89 } 90 ReadFile(std::string file)91 int32_t ReadFile(std::string file) 92 { 93 int fd = -1; 94 ssize_t bytesRead = 0; 95 char filePath[PATH_MAX + 1] = {0}; 96 97 if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s", file.c_str()) < 0) { 98 const int bufSize = 1024; 99 char buf[bufSize] = { 0 }; 100 strerror_r(errno, buf, bufSize); 101 HILOG_ERROR(LOG_CORE, "snprintf_s(%s) error, errno(%d:%s)", file.c_str(), errno, buf); 102 return -1; 103 } 104 105 char* realPath = realpath(filePath, nullptr); 106 if (realPath == nullptr) { 107 const int bufSize = 1024; 108 char buf[bufSize] = { 0 }; 109 strerror_r(errno, buf, bufSize); 110 HILOG_ERROR(LOG_CORE, "realpath(%s) failed, errno(%d:%s)", file.c_str(), errno, buf); 111 return -1; 112 } 113 114 fd = open(realPath, O_RDONLY | O_CLOEXEC); 115 if (fd == -1) { 116 const int bufSize = 1024; 117 char buf[bufSize] = { 0 }; 118 strerror_r(errno, buf, bufSize); 119 HILOG_ERROR(LOG_CORE, "%s:failed to open(%s), errno(%d:%s)", __func__, realPath, errno, buf); 120 return -1; 121 } 122 if (g_buffer == nullptr) { 123 HILOG_ERROR(LOG_CORE, "%s:empty address, g_buffer is NULL", __func__); 124 close(fd); 125 return -1; 126 } 127 bytesRead = read(fd, g_buffer.get(), g_bufferSize - 1); 128 if (bytesRead <= 0) { 129 close(fd); 130 HILOG_ERROR(LOG_CORE, "%s:failed to read(%s), errno=%d", __func__, realPath, errno); 131 return -1; 132 } 133 close(fd); 134 free(realPath); 135 136 return bytesRead; 137 } 138 DepthFree(int depth,void * p)139 void DepthFree(int depth, void *p) 140 { 141 StaticSpace staticeData; 142 if (depth == 0) { 143 staticeData.data[0] = 1; 144 free(p); 145 return; 146 } 147 return (DepthFree(depth - 1, p)); 148 } 149 DepthMalloc(int depth)150 char *DepthMalloc(int depth) 151 { 152 StaticSpace staticeData; 153 if (depth == 0) { 154 staticeData.data[0] = 1; 155 return (char *)malloc(DEFAULT_MALLOC_SIZE); 156 } 157 return (DepthMalloc(depth - 1)); 158 } 159 ApplyForMalloc(int depth)160 void ApplyForMalloc(int depth) 161 { 162 char *p = DepthMalloc(depth); 163 if (!p) { 164 const int bufSize = 1024; 165 char buf[bufSize] = { 0 }; 166 strerror_r(errno, buf, bufSize); 167 HILOG_ERROR(LOG_CORE, "ApplyForMalloc: malloc failure, errno(%d:%s)", errno, buf); 168 return; 169 } 170 DepthFree(depth, p); 171 } 172 StartMallocProcess(int depth,int & pid)173 void StartMallocProcess(int depth, int& pid) 174 { 175 int processNum = fork(); 176 if (processNum == 0) { 177 while (1) { 178 ApplyForMalloc(depth); 179 sleep(1); 180 } 181 } else { 182 pid = processNum; 183 } 184 } 185 DepthCalloc(int depth,int callocSize)186 char *DepthCalloc(int depth, int callocSize) 187 { 188 StaticSpace staticeData; 189 if (depth == 0) { 190 staticeData.data[0] = 1; 191 return (char *)calloc(sizeof(char), callocSize); 192 } 193 return (DepthCalloc(depth - 1, callocSize)); 194 } 195 ApplyForCalloc(int depth)196 void ApplyForCalloc(int depth) 197 { 198 int callocSize = DEFAULT_CALLOC_SIZE / sizeof(char); 199 char *p = DepthCalloc(depth, callocSize); 200 if (!p) { 201 const int bufSize = 1024; 202 char buf[bufSize] = { 0 }; 203 strerror_r(errno, buf, bufSize); 204 HILOG_ERROR(LOG_CORE, "ApplyForCalloc: calloc failure, errno(%d:%s)", errno, buf); 205 return; 206 } 207 DepthFree(depth, p); 208 } 209 StartCallocProcess(int depth,int & pid)210 void StartCallocProcess(int depth, int& pid) 211 { 212 int processNum = fork(); 213 if (processNum == 0) { 214 while (1) { 215 ApplyForCalloc(depth); 216 sleep(1); 217 } 218 } else { 219 pid = processNum; 220 } 221 } 222 DepthRealloc(int depth,void * p,int reallocSize)223 char *DepthRealloc(int depth, void *p, int reallocSize) 224 { 225 StaticSpace staticeData; 226 if (depth == 0) { 227 staticeData.data[0] = 1; 228 return (char *)realloc(p, reallocSize); 229 } 230 return (DepthRealloc(depth - 1, p, reallocSize)); 231 } 232 ApplyForRealloc(int depth)233 void ApplyForRealloc(int depth) 234 { 235 int reallocSize = DEFAULT_REALLOC_SIZE; 236 char *p = (char *)malloc(DEFAULT_MALLOC_SIZE); 237 if (!p) { 238 const int bufSize = 1024; 239 char buf[bufSize] = { 0 }; 240 strerror_r(errno, buf, bufSize); 241 HILOG_ERROR(LOG_CORE, "ApplyForRealloc: malloc failure, errno(%d:%s)", errno, buf); 242 return; 243 } 244 char *np = DepthRealloc(depth, p, reallocSize); 245 if (!np) { 246 free(p); 247 const int bufSize = 1024; 248 char buf[bufSize] = { 0 }; 249 strerror_r(errno, buf, bufSize); 250 HILOG_ERROR(LOG_CORE, "ApplyForRealloc: realloc failure, errno(%d:%s)", errno, buf); 251 return; 252 } 253 DepthFree(depth, np); 254 } 255 StartReallocProcess(int depth,int & pid)256 void StartReallocProcess(int depth, int& pid) 257 { 258 int processNum = fork(); 259 if (processNum == 0) { 260 while (1) { 261 ApplyForRealloc(depth); 262 sleep(1); 263 } 264 } else { 265 pid = processNum; 266 } 267 } 268 Getdata(BufferSplitter & totalbuffer,std::vector<std::string> & hookVec,char delimiter)269 bool Getdata(BufferSplitter& totalbuffer, std::vector<std::string>& hookVec, char delimiter) 270 { 271 totalbuffer.NextWord(delimiter); 272 if (!totalbuffer.CurWord()) { 273 return false; 274 } 275 std::string curWord = std::string(totalbuffer.CurWord(), totalbuffer.CurWordSize()); 276 hookVec.push_back(curWord); 277 return true; 278 } 279 280 private: 281 int g_daemonPid = -1; 282 int g_daemonSetDepthPid = -1; 283 }; 284 285 /** 286 * @tc.name: native hook 287 * @tc.desc: Test hook malloc normal process. 288 * @tc.type: FUNC 289 */ 290 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0080, Function | MediumTest | Level1) 291 { 292 int setDepth = 100; // 递归深度大于hook默认深度30,测试文本 293 int mallocPid = -1; 294 std::string outFile = DEFAULT_PATH + "hooktest_malloc.txt"; 295 StartMallocProcess(setDepth, mallocPid); 296 sleep(1); 297 StartDaemonProcessArgs(mallocPid, outFile); 298 299 sleep(1); 300 std::string cmd = "kill -36 " + std::to_string(mallocPid); 301 system(cmd.c_str()); 302 303 sleep(SLEEP_TIME); // 等待生成文本 304 StopProcess(mallocPid); 305 StopProcess(g_daemonPid); 306 307 int32_t ret = ReadFile(outFile); 308 ASSERT_NE(ret, -1); 309 310 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 311 std::vector<std::string> hookVec; 312 std::string addr = ""; 313 int depth = 0; 314 int addrPos = 3; 315 bool isFirstHook = true; 316 do { 317 char delimiter = ';'; 318 Getdata(totalbuffer, hookVec, delimiter); 319 320 if (hookVec[0] == "malloc") { 321 for (int i = 0; i < g_mallocGetDataSize; i++) { 322 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 323 } 324 delimiter = '\n'; 325 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 326 ASSERT_EQ(static_cast<int>(hookVec.size()), g_mallocVecSize); 327 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); 328 if (!isFirstHook) { 329 EXPECT_EQ(depth, g_defaultDepth); 330 } 331 332 addr = hookVec[addrPos]; 333 depth = 0; 334 } else if (hookVec[0] == "free") { 335 for (int i = 0; i < g_freeGetDataSize; i++) { 336 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 337 } 338 delimiter = '\n'; 339 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 340 ASSERT_EQ(static_cast<int>(hookVec.size()), g_freeVecSize); 341 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 342 EXPECT_EQ(depth, g_defaultDepth); 343 344 isFirstHook= false; 345 addr = ""; 346 depth = 0; 347 } else { 348 depth++; 349 } 350 351 hookVec.clear(); 352 } while (totalbuffer.NextLine()); 353 } 354 355 /** 356 * @tc.name: native hook 357 * @tc.desc: Test hook calloc normal process. 358 * @tc.type: FUNC 359 */ 360 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0090, Function | MediumTest | Level3) 361 { 362 int setDepth = 1; // 递归深度小于hook深度100,测试文本 363 int setHookDepth = 100; 364 int callocPid = -1; 365 std::string outFile = DEFAULT_PATH + "hooktest_calloc.txt"; 366 StartCallocProcess(setDepth, callocPid); 367 sleep(1); 368 StartDaemonProcessArgsDepth(callocPid, setHookDepth, outFile); 369 370 sleep(1); 371 std::string cmd = "kill -36 " + std::to_string(callocPid); 372 system(cmd.c_str()); 373 374 sleep(SLEEP_TIME); // 等待生成文本 375 StopProcess(callocPid); 376 StopProcess(g_daemonSetDepthPid); 377 378 int32_t ret = ReadFile(outFile); 379 ASSERT_NE(ret, -1); 380 381 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 382 std::vector<std::string> hookVec; 383 std::string addr = ""; 384 int depth = 0; 385 int addrPos = 3; 386 bool isFirstHook = true; 387 do { 388 char delimiter = ';'; 389 Getdata(totalbuffer, hookVec, delimiter); 390 391 if (hookVec[0] == "malloc") { 392 for (int i = 0; i < g_mallocGetDataSize; i++) { 393 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 394 } 395 delimiter = '\n'; 396 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 397 ASSERT_EQ(static_cast<int>(hookVec.size()), g_mallocVecSize); 398 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_CALLOC_SIZE); 399 if (!isFirstHook) { 400 EXPECT_EQ(depth, g_callocDepth - 1); 401 } 402 403 addr = hookVec[addrPos]; 404 depth = 0; 405 } else if (hookVec[0] == "free") { 406 for (int i = 0; i < g_freeGetDataSize; i++) { 407 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 408 } 409 delimiter = '\n'; 410 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 411 ASSERT_EQ(static_cast<int>(hookVec.size()), g_freeVecSize); 412 EXPECT_STREQ(hookVec[addrPos].c_str(), addr.c_str()); 413 EXPECT_EQ(depth, g_callocDepth); 414 415 isFirstHook= false; 416 addr = ""; 417 depth = 0; 418 } else { 419 depth++; 420 } 421 422 hookVec.clear(); 423 } while (totalbuffer.NextLine()); 424 } 425 426 /** 427 * @tc.name: native hook 428 * @tc.desc: Test hook realloc normal process. 429 * @tc.type: FUNC 430 */ 431 HWTEST_F(CheckHookDataTest, DFX_DFR_Hiprofiler_0100, Function | MediumTest | Level3) 432 { 433 int setDepth = 100; // realloc测试文本 434 int reallocPid = -1; 435 std::string outFile = DEFAULT_PATH + "hooktest_realloc.txt"; 436 StartReallocProcess(setDepth, reallocPid); 437 sleep(1); 438 StartDaemonProcessArgs(reallocPid, outFile); 439 440 sleep(1); 441 std::string cmd = "kill -36 " + std::to_string(reallocPid); 442 system(cmd.c_str()); 443 444 sleep(SLEEP_TIME); // 等待生成文本 445 StopProcess(reallocPid); 446 StopProcess(g_daemonPid); 447 448 int32_t ret = ReadFile(outFile); 449 ASSERT_NE(ret, -1); 450 451 BufferSplitter totalbuffer(const_cast<char*>((char*)g_buffer.get()), ret + 1); 452 std::vector<std::string> hookVec; 453 std::string mallocAddr = ""; 454 std::string reallocAddr = ""; 455 int depth = 0; 456 int addrPos = 3; 457 bool isFirstHook = true; 458 bool isRealloc = false; 459 do { 460 char delimiter = ';'; 461 Getdata(totalbuffer, hookVec, delimiter); 462 463 if (hookVec[0] == "malloc") { 464 for (int i = 0; i < g_mallocGetDataSize; i++) { 465 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 466 } 467 delimiter = '\n'; 468 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 469 ASSERT_EQ(static_cast<int>(hookVec.size()), g_mallocVecSize); 470 471 if (isRealloc) { 472 reallocAddr = hookVec[addrPos]; 473 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_REALLOC_SIZE); 474 EXPECT_EQ(depth, g_defaultDepth/g_freeGetDataSize); 475 isFirstHook = false; 476 } else { 477 mallocAddr = hookVec[addrPos]; 478 ASSERT_EQ(atoi(hookVec[4].c_str()), DEFAULT_MALLOC_SIZE); 479 if (!isFirstHook) { 480 EXPECT_EQ(depth, g_defaultDepth); 481 } 482 } 483 484 isRealloc = true; 485 depth = 0; 486 } else if (hookVec[0] == "free") { 487 for (int i = 0; i < g_freeGetDataSize; i++) { 488 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 489 } 490 delimiter = '\n'; 491 EXPECT_TRUE(Getdata(totalbuffer, hookVec, delimiter)); 492 ASSERT_EQ(static_cast<int>(hookVec.size()), g_freeVecSize); 493 494 if (isRealloc) { 495 EXPECT_STREQ(hookVec[addrPos].c_str(), mallocAddr.c_str()); 496 mallocAddr = ""; 497 } else { 498 EXPECT_STREQ(hookVec[addrPos].c_str(), reallocAddr.c_str()); 499 reallocAddr = ""; 500 } 501 502 EXPECT_EQ(depth, g_defaultDepth); 503 504 isRealloc = false; 505 depth = 0; 506 } else { 507 depth++; 508 } 509 510 hookVec.clear(); 511 } while (totalbuffer.NextLine()); 512 } 513 } 514 515 #pragma clang optimize on 516