• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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 #ifdef USE_GWP_ASAN
17 #define _GNU_SOURCE
18 
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/random.h>
23 
24 #include "gwp_asan.h"
25 
26 #include "musl_log.h"
27 #include "musl_malloc.h"
28 #include "pthread.h"
29 #include "pthread_impl.h"
30 
31 #ifdef OHOS_ENABLE_PARAMETER
32 #include "sys_param.h"
33 #endif
34 
35 #define MAX_SIMULTANEOUS_ALLOCATIONS 1000
36 #define SAMPLE_RATE 2500
37 #define MIN_SAMPLE_SIZE 0
38 #define WHITE_LIST_PATH ""
39 #define GWP_ASAN_NAME_LEN 256
40 #define SECONDS_PER_DAY (24ULL * 60 * 60)
41 #define GWP_ASAN_PREDICT_TRUE(exp) __builtin_expect((exp) != 0, 1)
42 #define GWP_ASAN_PREDICT_FALSE(exp) __builtin_expect((exp) != 0, 0)
43 #define GWP_ASAN_LOGD(...) // change it to MUSL_LOGD to get gwp_asan debug log.
44 #define GWP_ASAN_NO_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))
45 
46 #if defined(__aarch64__)
47 #define REG_AARCH64_X29 29
get_pc(ucontext_t * context)48 static size_t get_pc(ucontext_t *context)
49 {
50     return context->uc_mcontext.pc;
51 }
52 
get_frame_pointer(ucontext_t * context)53 static size_t get_frame_pointer(ucontext_t *context)
54 {
55     return context->uc_mcontext.regs[REG_AARCH64_X29];
56 }
57 #else
get_pc(ucontext_t * context)58 static size_t get_pc(ucontext_t *context)
59 {
60     GWP_ASAN_LOGD("[gwp_asan] Unsupported platform");
61     return 0;
62 }
63 
get_frame_pointer(ucontext_t * context)64 static size_t get_frame_pointer(ucontext_t *context)
65 {
66     GWP_ASAN_LOGD("[gwp_asan] Unsupported platform");
67     return 0;
68 }
69 #endif
70 
71 static bool gwp_asan_initialized = false;
72 static bool gwp_asan_thirdparty_telemetry = false;
73 static uint8_t process_sample_rate = 128;
74 static uint8_t force_sample_alloctor = 0;
75 static uint8_t previous_random_value = 0;
76 
77 #ifndef _GNU_SOURCE
78 typedef struct {
79     const char *dli_fname;
80     void *dli_fbase;
81     const char *dli_sname;
82     void *dli_saddr;
83 } Dl_info;
84 #endif
85 
86 // C interfaces of gwp_asan provided by LLVM side.
87 extern void init_gwp_asan(void *init_options);
88 extern void* gwp_asan_malloc(size_t bytes);
89 extern void gwp_asan_free(void *mem);
90 extern bool gwp_asan_should_sample();
91 extern bool gwp_asan_pointer_is_mine(void *mem);
92 extern bool gwp_asan_has_free_mem();
93 extern size_t gwp_asan_get_size(void *mem);
94 extern void gwp_asan_disable();
95 extern void gwp_asan_enable();
96 extern void gwp_asan_iterate(void *base, size_t size,
97                                   void (*callback)(void* base, size_t size, void *arg), void *arg);
98 
99 
100 extern int dladdr(const void *addr, Dl_info *info);
101 
get_process_short_name(char * buf,size_t length)102 static char *get_process_short_name(char *buf, size_t length)
103 {
104     char *app = NULL;
105     int fd = open("/proc/self/cmdline", O_RDONLY);
106     if (fd != -1) {
107         ssize_t ret = read(fd, buf, length - 1);
108         if (ret != -1) {
109             buf[ret] = 0;
110             app = strrchr(buf, '/');
111             if (app) {
112                 app++;
113             } else {
114                 app = buf;
115             }
116             char *app_end = strchr(app, ':');
117             if (app_end) {
118                 *app_end = 0;
119             }
120         }
121         close(fd);
122     }
123     return app;
124 }
125 
is_gwp_asan_disable()126 bool is_gwp_asan_disable()
127 {
128     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.disable.all";
129     static CachedHandle para_handler = NULL;
130     if (para_handler == NULL) {
131         para_handler = CachedParameterCreate(para_name, "false");
132     }
133     const char *para_value = CachedParameterGet(para_handler);
134     if (para_value != NULL && strcmp(para_value, "true") == 0) {
135         return true;
136     }
137     return false;
138 }
139 
is_commercial()140 bool is_commercial()
141 {
142     char para_name[GWP_ASAN_NAME_LEN] = "const.logsystem.versiontype";
143     static CachedHandle para_handler = NULL;
144     if (para_handler == NULL) {
145         para_handler = CachedParameterCreate(para_name, "none");
146     }
147     const char *para_value = CachedParameterGet(para_handler);
148     if (para_value != NULL && strcmp(para_value, "commercial") == 0) {
149         return true;
150     }
151     return false;
152 }
153 
force_sample_process_by_env()154 bool force_sample_process_by_env()
155 {
156     char buf[GWP_ASAN_NAME_LEN];
157     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
158     if (!path) {
159         return false;
160     }
161     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.enable.app.";
162     strcat(para_name, path);
163     static CachedHandle app_enable_handle = NULL;
164     if (app_enable_handle == NULL) {
165         app_enable_handle = CachedParameterCreate(para_name, "false");
166     }
167     const char *param_value = CachedParameterGet(app_enable_handle);
168     if (param_value != NULL) {
169         if (strcmp(param_value, "true") == 0) {
170             return true;
171         }
172     }
173     return false;
174 }
175 
force_sample_alloctor_by_env()176 bool force_sample_alloctor_by_env()
177 {
178     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.sample.all";
179     static CachedHandle para_handler = NULL;
180     if (para_handler == NULL) {
181         para_handler = CachedParameterCreate(para_name, "false");
182     }
183     const char *para_value = CachedParameterGet(para_handler);
184     if (para_value != NULL && strcmp(para_value, "true") == 0) {
185         force_sample_alloctor = 1;
186         return true;
187     }
188     return false;
189 }
190 
should_sample_process()191 bool should_sample_process()
192 {
193 #ifdef OHOS_ENABLE_PARAMETER
194     if (force_sample_process_by_env()) {
195         return true;
196     }
197 #endif
198 
199     uint8_t random_value;
200     // If getting a random number using a non-blocking fails, the random value is incremented.
201     if (getrandom(&random_value, sizeof(random_value), GRND_RANDOM | GRND_NONBLOCK) == -1) {
202         random_value = previous_random_value + 1;
203         previous_random_value = random_value;
204     }
205 
206     return (random_value % process_sample_rate) == 0 ? true : false;
207 }
208 
209 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
210  * It is not signal-safe, do not call from signal handlers.
211  */
get_sample_parameter()212 const char *get_sample_parameter()
213 {
214     static char sample_param[GWP_ASAN_NAME_LEN];
215     snprintf(sample_param, GWP_ASAN_NAME_LEN, "%d:%d", SAMPLE_RATE, MAX_SIMULTANEOUS_ALLOCATIONS);
216     char buf[GWP_ASAN_NAME_LEN];
217     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
218     if (!path) {
219         MUSL_LOGW("[gwp_asan]: get_sample_parameter get process_name failed!");
220         return sample_param;
221     }
222     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.sample.app.";
223     strcat(para_name, path);
224     CachedHandle handle = CachedParameterCreate(para_name, "");
225     const char *param_value = CachedParameterGet(handle);
226     if (!param_value || strlen(param_value) == 0) {
227         return sample_param;
228     }
229     return param_value;
230 }
231 
232 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
233  * It is not signal-safe, do not call from signal handlers.
234  */
parse_sample_parameter(int * sample_rate,int * max_slot)235 void parse_sample_parameter(int *sample_rate, int *max_slot)
236 {
237     const int MAX_SLOT_PARAM_SIZE = 20000;
238     const int PARSE_FULL_PARAM = 2;
239     const int PARSE_SINGLE_PARAM = 1;
240     if (!sample_rate || !max_slot) {
241         MUSL_LOGW("[gwp_asan]: parse_sample_parameter invalid pointer!");
242         return;
243     }
244     const char *param_value = get_sample_parameter();
245     int parsed_rate = 0, parsed_slot = 0;
246     char extra_char;
247     if (sscanf(param_value, "%d:%d%c", &parsed_rate, &parsed_slot, &extra_char) == PARSE_FULL_PARAM) {
248         if (parsed_rate < 0 || parsed_rate > INT_MAX || parsed_slot < 0 ||
249             (!gwp_asan_thirdparty_telemetry && parsed_slot > MAX_SLOT_PARAM_SIZE)) {
250             MUSL_LOGW("[gwp_asan]: parse_sample_parameter abnormal rate and slot.");
251             return;
252         }
253         *sample_rate = parsed_rate;
254         *max_slot = parsed_slot;
255     } else if (sscanf(param_value, "%d:%c", &parsed_rate, &extra_char) == PARSE_SINGLE_PARAM) {
256         if (parsed_rate < 0 || parsed_rate > INT_MAX) {
257             MUSL_LOGW("[gwp_asan]: parse_sample_parameter abnormal rate.");
258             return;
259         }
260         *sample_rate = parsed_rate;
261     } else if (sscanf(param_value, ":%d%c", &parsed_slot, &extra_char) == PARSE_SINGLE_PARAM) {
262         if (parsed_slot < 0 || (!gwp_asan_thirdparty_telemetry && parsed_slot > MAX_SLOT_PARAM_SIZE)) {
263             MUSL_LOGW("[gwp_asan]: parse_sample_parameter abnormal slot.");
264             return;
265         }
266         *max_slot = parsed_slot;
267     } else {
268         MUSL_LOGW("[gwp_asan]: parse_sample_parameter invalid format: %{public}s.", param_value);
269     }
270 }
271 
272 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
273  * It is not signal-safe, do not call from signal handlers.
274  */
get_min_size_parameter()275 int get_min_size_parameter()
276 {
277     char buf[GWP_ASAN_NAME_LEN];
278     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
279     if (!path) {
280         MUSL_LOGW("[gwp_asan]: get_min_size_parameter get process_name failed!");
281         return MIN_SAMPLE_SIZE;
282     }
283     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.app.min_size.";
284     strcat(para_name, path);
285     CachedHandle handle = CachedParameterCreate(para_name, "0");
286     const char *param_value = CachedParameterGet(handle);
287     if (!param_value || strlen(param_value) == 0) {
288         return MIN_SAMPLE_SIZE;
289     }
290     char *endPtr = NULL;
291     long min_size = strtol(param_value, &endPtr, 10);
292     if (*endPtr != '\0' || min_size < 0 || min_size > INT_MAX) {
293         return MIN_SAMPLE_SIZE;
294     }
295     return (int)min_size;
296 }
297 
298 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
299  * It is not signal-safe, do not call from signal handlers.
300  */
get_library_parameter()301 const char *get_library_parameter()
302 {
303     char buf[GWP_ASAN_NAME_LEN];
304     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
305     if (!path) {
306         MUSL_LOGW("[gwp_asan]: get_library_parameter get process_name failed!");
307         return WHITE_LIST_PATH;
308     }
309     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.app.library.";
310     strcat(para_name, path);
311     CachedHandle handle = CachedParameterCreate(para_name, "");
312     const char *param_value = CachedParameterGet(handle);
313     if (!param_value || strlen(param_value) == 0) {
314         return WHITE_LIST_PATH;
315     }
316     return param_value;
317 }
318 
319 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
320  * It is not signal-safe, do not call from signal handlers.
321  */
get_gray_begin_parameter()322 uint64_t get_gray_begin_parameter()
323 {
324     char buf[GWP_ASAN_NAME_LEN];
325     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
326     if (!path) {
327         MUSL_LOGW("[gwp_asan]: get_gray_begin_parameter get process_name failed!");
328         return 0;
329     }
330     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.gray_begin.app.";
331     strcat(para_name, path);
332     CachedHandle handle = CachedParameterCreate(para_name, "");
333     const char *param_value = CachedParameterGet(handle);
334     if (!param_value || strlen(param_value) == 0) {
335         return 0;
336     }
337     char *endPtr = NULL;
338     unsigned long long gray_begin = strtoull(param_value, &endPtr, 10);
339     if (*endPtr != '\0' || gray_begin < 0 || gray_begin > ULLONG_MAX) {
340         MUSL_LOGW("[gwp_asan]: invalid gray_begin value: %s", param_value);
341         return 0;
342     }
343     return (uint64_t)gray_begin;
344 }
345 
346 /* This function is used for gwp_asan to get telemetry param to init gwp_asan.
347  * It is not signal-safe, do not call from signal handlers.
348  */
get_gray_days_parameter()349 uint64_t get_gray_days_parameter()
350 {
351     char buf[GWP_ASAN_NAME_LEN];
352     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
353     if (!path) {
354         MUSL_LOGW("[gwp_asan]: get_gray_days_parameter get process_name failed!");
355         return 0;
356     }
357     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.gray_days.app.";
358     strcat(para_name, path);
359     CachedHandle handle = CachedParameterCreate(para_name, "");
360     const char *param_value = CachedParameterGet(handle);
361     if (!param_value || strlen(param_value) == 0) {
362         return 0;
363     }
364     char *endPtr = NULL;
365     unsigned long long gray_days = strtoull(param_value, &endPtr, 10);
366     if (*endPtr != '\0' || gray_days < 0 || gray_days > ULLONG_MAX) {
367         MUSL_LOGW("[gwp_asan]: invalid gray_days value: %s", param_value);
368         return 0;
369     }
370     return (uint64_t)gray_days * SECONDS_PER_DAY;
371 }
372 
373 #define ASAN_LOG_LIB "libasan_logger.z.so"
374 static void (*WriteSanitizerLog)(char*, size_t, char*);
375 static void* handle = NULL;
376 static bool try_load_asan_logger = false;
377 static pthread_mutex_t gwpasan_mutex = PTHREAD_MUTEX_INITIALIZER;
378 
gwp_asan_printf(const char * fmt,...)379 void gwp_asan_printf(const char *fmt, ...)
380 {
381     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.log.path";
382     static CachedHandle para_handler = NULL;
383     if (para_handler == NULL) {
384         para_handler = CachedParameterCreate(para_name, "default");
385     }
386     const char *para_value = CachedParameterGet(para_handler);
387     if (strcmp(para_value, "file") == 0) {
388         char process_short_name[GWP_ASAN_NAME_LEN];
389         char *path = get_process_short_name(process_short_name, GWP_ASAN_NAME_LEN);
390         if (!path) {
391             MUSL_LOGW("[gwp_asan]: get_process_short_name failed!");
392             return;
393         }
394         char log_path[GWP_ASAN_NAME_LEN];
395         snprintf(log_path, GWP_ASAN_NAME_LEN, "%s%s.%s.%d.log", GWP_ASAN_LOG_DIR, GWP_ASAN_LOG_TAG, path, getpid());
396         FILE *fp = fopen(log_path, "a+");
397         if (!fp) {
398             MUSL_LOGW("[gwp_asan]: %{public}s fopen %{public}s failed!", path, log_path);
399             return;
400         } else {
401             MUSL_LOGW("[gwp_asan]: %{public}s fopen %{public}s succeed.", path, log_path);
402         }
403         va_list ap;
404         va_start(ap, fmt);
405         int result = vfprintf(fp, fmt, ap);
406         va_end(ap);
407         fclose(fp);
408         if (result < 0) {
409             MUSL_LOGW("[gwp_asan] %{public}s write log failed!\n", path);
410         }
411         return;
412     }
413     if (strcmp(para_value, "default") == 0) {
414         va_list ap;
415         va_start(ap, fmt);
416         char log_buffer[PATH_MAX];
417         int result = vsnprintf(log_buffer, PATH_MAX, fmt, ap);
418         va_end(ap);
419         if (result < 0) {
420             MUSL_LOGW("[gwp_asan] write log failed!\n");
421         }
422         if (WriteSanitizerLog != NULL) {
423             WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
424             return;
425 	}
426         if (try_load_asan_logger) {
427             return;
428         }
429         pthread_mutex_lock(&gwpasan_mutex);
430         if (WriteSanitizerLog != NULL) {
431             WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
432             pthread_mutex_unlock(&gwpasan_mutex);
433             return;
434         }
435         if (!try_load_asan_logger && handle == NULL) {
436             handle = dlopen(ASAN_LOG_LIB, RTLD_LAZY);
437 	    if (handle == NULL) {
438                 pthread_mutex_unlock(&gwpasan_mutex);
439                 return;
440             }
441             try_load_asan_logger = true;
442             *(void**)(&WriteSanitizerLog) = dlsym(handle, "WriteSanitizerLog");
443             if (WriteSanitizerLog != NULL) {
444                 WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
445             }
446         }
447         pthread_mutex_unlock(&gwpasan_mutex);
448         return;
449     }
450     if (strcmp(para_value, "stdout") == 0) {
451         va_list ap;
452         va_start(ap, fmt);
453         int result = vfprintf(stdout, fmt, ap);
454         va_end(ap);
455         if (result < 0) {
456             MUSL_LOGW("[gwp_asan] write log failed!\n");
457         }
458         return;
459     }
460 }
461 
gwp_asan_printf_backtrace(uintptr_t * trace_buffer,size_t trace_length,printf_t gwp_asan_printf)462 void gwp_asan_printf_backtrace(uintptr_t *trace_buffer, size_t trace_length, printf_t gwp_asan_printf)
463 {
464     if (trace_length == 0) {
465         gwp_asan_printf("It dosen't see any stack trace!\n");
466     }
467     for (size_t i = 0; i < trace_length; i++) {
468         if (trace_buffer[i]) {
469             Dl_info info;
470             if (dladdr(trace_buffer[i], &info)) {
471                 size_t offset = trace_buffer[i] - (uintptr_t)info.dli_fbase;
472                 gwp_asan_printf("  #%zu %p (%s+%p)\n", i, trace_buffer[i], info.dli_fname, offset);
473             } else {
474                 gwp_asan_printf("  #%zu %p\n", i, trace_buffer[i]);
475             }
476         }
477     }
478     gwp_asan_printf("\n");
479 }
480 
481 // Strip pc because pc may have been protected by pac(Pointer Authentication) when build with "-mbranch-protection".
strip_pac_pc(size_t ptr)482 size_t strip_pac_pc(size_t ptr)
483 {
484 #if defined(MUSL_AARCH64_ARCH)
485     register size_t x30 __asm__("x30") = ptr;
486     // "xpaclri" is a NOP on pre armv8.3-a arch.
487     __asm__ volatile("xpaclri" : "+r"(x30));
488     return x30;
489 #else
490     return ptr;
491 #endif
492 }
493 
494 /* This function is used for gwp_asan to record the call stack when allocate and deallocate.
495  * So we implemented a fast unwind function by using fp.
496  * The unwind process may stop because the value of fp is incorrect(fp was not saved on the stack due to optimization)
497  * We can build library with "-fno-omit-frame-pointer" to get a more accurate call stack.
498  * The basic unwind principle is as follows:
499  * Stack: func1->func2->func3
500  * --------------------| [Low Adress]
501  * |   fp      |       |-------->|
502  * |   lr      | func3 |         |
503  * |   ......  |       |         |
504  * --------------------|<--------|
505  * |   fp      |       |-------->|
506  * |   lr      | func2 |         |
507  * |   ......  |       |         |
508  * --------------------|         |
509  * |   fp      |       |<--------|
510  * |   lr      | func1 |
511  * |   ......  |       |
512  * --------------------| [High Address]
513  */
run_unwind(size_t * frame_buf,size_t num_frames,size_t max_record_stack,size_t current_frame_addr)514 GWP_ASAN_NO_ADDRESS size_t run_unwind(size_t *frame_buf,
515                                       size_t num_frames,
516                                       size_t max_record_stack,
517                                       size_t current_frame_addr)
518 {
519     size_t stack_end = (size_t)(__pthread_self()->stack);
520     size_t prev_fp = 0;
521     size_t prev_lr = 0;
522     while (true) {
523         unwind_info *frame = (unwind_info*)(current_frame_addr);
524         GWP_ASAN_LOGD("[gwp_asan] unwind info:%{public}d cur:%{public}p, end:%{public}p fp:%{public}p lr:%{public}p \n",
525                       num_frames, current_frame_addr, stack_end, frame->fp, frame->lr);
526         size_t stripped_lr = strip_pac_pc(frame->lr);
527         if (!stripped_lr) {
528             break;
529         }
530         if (num_frames < max_record_stack) {
531             frame_buf[num_frames] = stripped_lr - 4;
532         }
533         ++num_frames;
534         if (frame->fp == prev_fp || frame->lr == prev_lr || frame->fp < current_frame_addr + sizeof(unwind_info) ||
535             frame->fp >= stack_end || frame->fp % sizeof(void*) != 0) {
536             break;
537         }
538         prev_fp = frame->fp;
539         prev_lr = frame->lr;
540         current_frame_addr = frame->fp;
541     }
542 
543     return num_frames;
544 }
545 
libc_gwp_asan_unwind_fast(size_t * frame_buf,size_t max_record_stack)546 GWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_fast(size_t *frame_buf, size_t max_record_stack)
547 {
548     size_t current_frame_addr = __builtin_frame_address(0);
549     size_t num_frames = 0;
550 
551     return run_unwind(frame_buf, num_frames, max_record_stack, current_frame_addr);
552 }
553 
554 // Get fault address from sigchain in signal handler
libc_gwp_asan_unwind_segv(size_t * frame_buf,size_t max_record_stack,void * signal_context)555 GWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_segv(size_t *frame_buf, size_t max_record_stack, void *signal_context)
556 {
557     ucontext_t *context = (ucontext_t *)signal_context;
558     size_t current_frame_addr = get_frame_pointer(context);
559     size_t pc = get_pc(context);
560     size_t num_frames = 0;
561 
562     if (current_frame_addr && pc) {
563         frame_buf[num_frames] = strip_pac_pc(pc);
564         ++num_frames;
565     }
566     return run_unwind(frame_buf, num_frames, max_record_stack, current_frame_addr);
567 }
568 
init_gwp_asan_by_telemetry(int * sample_rate,int * max_simultaneous_allocations,int * min_sample_size,const char ** white_list_path)569 void init_gwp_asan_by_telemetry(int *sample_rate, int *max_simultaneous_allocations,
570                                 int *min_sample_size, const char **white_list_path)
571 {
572     uint64_t gray_begin = get_gray_begin_parameter();
573     uint64_t gray_days = get_gray_days_parameter();
574     uint64_t now = (uint64_t)time(NULL);
575     if (gray_begin > 0) {
576         if (now - gray_begin > gray_days) {
577             MUSL_LOGW("[gwp_asan]: init_gwp_asan_by_telemetry thirdparty telemetry expired.");
578             return;
579         }
580         gwp_asan_thirdparty_telemetry = true;
581     } else {
582         *min_sample_size = get_min_size_parameter();
583         *white_list_path = get_library_parameter();
584     }
585     parse_sample_parameter(sample_rate, max_simultaneous_allocations);
586 }
587 
init_gwp_asan_process(gwp_asan_option gwp_asan_option)588 bool init_gwp_asan_process(gwp_asan_option gwp_asan_option)
589 {
590     char buf[GWP_ASAN_NAME_LEN];
591     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
592     if (!path) {
593         return false;
594     }
595 
596     MUSL_LOGW("[gwp_asan]: %{public}d %{public}s gwp_asan initializing.\n", getpid(), path);
597     init_gwp_asan((void*)&gwp_asan_option);
598     gwp_asan_initialized = true;
599     MUSL_LOGW("[gwp_asan]: %{public}d %{public}s gwp_asan initialized.\n", getpid(), path);
600     return true;
601 }
602 
may_init_gwp_asan(bool force_init)603 bool may_init_gwp_asan(bool force_init)
604 {
605     int sample_rate = SAMPLE_RATE;
606     int max_simultaneous_allocations = MAX_SIMULTANEOUS_ALLOCATIONS;
607     int min_sample_size = MIN_SAMPLE_SIZE;
608     const char *white_list_path = WHITE_LIST_PATH;
609 
610     GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan enter force_init:%{public}d.\n", force_init);
611     if (gwp_asan_initialized) {
612         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan_initialized is true.\n");
613         return false;
614     }
615 #ifdef OHOS_ENABLE_PARAMETER
616     // Turn off gwp_asan.
617     if (GWP_ASAN_PREDICT_FALSE(is_gwp_asan_disable())) {
618         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan is disable by env.\n");
619         return false;
620     }
621 #endif
622 
623     if (!force_init && !should_sample_process()) {
624         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because sample not hit.\n");
625         return false;
626     }
627 
628 #ifdef OHOS_ENABLE_PARAMETER
629     // All memory allocations use gwp_asan.
630     force_sample_alloctor_by_env();
631     init_gwp_asan_by_telemetry(&sample_rate, &max_simultaneous_allocations,
632         &min_sample_size, &white_list_path);
633     MUSL_LOGW("[gwp_asan]: sample_rate:%{public}d, slot:%{public}d, "\
634         "min_sample_size:%{public}d, white_list_path:%{public}s",
635         sample_rate, max_simultaneous_allocations, min_sample_size, white_list_path);
636 #endif
637 
638     gwp_asan_option gwp_asan_option = {
639         .enable = true,
640         .install_fork_handlers = true,
641         .install_signal_handlers = true,
642         .max_simultaneous_allocations = max_simultaneous_allocations,
643         .sample_rate = sample_rate,
644         .backtrace = libc_gwp_asan_unwind_fast,
645         .gwp_asan_printf = gwp_asan_printf,
646         .printf_backtrace = gwp_asan_printf_backtrace,
647         .segv_backtrace = libc_gwp_asan_unwind_segv,
648         .min_sample_size = min_sample_size,
649         .white_list_path = white_list_path
650     };
651 
652     return init_gwp_asan_process(gwp_asan_option);
653 }
654 
init_gwp_asan_by_libc(bool force_init)655 bool init_gwp_asan_by_libc(bool force_init)
656 {
657 #ifdef OHOS_ENABLE_PARAMETER
658     if (is_commercial()) {
659         return false;
660     }
661 #endif
662     char buf[GWP_ASAN_NAME_LEN];
663     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
664     if (!path) {
665         return false;
666     }
667     // We don't sample appspawn, and the chaild process decides whether to sample or not.
668     if (strcmp(path, "appspawn") == 0 || strcmp(path, "sh") == 0) {
669         return false;
670     }
671     return may_init_gwp_asan(force_init);
672 }
673 
get_platform_gwp_asan_tls_slot()674 void* get_platform_gwp_asan_tls_slot()
675 {
676     return (void*)(&(__pthread_self()->gwp_asan_tls));
677 }
678 
libc_gwp_asan_malloc(size_t bytes)679 void* libc_gwp_asan_malloc(size_t bytes)
680 {
681     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
682         return MuslFunc(malloc)(bytes);
683     }
684     void *res = NULL;
685     if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
686         res = gwp_asan_malloc(bytes);
687         if (res != NULL) {
688             return res;
689         }
690     }
691     return MuslFunc(malloc)(bytes);
692 }
693 
libc_gwp_asan_calloc(size_t nmemb,size_t size)694 void* libc_gwp_asan_calloc(size_t nmemb, size_t size)
695 {
696     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
697         return MuslFunc(calloc)(nmemb, size);
698     }
699 
700     if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
701         size_t total_bytes;
702         void* result = NULL;
703         if (!__builtin_mul_overflow(nmemb, size, &total_bytes)) {
704             GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc nmemb:%{public}d size:%{public}d.\n", nmemb, size);
705             result = gwp_asan_malloc(total_bytes);
706             if (result != NULL) {
707                 return result;
708             }
709         }
710     }
711 
712     return MuslFunc(calloc)(nmemb, size);
713 }
714 
libc_gwp_asan_realloc(void * ptr,size_t size)715 void* libc_gwp_asan_realloc(void *ptr, size_t size)
716 {
717     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
718         return MuslFunc(realloc)(ptr, size);
719     }
720 
721     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(ptr))) {
722         GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc ptr:%{public}p size:%{public}d.\n", ptr, size);
723         if (GWP_ASAN_PREDICT_FALSE(size == 0)) {
724             gwp_asan_free(ptr);
725             return NULL;
726         }
727 
728         void* new_addr = gwp_asan_malloc(size);
729         if (new_addr != NULL) {
730             size_t old_size = gwp_asan_get_size(ptr);
731             memcpy(new_addr, ptr, (size < old_size) ? size : old_size);
732             gwp_asan_free(ptr);
733             return new_addr;
734         } else {
735             // Use the default allocator if gwp malloc failed.
736             void* addr_of_default_allocator = MuslFunc(malloc)(size);
737             if (addr_of_default_allocator != NULL) {
738                 size_t old_size = gwp_asan_get_size(ptr);
739                 memcpy(addr_of_default_allocator, ptr, (size < old_size) ? size : old_size);
740                 gwp_asan_free(ptr);
741                 return addr_of_default_allocator;
742             } else {
743                 return NULL;
744             }
745         }
746     }
747     return MuslFunc(realloc)(ptr, size);
748 }
749 
libc_gwp_asan_free(void * addr)750 void libc_gwp_asan_free(void *addr)
751 {
752     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
753         return MuslFunc(free)(addr);
754     }
755     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
756         return gwp_asan_free(addr);
757     }
758     return MuslFunc(free)(addr);
759 }
760 
libc_gwp_asan_malloc_usable_size(void * addr)761 size_t libc_gwp_asan_malloc_usable_size(void *addr)
762 {
763     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
764         return MuslMalloc(malloc_usable_size)(addr);
765     }
766     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
767         return gwp_asan_get_size(addr);
768     }
769     return MuslMalloc(malloc_usable_size)(addr);
770 }
771 
libc_gwp_asan_malloc_iterate(void * base,size_t size,void (* callback)(uintptr_t base,size_t size,void * arg),void * arg)772 void libc_gwp_asan_malloc_iterate(void *base, size_t size,
773                              void (*callback)(uintptr_t base, size_t size, void *arg), void *arg)
774 {
775     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
776         return;
777     }
778     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(base))) {
779         return gwp_asan_iterate(base, size, callback, arg);
780     }
781     return;
782 }
783 
libc_gwp_asan_malloc_disable()784 void libc_gwp_asan_malloc_disable()
785 {
786     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
787         return;
788     }
789 
790     return gwp_asan_disable();
791 }
792 
libc_gwp_asan_malloc_enable()793 void libc_gwp_asan_malloc_enable()
794 {
795     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
796         return;
797     }
798 
799     return gwp_asan_enable();
800 }
801 
libc_gwp_asan_has_free_mem()802 bool libc_gwp_asan_has_free_mem()
803 {
804     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
805         return false;
806     }
807     gwp_asan_disable();
808     int res = gwp_asan_has_free_mem();
809     gwp_asan_enable();
810     return res;
811 }
libc_gwp_asan_ptr_is_mine(void * addr)812 bool libc_gwp_asan_ptr_is_mine(void *addr)
813 {
814     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
815         return false;
816     }
817 
818     return gwp_asan_pointer_is_mine(addr);
819 }
820 #else
821 #include <stdbool.h>
822 
823 // Used for appspawn.
may_init_gwp_asan(bool force_init)824 bool may_init_gwp_asan(bool force_init)
825 {
826     return false;
827 }
828 #endif
829