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