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 '/' 58const char * const LIBC_HOOK_PARAM = "libc.hook_mode"; 59 60struct Params { 61 char key[MAX_PARA_LEN]; 62 char value[MAX_PARA_LEN]; 63}; 64 65static 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 89static 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 103static 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 125static 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 134static 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 150static 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 159static 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 193static 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 234static 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 244bool 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