/** * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "common.h" #include "memutils_track.h" void memutils_init(void) { real_memalign = dlsym(RTLD_NEXT, "memalign"); if (!real_memalign) { return; } real_malloc = dlsym(RTLD_NEXT, "malloc"); if (!real_malloc) { return; } real_free = dlsym(RTLD_NEXT, "free"); if (!real_free) { return; } #ifdef CHECK_MEMORY_LEAK real_calloc = dlsym(RTLD_NEXT, "calloc"); if (!real_calloc) { return; } atexit(exit_vulnerable_if_memory_leak_detected); #endif /* CHECK_MEMORY_LEAK */ s_memutils_initialized = true; } void *memalign(size_t alignment, size_t size) { if (!s_memutils_initialized) { memutils_init(); } void* mem_ptr = real_memalign(alignment, size); #ifdef CHECK_UNINITIALIZED_MEMORY if(mem_ptr) { memset(mem_ptr, INITIAL_VAL, size); } #endif /* CHECK_UNINITIALIZED_MEMORY */ #ifdef ENABLE_SELECTIVE_OVERLOADING if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) { return mem_ptr; } #endif /* ENABLE_SELECTIVE_OVERLOADING */ if (!is_tracking_required(size)) { return mem_ptr; } if (s_allocation_index >= MAX_ENTRIES) { return mem_ptr; } s_allocation_list[s_allocation_index].mem_ptr = mem_ptr; s_allocation_list[s_allocation_index].mem_size = size; ++s_allocation_index; return mem_ptr; } void *malloc(size_t size) { if (!s_memutils_initialized) { memutils_init(); } void* mem_ptr = real_malloc(size); #ifdef CHECK_UNINITIALIZED_MEMORY if(mem_ptr) { memset(mem_ptr, INITIAL_VAL, size); } #endif /* CHECK_UNINITIALIZED_MEMORY */ #ifdef ENABLE_SELECTIVE_OVERLOADING if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) { return mem_ptr; } #endif /* ENABLE_SELECTIVE_OVERLOADING */ if (!is_tracking_required(size)) { return mem_ptr; } if (s_allocation_index >= MAX_ENTRIES) { return mem_ptr; } s_allocation_list[s_allocation_index].mem_ptr = mem_ptr; s_allocation_list[s_allocation_index].mem_size = size; ++s_allocation_index; return mem_ptr; } void free(void *ptr) { if (!s_memutils_initialized) { memutils_init(); } if (ptr) { for (int i = 0; i < s_allocation_index; ++i) { if (ptr == s_allocation_list[i].mem_ptr) { real_free(ptr); memset(&s_allocation_list[i], 0, sizeof(allocated_memory_struct)); return; } } } return real_free(ptr); } #ifdef CHECK_MEMORY_LEAK void *calloc(size_t nitems, size_t size) { if (!s_memutils_initialized) { memutils_init(); } void* mem_ptr = real_calloc(nitems, size); #ifdef ENABLE_SELECTIVE_OVERLOADING if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) { return mem_ptr; } #endif /* ENABLE_SELECTIVE_OVERLOADING */ if (!is_tracking_required((nitems *size))) { return mem_ptr; } if (s_allocation_index >= MAX_ENTRIES) { return mem_ptr; } s_allocation_list[s_allocation_index].mem_ptr = mem_ptr; s_allocation_list[s_allocation_index].mem_size = nitems * size; ++s_allocation_index; return mem_ptr; } void exit_vulnerable_if_memory_leak_detected(void) { bool memory_leak_detected = false; for (int i = 0; i < s_allocation_index; ++i) { if (s_allocation_list[i].mem_ptr) { real_free(s_allocation_list[i].mem_ptr); memset(&s_allocation_list[i], 0, sizeof(allocated_memory_struct)); memory_leak_detected = true; } } if(memory_leak_detected) { exit(EXIT_VULNERABLE); } return; } #endif /* CHECK_MEMORY_LEAK */ #ifdef CHECK_UNINITIALIZED_MEMORY bool is_memory_uninitialized() { for (int i = 0; i < s_allocation_index; ++i) { uint8_t *mem_ptr = s_allocation_list[i].mem_ptr; size_t mem_size = s_allocation_list[i].mem_size; if (mem_ptr) { #ifdef CHECK_FOUR_BYTES if(mem_size > (2 * sizeof(uint32_t))) { uint8_t *mem_ptr_start = (uint8_t *) s_allocation_list[i].mem_ptr; uint8_t *mem_ptr_end = (uint8_t *) s_allocation_list[i].mem_ptr + mem_size - 1; for (size_t j = 0; j < sizeof(uint32_t); ++j) { if (*mem_ptr_start++ == INITIAL_VAL) { return true; } if (*mem_ptr_end-- == INITIAL_VAL) { return true; } } continue; } #endif /* CHECK_FOUR_BYTES */ for (size_t j = 0; j < mem_size; ++j) { if (*mem_ptr++ == INITIAL_VAL) { return true; } } } } return false; } #endif /* CHECK_UNINITIALIZED_MEMORY */