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