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, ¶mCnt, 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