1570af302Sopenharmony_ci/** 2570af302Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4570af302Sopenharmony_ci * you may not use this file except in compliance with the License. 5570af302Sopenharmony_ci * You may obtain a copy of the License at 6570af302Sopenharmony_ci * 7570af302Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8570af302Sopenharmony_ci * 9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12570af302Sopenharmony_ci * See the License for the specific language governing permissions and 13570af302Sopenharmony_ci * limitations under the License. 14570af302Sopenharmony_ci */ 15570af302Sopenharmony_ci 16570af302Sopenharmony_ci#ifdef USE_GWP_ASAN 17570af302Sopenharmony_ci 18570af302Sopenharmony_ci#include <fcntl.h> 19570af302Sopenharmony_ci#include <unistd.h> 20570af302Sopenharmony_ci#include <string.h> 21570af302Sopenharmony_ci#include <sys/random.h> 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci#include "gwp_asan.h" 24570af302Sopenharmony_ci 25570af302Sopenharmony_ci#include "musl_log.h" 26570af302Sopenharmony_ci#include "musl_malloc.h" 27570af302Sopenharmony_ci#include "pthread.h" 28570af302Sopenharmony_ci#include "pthread_impl.h" 29570af302Sopenharmony_ci 30570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER 31570af302Sopenharmony_ci#include "sys_param.h" 32570af302Sopenharmony_ci#endif 33570af302Sopenharmony_ci 34570af302Sopenharmony_ci#define MAX_SIMULTANEOUS_ALLOCATIONS 32 35570af302Sopenharmony_ci#define SAMPLE_RATE 2500 36570af302Sopenharmony_ci#define GWP_ASAN_NAME_LEN 256 37570af302Sopenharmony_ci#define GWP_ASAN_PREDICT_TRUE(exp) __builtin_expect((exp) != 0, 1) 38570af302Sopenharmony_ci#define GWP_ASAN_PREDICT_FALSE(exp) __builtin_expect((exp) != 0, 0) 39570af302Sopenharmony_ci#define GWP_ASAN_LOGD(...) // change it to MUSL_LOGD to get gwp_asan debug log. 40570af302Sopenharmony_ci#define GWP_ASAN_NO_ADDRESS __attribute__((no_sanitize("address", "hwaddress"))) 41570af302Sopenharmony_ci 42570af302Sopenharmony_cistatic bool gwp_asan_initialized = false; 43570af302Sopenharmony_cistatic uint8_t process_sample_rate = 128; 44570af302Sopenharmony_cistatic uint8_t force_sample_alloctor = 0; 45570af302Sopenharmony_cistatic uint8_t previous_random_value = 0; 46570af302Sopenharmony_ci 47570af302Sopenharmony_citypedef struct { 48570af302Sopenharmony_ci const char *dli_fname; 49570af302Sopenharmony_ci void *dli_fbase; 50570af302Sopenharmony_ci const char *dli_sname; 51570af302Sopenharmony_ci void *dli_saddr; 52570af302Sopenharmony_ci} Dl_info; 53570af302Sopenharmony_ci 54570af302Sopenharmony_ci// C interfaces of gwp_asan provided by LLVM side. 55570af302Sopenharmony_ciextern void init_gwp_asan(void *init_options); 56570af302Sopenharmony_ciextern void* gwp_asan_malloc(size_t bytes); 57570af302Sopenharmony_ciextern void gwp_asan_free(void *mem); 58570af302Sopenharmony_ciextern bool gwp_asan_should_sample(); 59570af302Sopenharmony_ciextern bool gwp_asan_pointer_is_mine(void *mem); 60570af302Sopenharmony_ciextern bool gwp_asan_has_free_mem(); 61570af302Sopenharmony_ciextern size_t gwp_asan_get_size(void *mem); 62570af302Sopenharmony_ciextern void gwp_asan_disable(); 63570af302Sopenharmony_ciextern void gwp_asan_enable(); 64570af302Sopenharmony_ciextern void gwp_asan_iterate(void *base, size_t size, 65570af302Sopenharmony_ci void (*callback)(void* base, size_t size, void *arg), void *arg); 66570af302Sopenharmony_ci 67570af302Sopenharmony_ci 68570af302Sopenharmony_ciextern int dladdr(const void *addr, Dl_info *info); 69570af302Sopenharmony_ci 70570af302Sopenharmony_cistatic char *get_process_short_name(char *buf, size_t length) 71570af302Sopenharmony_ci{ 72570af302Sopenharmony_ci char *app = NULL; 73570af302Sopenharmony_ci int fd = open("/proc/self/cmdline", O_RDONLY); 74570af302Sopenharmony_ci if (fd != -1) { 75570af302Sopenharmony_ci ssize_t ret = read(fd, buf, length - 1); 76570af302Sopenharmony_ci if (ret != -1) { 77570af302Sopenharmony_ci buf[ret] = 0; 78570af302Sopenharmony_ci app = strrchr(buf, '/'); 79570af302Sopenharmony_ci if (app) { 80570af302Sopenharmony_ci app++; 81570af302Sopenharmony_ci } else { 82570af302Sopenharmony_ci app = buf; 83570af302Sopenharmony_ci } 84570af302Sopenharmony_ci char *app_end = strchr(app, ':'); 85570af302Sopenharmony_ci if (app_end) { 86570af302Sopenharmony_ci *app_end = 0; 87570af302Sopenharmony_ci } 88570af302Sopenharmony_ci } 89570af302Sopenharmony_ci close(fd); 90570af302Sopenharmony_ci } 91570af302Sopenharmony_ci return app; 92570af302Sopenharmony_ci} 93570af302Sopenharmony_ci 94570af302Sopenharmony_cibool is_gwp_asan_disable() 95570af302Sopenharmony_ci{ 96570af302Sopenharmony_ci char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.disable.all"; 97570af302Sopenharmony_ci static CachedHandle para_handler = NULL; 98570af302Sopenharmony_ci if (para_handler == NULL) { 99570af302Sopenharmony_ci para_handler = CachedParameterCreate(para_name, "false"); 100570af302Sopenharmony_ci } 101570af302Sopenharmony_ci char *para_value = CachedParameterGet(para_handler); 102570af302Sopenharmony_ci if (para_value != NULL && strcmp(para_value, "true") == 0) { 103570af302Sopenharmony_ci return true; 104570af302Sopenharmony_ci } 105570af302Sopenharmony_ci return false; 106570af302Sopenharmony_ci} 107570af302Sopenharmony_ci 108570af302Sopenharmony_cibool force_sample_process_by_env() 109570af302Sopenharmony_ci{ 110570af302Sopenharmony_ci char buf[GWP_ASAN_NAME_LEN]; 111570af302Sopenharmony_ci char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN); 112570af302Sopenharmony_ci if (!path) { 113570af302Sopenharmony_ci return false; 114570af302Sopenharmony_ci } 115570af302Sopenharmony_ci char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.enable.app."; 116570af302Sopenharmony_ci strcat(para_name, path); 117570af302Sopenharmony_ci static CachedHandle app_enable_handle = NULL; 118570af302Sopenharmony_ci if (app_enable_handle == NULL) { 119570af302Sopenharmony_ci app_enable_handle = CachedParameterCreate(para_name, "false"); 120570af302Sopenharmony_ci } 121570af302Sopenharmony_ci char *param_value = CachedParameterGet(app_enable_handle); 122570af302Sopenharmony_ci if (param_value != NULL) { 123570af302Sopenharmony_ci if (strcmp(param_value, "true") == 0) { 124570af302Sopenharmony_ci return true; 125570af302Sopenharmony_ci } 126570af302Sopenharmony_ci } 127570af302Sopenharmony_ci return false; 128570af302Sopenharmony_ci} 129570af302Sopenharmony_ci 130570af302Sopenharmony_cibool force_sample_alloctor_by_env() 131570af302Sopenharmony_ci{ 132570af302Sopenharmony_ci char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.sample.all"; 133570af302Sopenharmony_ci static CachedHandle para_handler = NULL; 134570af302Sopenharmony_ci if (para_handler == NULL) { 135570af302Sopenharmony_ci para_handler = CachedParameterCreate(para_name, "false"); 136570af302Sopenharmony_ci } 137570af302Sopenharmony_ci char *para_value = CachedParameterGet(para_handler); 138570af302Sopenharmony_ci if (para_value != NULL && strcmp(para_value, "true") == 0) { 139570af302Sopenharmony_ci force_sample_alloctor = 1; 140570af302Sopenharmony_ci return true; 141570af302Sopenharmony_ci } 142570af302Sopenharmony_ci return false; 143570af302Sopenharmony_ci} 144570af302Sopenharmony_ci 145570af302Sopenharmony_cibool should_sample_process() 146570af302Sopenharmony_ci{ 147570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER 148570af302Sopenharmony_ci if (force_sample_process_by_env()) { 149570af302Sopenharmony_ci return true; 150570af302Sopenharmony_ci } 151570af302Sopenharmony_ci#endif 152570af302Sopenharmony_ci 153570af302Sopenharmony_ci uint8_t random_value; 154570af302Sopenharmony_ci // If getting a random number using a non-blocking fails, the random value is incremented. 155570af302Sopenharmony_ci if (getrandom(&random_value, sizeof(random_value), GRND_RANDOM | GRND_NONBLOCK) == -1) { 156570af302Sopenharmony_ci random_value = previous_random_value + 1; 157570af302Sopenharmony_ci previous_random_value = random_value; 158570af302Sopenharmony_ci } 159570af302Sopenharmony_ci 160570af302Sopenharmony_ci return (random_value % process_sample_rate) == 0 ? true : false; 161570af302Sopenharmony_ci} 162570af302Sopenharmony_ci 163570af302Sopenharmony_ci#define ASAN_LOG_LIB "libasan_logger.z.so" 164570af302Sopenharmony_cistatic void (*WriteGwpAsanLog)(char*, size_t); 165570af302Sopenharmony_cistatic void* handle = NULL; 166570af302Sopenharmony_cistatic bool try_load_asan_logger = false; 167570af302Sopenharmony_cistatic pthread_mutex_t gwpasan_mutex = PTHREAD_MUTEX_INITIALIZER; 168570af302Sopenharmony_ci 169570af302Sopenharmony_civoid gwp_asan_printf(const char *fmt, ...) 170570af302Sopenharmony_ci{ 171570af302Sopenharmony_ci char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.log.path"; 172570af302Sopenharmony_ci static CachedHandle para_handler = NULL; 173570af302Sopenharmony_ci if (para_handler == NULL) { 174570af302Sopenharmony_ci para_handler = CachedParameterCreate(para_name, "file"); 175570af302Sopenharmony_ci } 176570af302Sopenharmony_ci char *para_value = CachedParameterGet(para_handler); 177570af302Sopenharmony_ci if (strcmp(para_value, "file") == 0) { 178570af302Sopenharmony_ci char process_short_name[GWP_ASAN_NAME_LEN]; 179570af302Sopenharmony_ci char *path = get_process_short_name(process_short_name, GWP_ASAN_NAME_LEN); 180570af302Sopenharmony_ci if (!path) { 181570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan]: get_process_short_name failed!"); 182570af302Sopenharmony_ci return; 183570af302Sopenharmony_ci } 184570af302Sopenharmony_ci char log_path[GWP_ASAN_NAME_LEN]; 185570af302Sopenharmony_ci snprintf(log_path, GWP_ASAN_NAME_LEN, "%s%s.%s.%d.log", GWP_ASAN_LOG_DIR, GWP_ASAN_LOG_TAG, path, getpid()); 186570af302Sopenharmony_ci FILE *fp = fopen(log_path, "a+"); 187570af302Sopenharmony_ci if (!fp) { 188570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s failed!", path, log_path); 189570af302Sopenharmony_ci return; 190570af302Sopenharmony_ci } else { 191570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s succeed.", path, log_path); 192570af302Sopenharmony_ci } 193570af302Sopenharmony_ci va_list ap; 194570af302Sopenharmony_ci va_start(ap, fmt); 195570af302Sopenharmony_ci int result = vfprintf(fp, fmt, ap); 196570af302Sopenharmony_ci va_end(ap); 197570af302Sopenharmony_ci fclose(fp); 198570af302Sopenharmony_ci if (result < 0) { 199570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan] %{public}s write log failed!\n", path); 200570af302Sopenharmony_ci } 201570af302Sopenharmony_ci return; 202570af302Sopenharmony_ci } 203570af302Sopenharmony_ci if (strcmp(para_value, "default") == 0) { 204570af302Sopenharmony_ci va_list ap; 205570af302Sopenharmony_ci va_start(ap, fmt); 206570af302Sopenharmony_ci char log_buffer[PATH_MAX]; 207570af302Sopenharmony_ci int result = vsnprintf(log_buffer, PATH_MAX, fmt, ap); 208570af302Sopenharmony_ci va_end(ap); 209570af302Sopenharmony_ci if (result < 0) { 210570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan] write log failed!\n"); 211570af302Sopenharmony_ci } 212570af302Sopenharmony_ci if (WriteGwpAsanLog != NULL) { 213570af302Sopenharmony_ci WriteGwpAsanLog(log_buffer, strlen(log_buffer)); 214570af302Sopenharmony_ci return; 215570af302Sopenharmony_ci } 216570af302Sopenharmony_ci if (try_load_asan_logger) { 217570af302Sopenharmony_ci return; 218570af302Sopenharmony_ci } 219570af302Sopenharmony_ci pthread_mutex_lock(&gwpasan_mutex); 220570af302Sopenharmony_ci if (WriteGwpAsanLog != NULL) { 221570af302Sopenharmony_ci WriteGwpAsanLog(log_buffer, strlen(log_buffer)); 222570af302Sopenharmony_ci pthread_mutex_unlock(&gwpasan_mutex); 223570af302Sopenharmony_ci return; 224570af302Sopenharmony_ci } 225570af302Sopenharmony_ci if (!try_load_asan_logger && handle == NULL) { 226570af302Sopenharmony_ci try_load_asan_logger = true; 227570af302Sopenharmony_ci handle = dlopen(ASAN_LOG_LIB, RTLD_LAZY); 228570af302Sopenharmony_ci if (handle == NULL) { 229570af302Sopenharmony_ci pthread_mutex_unlock(&gwpasan_mutex); 230570af302Sopenharmony_ci return; 231570af302Sopenharmony_ci } 232570af302Sopenharmony_ci *(void**)(&WriteGwpAsanLog) = dlsym(handle, "WriteGwpAsanLog"); 233570af302Sopenharmony_ci if (WriteGwpAsanLog != NULL) { 234570af302Sopenharmony_ci WriteGwpAsanLog(log_buffer, strlen(log_buffer)); 235570af302Sopenharmony_ci } 236570af302Sopenharmony_ci } 237570af302Sopenharmony_ci pthread_mutex_unlock(&gwpasan_mutex); 238570af302Sopenharmony_ci return; 239570af302Sopenharmony_ci } 240570af302Sopenharmony_ci if (strcmp(para_value, "stdout") == 0) { 241570af302Sopenharmony_ci va_list ap; 242570af302Sopenharmony_ci va_start(ap, fmt); 243570af302Sopenharmony_ci int result = vfprintf(stdout, fmt, ap); 244570af302Sopenharmony_ci va_end(ap); 245570af302Sopenharmony_ci if (result < 0) { 246570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan] write log failed!\n"); 247570af302Sopenharmony_ci } 248570af302Sopenharmony_ci return; 249570af302Sopenharmony_ci } 250570af302Sopenharmony_ci} 251570af302Sopenharmony_ci 252570af302Sopenharmony_civoid gwp_asan_printf_backtrace(uintptr_t *trace_buffer, size_t trace_length, printf_t gwp_asan_printf) 253570af302Sopenharmony_ci{ 254570af302Sopenharmony_ci if (trace_length == 0) { 255570af302Sopenharmony_ci gwp_asan_printf("It dosen't see any stack trace!\n"); 256570af302Sopenharmony_ci } 257570af302Sopenharmony_ci for (size_t i = 0; i < trace_length; i++) { 258570af302Sopenharmony_ci if (trace_buffer[i]) { 259570af302Sopenharmony_ci Dl_info info; 260570af302Sopenharmony_ci if (dladdr(trace_buffer[i], &info)) { 261570af302Sopenharmony_ci size_t offset = trace_buffer[i] - (uintptr_t)info.dli_fbase; 262570af302Sopenharmony_ci gwp_asan_printf(" #%zu %p (%s+%p)\n", i, trace_buffer[i], info.dli_fname, offset); 263570af302Sopenharmony_ci } else { 264570af302Sopenharmony_ci gwp_asan_printf(" #%zu %p\n", i, trace_buffer[i]); 265570af302Sopenharmony_ci } 266570af302Sopenharmony_ci } 267570af302Sopenharmony_ci } 268570af302Sopenharmony_ci gwp_asan_printf("\n"); 269570af302Sopenharmony_ci} 270570af302Sopenharmony_ci 271570af302Sopenharmony_ci// Strip pc because pc may have been protected by pac(Pointer Authentication) when build with "-mbranch-protection". 272570af302Sopenharmony_cisize_t strip_pac_pc(size_t ptr) 273570af302Sopenharmony_ci{ 274570af302Sopenharmony_ci#if defined(MUSL_AARCH64_ARCH) 275570af302Sopenharmony_ci register size_t x30 __asm__("x30") = ptr; 276570af302Sopenharmony_ci // "xpaclri" is a NOP on pre armv8.3-a arch. 277570af302Sopenharmony_ci __asm__ volatile("xpaclri" : "+r"(x30)); 278570af302Sopenharmony_ci return x30; 279570af302Sopenharmony_ci#else 280570af302Sopenharmony_ci return ptr; 281570af302Sopenharmony_ci#endif 282570af302Sopenharmony_ci} 283570af302Sopenharmony_ci 284570af302Sopenharmony_ci/* This function is used for gwp_asan to record the call stack when allocate and deallocate. 285570af302Sopenharmony_ci * So we implemented a fast unwind function by using fp. 286570af302Sopenharmony_ci * The unwind process may stop because the value of fp is incorrect(fp was not saved on the stack due to optimization) 287570af302Sopenharmony_ci * We can build library with "-fno-omit-frame-pointer" to get a more accurate call stack. 288570af302Sopenharmony_ci * The basic unwind principle is as follows: 289570af302Sopenharmony_ci * Stack: func1->func2->func3 290570af302Sopenharmony_ci * --------------------| [Low Adress] 291570af302Sopenharmony_ci * | fp | |-------->| 292570af302Sopenharmony_ci * | lr | func3 | | 293570af302Sopenharmony_ci * | ...... | | | 294570af302Sopenharmony_ci * --------------------|<--------| 295570af302Sopenharmony_ci * | fp | |-------->| 296570af302Sopenharmony_ci * | lr | func2 | | 297570af302Sopenharmony_ci * | ...... | | | 298570af302Sopenharmony_ci * --------------------| | 299570af302Sopenharmony_ci * | fp | |<--------| 300570af302Sopenharmony_ci * | lr | func1 | 301570af302Sopenharmony_ci * | ...... | | 302570af302Sopenharmony_ci * --------------------| [High Address] 303570af302Sopenharmony_ci */ 304570af302Sopenharmony_ciGWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_fast(size_t *frame_buf, size_t max_record_stack, 305570af302Sopenharmony_ci __attribute__((unused)) void *signal_context) 306570af302Sopenharmony_ci{ 307570af302Sopenharmony_ci size_t current_frame_addr = __builtin_frame_address(0); 308570af302Sopenharmony_ci size_t stack_end = (size_t)(__pthread_self()->stack); 309570af302Sopenharmony_ci size_t num_frames = 0; 310570af302Sopenharmony_ci size_t prev_fp = 0; 311570af302Sopenharmony_ci size_t prev_lr = 0; 312570af302Sopenharmony_ci while (true) { 313570af302Sopenharmony_ci unwind_info *frame = (unwind_info*)(current_frame_addr); 314570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan] unwind info:%{public}d cur:%{public}p, end:%{public}p fp:%{public}p lr:%{public}p \n", 315570af302Sopenharmony_ci num_frames, current_frame_addr, stack_end, frame->fp, frame->lr); 316570af302Sopenharmony_ci if (!frame->lr) { 317570af302Sopenharmony_ci break; 318570af302Sopenharmony_ci } 319570af302Sopenharmony_ci if (num_frames < max_record_stack) { 320570af302Sopenharmony_ci frame_buf[num_frames] = strip_pac_pc(frame->lr) - 4; 321570af302Sopenharmony_ci } 322570af302Sopenharmony_ci ++num_frames; 323570af302Sopenharmony_ci if (frame->fp == prev_fp || frame->lr == prev_lr || frame->fp < current_frame_addr + sizeof(unwind_info) || 324570af302Sopenharmony_ci frame->fp >= stack_end || frame->fp % sizeof(void*) != 0) { 325570af302Sopenharmony_ci break; 326570af302Sopenharmony_ci } 327570af302Sopenharmony_ci prev_fp = frame->fp; 328570af302Sopenharmony_ci prev_lr = frame->lr; 329570af302Sopenharmony_ci current_frame_addr = frame->fp; 330570af302Sopenharmony_ci } 331570af302Sopenharmony_ci 332570af302Sopenharmony_ci return num_frames; 333570af302Sopenharmony_ci} 334570af302Sopenharmony_ci 335570af302Sopenharmony_cibool may_init_gwp_asan(bool force_init) 336570af302Sopenharmony_ci{ 337570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan enter force_init:%{public}d.\n", force_init); 338570af302Sopenharmony_ci if (gwp_asan_initialized) { 339570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan_initialized is true.\n"); 340570af302Sopenharmony_ci return false; 341570af302Sopenharmony_ci } 342570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER 343570af302Sopenharmony_ci // Turn off gwp_asan. 344570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(is_gwp_asan_disable())) { 345570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan is disable by env.\n"); 346570af302Sopenharmony_ci return false; 347570af302Sopenharmony_ci } 348570af302Sopenharmony_ci#endif 349570af302Sopenharmony_ci 350570af302Sopenharmony_ci if (!force_init && !should_sample_process()) { 351570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because sample not hit.\n"); 352570af302Sopenharmony_ci return false; 353570af302Sopenharmony_ci } 354570af302Sopenharmony_ci 355570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER 356570af302Sopenharmony_ci // All memory allocations use gwp_asan. 357570af302Sopenharmony_ci force_sample_alloctor_by_env(); 358570af302Sopenharmony_ci#endif 359570af302Sopenharmony_ci 360570af302Sopenharmony_ci gwp_asan_option gwp_asan_option = { 361570af302Sopenharmony_ci .enable = true, 362570af302Sopenharmony_ci .install_fork_handlers = true, 363570af302Sopenharmony_ci .install_signal_handlers = true, 364570af302Sopenharmony_ci .max_simultaneous_allocations = MAX_SIMULTANEOUS_ALLOCATIONS, 365570af302Sopenharmony_ci .sample_rate = SAMPLE_RATE, 366570af302Sopenharmony_ci .backtrace = libc_gwp_asan_unwind_fast, 367570af302Sopenharmony_ci .gwp_asan_printf = gwp_asan_printf, 368570af302Sopenharmony_ci .printf_backtrace = gwp_asan_printf_backtrace, 369570af302Sopenharmony_ci .segv_backtrace = libc_gwp_asan_unwind_fast, 370570af302Sopenharmony_ci }; 371570af302Sopenharmony_ci 372570af302Sopenharmony_ci char buf[GWP_ASAN_NAME_LEN]; 373570af302Sopenharmony_ci char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN); 374570af302Sopenharmony_ci if (!path) { 375570af302Sopenharmony_ci return false; 376570af302Sopenharmony_ci } 377570af302Sopenharmony_ci 378570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initializing.\n", getpid(), path); 379570af302Sopenharmony_ci init_gwp_asan((void*)&gwp_asan_option); 380570af302Sopenharmony_ci gwp_asan_initialized = true; 381570af302Sopenharmony_ci MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initialized.\n", getpid(), path); 382570af302Sopenharmony_ci return true; 383570af302Sopenharmony_ci} 384570af302Sopenharmony_cibool init_gwp_asan_by_libc(bool force_init) 385570af302Sopenharmony_ci{ 386570af302Sopenharmony_ci char buf[GWP_ASAN_NAME_LEN]; 387570af302Sopenharmony_ci char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN); 388570af302Sopenharmony_ci if (!path) { 389570af302Sopenharmony_ci return false; 390570af302Sopenharmony_ci } 391570af302Sopenharmony_ci // We don't sample appspawn, and the chaild process decides whether to sample or not. 392570af302Sopenharmony_ci if (strcmp(path, "appspawn") == 0 || strcmp(path, "sh") == 0) { 393570af302Sopenharmony_ci return false; 394570af302Sopenharmony_ci } 395570af302Sopenharmony_ci return may_init_gwp_asan(force_init); 396570af302Sopenharmony_ci} 397570af302Sopenharmony_ci 398570af302Sopenharmony_civoid* get_platform_gwp_asan_tls_slot() 399570af302Sopenharmony_ci{ 400570af302Sopenharmony_ci return (void*)(&(__pthread_self()->gwp_asan_tls)); 401570af302Sopenharmony_ci} 402570af302Sopenharmony_ci 403570af302Sopenharmony_civoid* libc_gwp_asan_malloc(size_t bytes) 404570af302Sopenharmony_ci{ 405570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 406570af302Sopenharmony_ci return MuslFunc(malloc)(bytes); 407570af302Sopenharmony_ci } 408570af302Sopenharmony_ci void *res = NULL; 409570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) { 410570af302Sopenharmony_ci res = gwp_asan_malloc(bytes); 411570af302Sopenharmony_ci if (res != NULL) { 412570af302Sopenharmony_ci return res; 413570af302Sopenharmony_ci } 414570af302Sopenharmony_ci } 415570af302Sopenharmony_ci return MuslFunc(malloc)(bytes); 416570af302Sopenharmony_ci} 417570af302Sopenharmony_ci 418570af302Sopenharmony_civoid* libc_gwp_asan_calloc(size_t nmemb, size_t size) 419570af302Sopenharmony_ci{ 420570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 421570af302Sopenharmony_ci return MuslFunc(calloc)(nmemb, size); 422570af302Sopenharmony_ci } 423570af302Sopenharmony_ci 424570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) { 425570af302Sopenharmony_ci size_t total_bytes; 426570af302Sopenharmony_ci void* result = NULL; 427570af302Sopenharmony_ci if (!__builtin_mul_overflow(nmemb, size, &total_bytes)) { 428570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc nmemb:%{public}d size:%{public}d.\n", nmemb, size); 429570af302Sopenharmony_ci result = gwp_asan_malloc(total_bytes); 430570af302Sopenharmony_ci if (result != NULL) { 431570af302Sopenharmony_ci return result; 432570af302Sopenharmony_ci } 433570af302Sopenharmony_ci } 434570af302Sopenharmony_ci } 435570af302Sopenharmony_ci 436570af302Sopenharmony_ci return MuslFunc(calloc)(nmemb, size); 437570af302Sopenharmony_ci} 438570af302Sopenharmony_ci 439570af302Sopenharmony_civoid* libc_gwp_asan_realloc(void *ptr, size_t size) 440570af302Sopenharmony_ci{ 441570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 442570af302Sopenharmony_ci return MuslFunc(realloc)(ptr, size); 443570af302Sopenharmony_ci } 444570af302Sopenharmony_ci 445570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(ptr))) { 446570af302Sopenharmony_ci GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc ptr:%{public}p size:%{public}d.\n", ptr, size); 447570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(size == 0)) { 448570af302Sopenharmony_ci gwp_asan_free(ptr); 449570af302Sopenharmony_ci return NULL; 450570af302Sopenharmony_ci } 451570af302Sopenharmony_ci 452570af302Sopenharmony_ci void* new_addr = gwp_asan_malloc(size); 453570af302Sopenharmony_ci if (new_addr != NULL) { 454570af302Sopenharmony_ci size_t old_size = gwp_asan_get_size(ptr); 455570af302Sopenharmony_ci memcpy(new_addr, ptr, (size < old_size) ? size : old_size); 456570af302Sopenharmony_ci gwp_asan_free(ptr); 457570af302Sopenharmony_ci return new_addr; 458570af302Sopenharmony_ci } else { 459570af302Sopenharmony_ci // Use the default allocator if gwp malloc failed. 460570af302Sopenharmony_ci void* addr_of_default_allocator = MuslFunc(malloc)(size); 461570af302Sopenharmony_ci if (addr_of_default_allocator != NULL) { 462570af302Sopenharmony_ci size_t old_size = gwp_asan_get_size(ptr); 463570af302Sopenharmony_ci memcpy(addr_of_default_allocator, ptr, (size < old_size) ? size : old_size); 464570af302Sopenharmony_ci gwp_asan_free(ptr); 465570af302Sopenharmony_ci return addr_of_default_allocator; 466570af302Sopenharmony_ci } else { 467570af302Sopenharmony_ci return NULL; 468570af302Sopenharmony_ci } 469570af302Sopenharmony_ci } 470570af302Sopenharmony_ci } 471570af302Sopenharmony_ci return MuslFunc(realloc)(ptr, size); 472570af302Sopenharmony_ci} 473570af302Sopenharmony_ci 474570af302Sopenharmony_civoid libc_gwp_asan_free(void *addr) 475570af302Sopenharmony_ci{ 476570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 477570af302Sopenharmony_ci return MuslFunc(free)(addr); 478570af302Sopenharmony_ci } 479570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) { 480570af302Sopenharmony_ci return gwp_asan_free(addr); 481570af302Sopenharmony_ci } 482570af302Sopenharmony_ci return MuslFunc(free)(addr); 483570af302Sopenharmony_ci} 484570af302Sopenharmony_ci 485570af302Sopenharmony_cisize_t libc_gwp_asan_malloc_usable_size(void *addr) 486570af302Sopenharmony_ci{ 487570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 488570af302Sopenharmony_ci return MuslMalloc(malloc_usable_size)(addr); 489570af302Sopenharmony_ci } 490570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) { 491570af302Sopenharmony_ci return gwp_asan_get_size(addr); 492570af302Sopenharmony_ci } 493570af302Sopenharmony_ci return MuslMalloc(malloc_usable_size)(addr); 494570af302Sopenharmony_ci} 495570af302Sopenharmony_ci 496570af302Sopenharmony_civoid libc_gwp_asan_malloc_iterate(void *base, size_t size, 497570af302Sopenharmony_ci void (*callback)(uintptr_t base, size_t size, void *arg), void *arg) 498570af302Sopenharmony_ci{ 499570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 500570af302Sopenharmony_ci return; 501570af302Sopenharmony_ci } 502570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(base))) { 503570af302Sopenharmony_ci return gwp_asan_iterate(base, size, callback, arg); 504570af302Sopenharmony_ci } 505570af302Sopenharmony_ci return; 506570af302Sopenharmony_ci} 507570af302Sopenharmony_ci 508570af302Sopenharmony_civoid libc_gwp_asan_malloc_disable() 509570af302Sopenharmony_ci{ 510570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 511570af302Sopenharmony_ci return; 512570af302Sopenharmony_ci } 513570af302Sopenharmony_ci 514570af302Sopenharmony_ci return gwp_asan_disable(); 515570af302Sopenharmony_ci} 516570af302Sopenharmony_ci 517570af302Sopenharmony_civoid libc_gwp_asan_malloc_enable() 518570af302Sopenharmony_ci{ 519570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 520570af302Sopenharmony_ci return; 521570af302Sopenharmony_ci } 522570af302Sopenharmony_ci 523570af302Sopenharmony_ci return gwp_asan_enable(); 524570af302Sopenharmony_ci} 525570af302Sopenharmony_ci 526570af302Sopenharmony_cibool libc_gwp_asan_has_free_mem() 527570af302Sopenharmony_ci{ 528570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 529570af302Sopenharmony_ci return false; 530570af302Sopenharmony_ci } 531570af302Sopenharmony_ci gwp_asan_disable(); 532570af302Sopenharmony_ci int res = gwp_asan_has_free_mem(); 533570af302Sopenharmony_ci gwp_asan_enable(); 534570af302Sopenharmony_ci return res; 535570af302Sopenharmony_ci} 536570af302Sopenharmony_cibool libc_gwp_asan_ptr_is_mine(void *addr) 537570af302Sopenharmony_ci{ 538570af302Sopenharmony_ci if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) { 539570af302Sopenharmony_ci return false; 540570af302Sopenharmony_ci } 541570af302Sopenharmony_ci 542570af302Sopenharmony_ci return gwp_asan_pointer_is_mine(addr); 543570af302Sopenharmony_ci} 544570af302Sopenharmony_ci#else 545570af302Sopenharmony_ci#include <stdbool.h> 546570af302Sopenharmony_ci 547570af302Sopenharmony_ci// Used for appspawn. 548570af302Sopenharmony_cibool may_init_gwp_asan(bool force_init) 549570af302Sopenharmony_ci{ 550570af302Sopenharmony_ci return false; 551570af302Sopenharmony_ci} 552570af302Sopenharmony_ci#endif 553