• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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