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 PARAM_BUF_LEN 128
53 #define SLASH_CHR '/'
54 const char * const LIBC_HOOK_PARAM = "libc.hook_mode";
55
56 #ifdef HIDEBUG_BUILD_VARIANT_ROOT
57 #define MAX_PARA_LEN 50
58 #define MAX_PARA_CNT 20
59 #define QUERYNAME_LEN 80
60 #define COLON_CHR ':'
61
62 static struct Params {
63 char key[MAX_PARA_LEN];
64 char value[MAX_PARA_LEN];
65 } g_params[MAX_PARA_CNT];
66
67 int g_paramCnt = 0;
68
ParseKeyValue(const char * input)69 static void ParseKeyValue(const char *input)
70 {
71 if (g_paramCnt >= MAX_PARA_CNT) {
72 HIDEBUG_LOGE("Parameters is Full.");
73 return;
74 }
75 const char *colonPos = strchr(input, COLON_CHR);
76 if (colonPos == NULL) {
77 HIDEBUG_LOGE("params is illegal.");
78 return;
79 }
80 errno_t err = strncpy_s(g_params[g_paramCnt].key, MAX_PARA_LEN, input, colonPos - input);
81 if (err != EOK) {
82 HIDEBUG_LOGE("strncpy_s copy key strings failed.");
83 return;
84 }
85 err = strncpy_s(g_params[g_paramCnt].value, MAX_PARA_LEN, colonPos + 1, strlen(colonPos + 1));
86 if (err != EOK) {
87 HIDEBUG_LOGE("strncpy_s copy value strings failed.");
88 return;
89 }
90 g_paramCnt++;
91 }
92
SplitParams(char * input)93 static void SplitParams(char *input)
94 {
95 g_paramCnt = 0;
96 const char space[] = " ";
97 char *param;
98 char *next = NULL;
99 param = strtok_s(input, space, &next);
100 while (param != NULL) {
101 ParseKeyValue(param);
102 param = strtok_s(NULL, space, &next);
103 }
104 }
105
QueryParams(const char * queryName,char * result,const uint32_t size)106 static bool QueryParams(const char *queryName, char *result, const uint32_t size)
107 {
108 if (result == NULL || size > PARAM_BUF_LEN) {
109 return false;
110 }
111 #ifdef HIDEBUG_IN_INIT
112 uint32_t bufferSize = size;
113 int retLen = SystemReadParam(queryName, result, &bufferSize);
114 if (retLen != 0 || bufferSize <= 0 || bufferSize > PARAM_BUF_LEN - 1) {
115 return false;
116 }
117 result[bufferSize] = '\0';
118 #else
119 int retLen = GetParameter(queryName, NULL, result, size);
120 if (retLen <= 0 || retLen > PARAM_BUF_LEN - 1) {
121 return false;
122 }
123 result[retLen] = '\0';
124 #endif
125 return true;
126 }
127
QueryHiDebugEnvParams(const char * queryName)128 static int QueryHiDebugEnvParams(const char *queryName)
129 {
130 g_paramCnt = 0;
131 char paramOutBuf[PARAM_BUF_LEN] = { 0 };
132 if (QueryParams(queryName, paramOutBuf, PARAM_BUF_LEN)) {
133 SplitParams(paramOutBuf);
134 }
135 return g_paramCnt;
136 }
137
InitEnvParam(const char * serviceName)138 static bool InitEnvParam(const char *serviceName)
139 {
140 char paramOutBuf[PARAM_BUF_LEN] = { 0 };
141 if (!QueryParams("const.debuggable", paramOutBuf, PARAM_BUF_LEN) || strcmp(paramOutBuf, "1") != 0) {
142 return false;
143 }
144 errno_t err = 0;
145 char persistName[QUERYNAME_LEN] = "persist.hiviewdfx.debugenv.";
146 char onceName[QUERYNAME_LEN] = "hiviewdfx.debugenv.";
147 err = strcat_s(onceName, sizeof(onceName), serviceName);
148 if (err != EOK) {
149 HIDEBUG_LOGE("strcat_s query name failed.");
150 return false;
151 }
152 err = strcat_s(persistName, sizeof(persistName), serviceName);
153 if (err != EOK) {
154 HIDEBUG_LOGE("strcat_s persist query name failed.");
155 return false;
156 }
157
158 if (QueryHiDebugEnvParams(onceName) == 0 && QueryHiDebugEnvParams(persistName) == 0) {
159 return false;
160 }
161 for (int i = 0; i < g_paramCnt; ++i) {
162 if (setenv(g_params[i].key, g_params[i].value, 1) != 0) { // 1 : overwrite
163 HIDEBUG_LOGE("setenv failed, err: %" LOG_PRIV_PUBLIC "s", strerror(errno));
164 }
165 }
166 return true;
167 }
168 #endif
169
FilterServiceName(const char * inputName)170 static const char* FilterServiceName(const char *inputName)
171 {
172 const char *ret = strrchr(inputName, SLASH_CHR);
173 if (ret == NULL) {
174 return inputName;
175 }
176 return ret + 1;
177 }
178
GetMallocHookStartupValue(const char * param,char * path,int size)179 static int GetMallocHookStartupValue(const char *param, char *path, int size)
180 {
181 if (path == NULL || size <= 0) {
182 return -1;
183 }
184
185 const char *ptr = param;
186
187 while (*ptr && *ptr != ':') {
188 ++ptr;
189 }
190 if (*ptr == ':') {
191 ++ptr;
192 }
193 const int paramLength = 7;
194 if (strncmp(param, "startup", paramLength) == 0) {
195 if (*ptr == '\"') {
196 ++ptr;
197 int idx = 0;
198 while (idx < size - 1 && *ptr && *ptr != '\"') {
199 path[idx++] = *ptr++;
200 }
201 path[idx] = '\0';
202 } else {
203 int idx = 0;
204 while (idx < size - 1 && *ptr) {
205 path[idx++] = *ptr++;
206 }
207 path[idx] = '\0';
208 }
209 }
210 return 0;
211 }
212
MatchMallocHookStartupProp(const char * thisName)213 static bool MatchMallocHookStartupProp(const char *thisName)
214 {
215 char paramOutBuf[PARAM_BUF_LEN] = { 0 };
216 char targetProcName[PARAM_BUF_LEN] = { 0 };
217
218 #ifdef HIDEBUG_IN_INIT
219 uint32_t size = PARAM_BUF_LEN;
220 int retLen = SystemReadParam(LIBC_HOOK_PARAM, paramOutBuf, &size);
221 if (retLen != 0 || size <= 0) {
222 return 0;
223 }
224 retLen = (int)size;
225 #else
226 char defStrValue[PARAM_BUF_LEN] = { 0 };
227 int retLen = GetParameter(LIBC_HOOK_PARAM, defStrValue, paramOutBuf, PARAM_BUF_LEN);
228 if (retLen == 0) {
229 return 0;
230 }
231 #endif
232 const int paramLength = 8;
233 if (strncmp(paramOutBuf, "startup:", paramLength) != 0) {
234 return false;
235 }
236 retLen = GetMallocHookStartupValue(paramOutBuf, targetProcName, PARAM_BUF_LEN);
237 if (retLen == -1) {
238 HIDEBUG_LOGE("malloc hook parse startup value failed");
239 return false;
240 }
241
242 const int targetProcNameSize = strlen(targetProcName);
243 if (strncmp(targetProcName, "init", targetProcNameSize) == 0 ||
244 strncmp(targetProcName, "appspawn", targetProcNameSize) == 0) {
245 HIDEBUG_LOGI("malloc hook: this target proc '%" LOG_PRIV_PUBLIC "s' no hook", targetProcName);
246 return false;
247 }
248
249 if (strcmp(thisName, targetProcName) == 0) {
250 return true;
251 }
252 return false;
253 }
254
SetupMallocHookAtStartup(const char * thisName)255 static int SetupMallocHookAtStartup(const char *thisName)
256 {
257 const int hookSignal = 36;
258 if (!MatchMallocHookStartupProp(thisName)) {
259 return 0;
260 }
261 HIDEBUG_LOGI("malloc send hook signal.");
262 return raise(hookSignal);
263 }
264
InitEnvironmentParam(const char * inputName)265 bool InitEnvironmentParam(const char *inputName)
266 {
267 if (inputName == NULL) {
268 HIDEBUG_LOGE("input service name is null.");
269 return false;
270 }
271 const char *serviceName = FilterServiceName(inputName);
272 if (*serviceName == '\0') {
273 HIDEBUG_LOGE("input service name is illegal.");
274 return false;
275 }
276 #ifndef HIDEBUG_IN_INIT
277 InitHicheckerParamWrapper(serviceName);
278 #endif
279
280 #ifdef HAS_MUSL_STARTUP_MALLOC_HOOK_INTF
281 setup_malloc_hook_mode();
282 #else
283 SetupMallocHookAtStartup(serviceName);
284 #endif
285
286 #ifdef HIDEBUG_BUILD_VARIANT_ROOT
287 return InitEnvParam(serviceName);
288 #else
289 return true;
290 #endif
291 }
292