1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
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 "hidebug_base.h"
17 
18 #include <dlfcn.h>
19 #include <errno.h>
20 #include <inttypes.h>
21 #include <limits.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "securec.h"
29 
30 #ifdef HIDEBUG_IN_INIT
31 #include "init_module_engine.h"
32 #include "init_log.h"
33 #define HIDEBUG_LOGE(...) INIT_LOGE(__VA_ARGS__)
34 #define HIDEBUG_LOGI(...) INIT_LOGI(__VA_ARGS__)
35 #define LOG_PRIV_PUBLIC ""
36 #else
37 #include <parameter.h>
38 #include <sysparam_errno.h>
39 #include <hilog/log.h>
40 #include "hichecker_wrapper.h"
41 
42 #undef LOG_DOMAIN
43 #undef LOG_TAG
44 #define LOG_DOMAIN 0xD002D0A
45 #define LOG_TAG "HiDebug_Native"
46 
47 #define HIDEBUG_LOGE(...) HILOG_ERROR(LOG_CORE, __VA_ARGS__)
48 #define HIDEBUG_LOGI(...) HILOG_INFO(LOG_CORE, __VA_ARGS__)
49 #define LOG_PRIV_PUBLIC "{public}"
50 #endif
51 
52 #define MAX_PARA_LEN 50
53 #define MAX_PARA_CNT 20
54 #define PARAM_BUF_LEN 128
55 #define QUERYNAME_LEN 80
56 #define COLON_CHR ':'
57 #define SLASH_CHR '/'
58 const char * const LIBC_HOOK_PARAM = "libc.hook_mode";
59 
60 struct Params {
61     char key[MAX_PARA_LEN];
62     char value[MAX_PARA_LEN];
63 };
64 
ParseKeyValue(const char *input, uint32_t *paramCnt, struct Params *result, const uint32_t paramSize)65 static void ParseKeyValue(const char *input, uint32_t *paramCnt, struct Params *result, const uint32_t paramSize)
66 {
67     if (*paramCnt >= paramSize) {
68         HIDEBUG_LOGE("Parameters is Full.");
69         return;
70     }
71     const char *colonPos = strchr(input, COLON_CHR);
72     if (colonPos == NULL) {
73         HIDEBUG_LOGE("params is illegal.");
74         return;
75     }
76     errno_t err = strncpy_s(result[*paramCnt].key, MAX_PARA_LEN, input, colonPos - input);
77     if (err != EOK) {
78         HIDEBUG_LOGE("strncpy_s copy key strings failed.");
79         return;
80     }
81     err = strncpy_s(result[*paramCnt].value, MAX_PARA_LEN, colonPos + 1, strlen(colonPos + 1));
82     if (err != EOK) {
83         HIDEBUG_LOGE("strncpy_s copy value strings failed.");
84         return;
85     }
86     (*paramCnt)++;
87 }
88 
SplitParams(char *input, struct Params *result, const uint32_t paramSize)89 static uint32_t SplitParams(char *input, struct Params *result, const uint32_t paramSize)
90 {
91     uint32_t paramCnt = 0;
92     const char space[] = " ";
93     char *param;
94     char *next = NULL;
95     param = strtok_s(input, space, &next);
96     while (param != NULL) {
97         ParseKeyValue(param, &paramCnt, result, paramSize);
98         param = strtok_s(NULL, space, &next);
99     }
100     return paramCnt;
101 }
102 
QueryParams(const char *queryName, char *result, const uint32_t size)103 static bool QueryParams(const char *queryName, char *result, const uint32_t size)
104 {
105     if (result == NULL || size > PARAM_BUF_LEN) {
106         return false;
107     }
108 #ifdef HIDEBUG_IN_INIT
109     uint32_t bufferSize = size;
110     int retLen = SystemReadParam(queryName, result, &bufferSize);
111     if (retLen != 0 || bufferSize == 0 || bufferSize > PARAM_BUF_LEN - 1) {
112         return false;
113     }
114     result[bufferSize] = '\0';
115 #else
116     int retLen = GetParameter(queryName, NULL, result, size);
117     if (retLen <= 0 || retLen > PARAM_BUF_LEN - 1) {
118         return false;
119     }
120     result[retLen] = '\0';
121 #endif
122     return true;
123 }
124 
ConcatenateParamName(char* queryName, const size_t size, const char* serviceName)125 static bool ConcatenateParamName(char* queryName, const size_t size, const char* serviceName)
126 {
127     if (strcat_s(queryName, size, serviceName) != EOK) {
128         HIDEBUG_LOGE("strcat_s query name failed.");
129         return false;
130     }
131     return true;
132 }
133 
InitHiDebugEnvParams(const char *queryName)134 static bool InitHiDebugEnvParams(const char *queryName)
135 {
136     char paramOutBuf[PARAM_BUF_LEN] = { 0 };
137     if (!QueryParams(queryName, paramOutBuf, PARAM_BUF_LEN)) {
138         return false;
139     }
140     struct Params params[MAX_PARA_CNT];
141     uint32_t paramsCnt = SplitParams(paramOutBuf, params, MAX_PARA_CNT);
142     for (uint32_t i = 0; i < paramsCnt; ++i) {
143         if (setenv(params[i].key, params[i].value, 1) != 0) { // 1 : overwrite
144             HIDEBUG_LOGE("setenv failed, err: %" LOG_PRIV_PUBLIC "s", strerror(errno));
145         }
146     }
147     return paramsCnt > 0;
148 }
149 
FilterServiceName(const char *inputName)150 static const char* FilterServiceName(const char *inputName)
151 {
152     const char *ret = strrchr(inputName, SLASH_CHR);
153     if (ret == NULL) {
154         return inputName;
155     }
156     return ret + 1;
157 }
158 
GetMallocHookStartupValue(const char *param, char *path, int size)159 static int GetMallocHookStartupValue(const char *param, char *path, int size)
160 {
161     if (path == NULL || size <= 0) {
162         return -1;
163     }
164 
165     const char *ptr = param;
166 
167     while (*ptr && *ptr != ':') {
168         ++ptr;
169     }
170     if (*ptr == ':') {
171         ++ptr;
172     }
173     const int paramLength = 7;
174     if (strncmp(param, "startup", paramLength) == 0) {
175         if (*ptr == '\"') {
176             ++ptr;
177             int idx = 0;
178             while (idx < size - 1 && *ptr && *ptr != '\"') {
179                 path[idx++] = *ptr++;
180             }
181             path[idx] = '\0';
182         } else {
183             int idx = 0;
184             while (idx < size - 1 && *ptr) {
185                 path[idx++] = *ptr++;
186             }
187             path[idx] = '\0';
188         }
189     }
190     return 0;
191 }
192 
MatchMallocHookStartupProp(const char *thisName)193 static bool MatchMallocHookStartupProp(const char *thisName)
194 {
195     char paramOutBuf[PARAM_BUF_LEN] = { 0 };
196     char targetProcName[PARAM_BUF_LEN] = { 0 };
197 
198 #ifdef HIDEBUG_IN_INIT
199     uint32_t size = PARAM_BUF_LEN;
200     int retLen = SystemReadParam(LIBC_HOOK_PARAM, paramOutBuf, &size);
201     if (retLen != 0 || size <= 0) {
202         return 0;
203     }
204     retLen = (int)size;
205 #else
206     char defStrValue[PARAM_BUF_LEN] = { 0 };
207     int retLen = GetParameter(LIBC_HOOK_PARAM, defStrValue, paramOutBuf, PARAM_BUF_LEN);
208     if (retLen == 0) {
209         return 0;
210     }
211 #endif
212     const int paramLength = 8;
213     if (strncmp(paramOutBuf, "startup:", paramLength) != 0) {
214         return false;
215     }
216     retLen = GetMallocHookStartupValue(paramOutBuf, targetProcName, PARAM_BUF_LEN);
217     if (retLen == -1) {
218         HIDEBUG_LOGE("malloc hook parse startup value failed");
219         return false;
220     }
221 
222     const int targetProcNameSize = strlen(targetProcName);
223     if (strncmp(targetProcName, "init", targetProcNameSize) == 0) {
224         HIDEBUG_LOGI("malloc hook: this target proc '%" LOG_PRIV_PUBLIC "s' no hook", targetProcName);
225         return false;
226     }
227 
228     if (strcmp(thisName, targetProcName) == 0) {
229         return true;
230     }
231     return false;
232 }
233 
SetupMallocHookAtStartup(const char *thisName)234 static int SetupMallocHookAtStartup(const char *thisName)
235 {
236     const int hookSignal = 36;
237     if (!MatchMallocHookStartupProp(thisName)) {
238         return 0;
239     }
240     HIDEBUG_LOGI("malloc send hook signal.");
241     return raise(hookSignal);
242 }
243 
InitEnvironmentParam(const char *inputName)244 bool InitEnvironmentParam(const char *inputName)
245 {
246     if (inputName == NULL) {
247         HIDEBUG_LOGE("input service name is null.");
248         return false;
249     }
250     const char *serviceName = FilterServiceName(inputName);
251     if (*serviceName == '\0') {
252         HIDEBUG_LOGE("input service name is illegal.");
253         return false;
254     }
255 #ifndef HIDEBUG_IN_INIT
256     InitHicheckerParamWrapper(serviceName);
257 #endif
258 
259 #ifdef HAS_MUSL_STARTUP_MALLOC_HOOK_INTF
260     setup_malloc_hook_mode();
261 #else
262     SetupMallocHookAtStartup(serviceName);
263 #endif
264 
265     char paramOutBuf[PARAM_BUF_LEN] = { 0 };
266     if (!QueryParams("const.debuggable", paramOutBuf, PARAM_BUF_LEN) || strcmp(paramOutBuf, "1") != 0) {
267         return false;
268     }
269     char onceName[QUERYNAME_LEN] = "hiviewdfx.debugenv.";
270     if (!ConcatenateParamName(onceName, sizeof(onceName), serviceName)) {
271         return false;
272     }
273     if (InitHiDebugEnvParams(onceName)) {
274         return true;
275     }
276     char persistName[QUERYNAME_LEN] = "persist.hiviewdfx.debugenv.";
277     return ConcatenateParamName(persistName, sizeof(onceName), serviceName) && InitHiDebugEnvParams(persistName);
278 }
279