You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
263 lines
8.8 KiB
263 lines
8.8 KiB
/**
|
|
* Copyright (C) 2019 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 <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/mman.h>
|
|
#include <stdlib.h>
|
|
#include <dlfcn.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include "memutils.h"
|
|
|
|
void exit_handler(void) {
|
|
size_t page_size = getpagesize();
|
|
for (int i = 0; i < s_mem_map_index; i++) {
|
|
if (NULL != s_mem_map[i].start_ptr) {
|
|
ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
|
|
(s_mem_map[i].num_pages * page_size));
|
|
}
|
|
}
|
|
#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
|
|
for (int i = 0; i < MAX_ENTRIES; i++) {
|
|
if (NULL != s_free_list[i].start_ptr) {
|
|
ENABLE_MEM_ACCESS(s_free_list[i].start_ptr,
|
|
(s_free_list[i].num_pages * page_size));
|
|
real_free(s_free_list[i].start_ptr);
|
|
memset(&s_free_list[i], 0, sizeof(map_struct_t));
|
|
}
|
|
}
|
|
#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
|
|
}
|
|
|
|
void sigsegv_handler(int signum, siginfo_t *info, void* context) {
|
|
exit_handler();
|
|
(*old_sa.sa_sigaction)(signum, info, context);
|
|
}
|
|
|
|
void sighandler_init(void) {
|
|
sigemptyset(&new_sa.sa_mask);
|
|
new_sa.sa_flags = SA_SIGINFO;
|
|
new_sa.sa_sigaction = sigsegv_handler;
|
|
sigaction(SIGSEGV, &new_sa, &old_sa);
|
|
}
|
|
|
|
void memutils_init(void) {
|
|
real_memalign = dlsym(RTLD_NEXT, "memalign");
|
|
if (NULL == real_memalign) {
|
|
return;
|
|
}
|
|
#ifndef DISABLE_MALLOC_OVERLOADING
|
|
real_calloc = dlsym(RTLD_NEXT, "calloc");
|
|
if (NULL == real_calloc) {
|
|
return;
|
|
}
|
|
real_malloc = dlsym(RTLD_NEXT, "malloc");
|
|
if (NULL == real_malloc) {
|
|
return;
|
|
}
|
|
real_realloc = dlsym(RTLD_NEXT, "realloc");
|
|
if (NULL == real_realloc) {
|
|
return;
|
|
}
|
|
#endif /* DISABLE_MALLOC_OVERLOADING */
|
|
real_free = dlsym(RTLD_NEXT, "free");
|
|
if (NULL == real_free) {
|
|
return;
|
|
}
|
|
memset(&s_mem_map, 0, MAX_ENTRIES * sizeof(map_struct_t));
|
|
sighandler_init();
|
|
atexit(exit_handler);
|
|
s_memutils_initialized = 1;
|
|
}
|
|
|
|
void *memalign(size_t alignment, size_t size) {
|
|
if (s_memutils_initialized == 0) {
|
|
memutils_init();
|
|
}
|
|
#ifdef ENABLE_SELECTIVE_OVERLOADING
|
|
if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) {
|
|
return real_memalign(alignment, size);
|
|
}
|
|
#endif /* ENABLE_SELECTIVE_OVERLOADING */
|
|
char* start_ptr;
|
|
char* mem_ptr;
|
|
size_t total_size;
|
|
size_t aligned_size = size;
|
|
size_t num_pages;
|
|
size_t page_size = getpagesize();
|
|
|
|
if (s_mem_map_index == MAX_ENTRIES) {
|
|
return real_memalign(alignment, size);
|
|
}
|
|
|
|
if (alignment > page_size) {
|
|
return real_memalign(alignment, size);
|
|
}
|
|
|
|
if ((0 == page_size) || (0 == alignment) || (0 == size)) {
|
|
return real_memalign(alignment, size);
|
|
}
|
|
#ifdef CHECK_OVERFLOW
|
|
/* User specified alignment is not respected and is overridden by
|
|
* MINIMUM_ALIGNMENT. This is required to catch OOB read when read offset
|
|
* is less than user specified alignment. "MINIMUM_ALIGNMENT" helps to
|
|
* avoid bus errors due to non-aligned memory. */
|
|
if (0 != (size % MINIMUM_ALIGNMENT)) {
|
|
aligned_size = size + (MINIMUM_ALIGNMENT - (size % MINIMUM_ALIGNMENT));
|
|
}
|
|
#endif
|
|
|
|
if (0 != (aligned_size % page_size)) {
|
|
num_pages = (aligned_size / page_size) + 2;
|
|
} else {
|
|
num_pages = (aligned_size / page_size) + 1;
|
|
}
|
|
|
|
total_size = (num_pages * page_size);
|
|
start_ptr = (char *) real_memalign(page_size, total_size);
|
|
#ifdef CHECK_OVERFLOW
|
|
mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - aligned_size;
|
|
DISABLE_MEM_ACCESS((start_ptr + ((num_pages - 1) * page_size)), page_size);
|
|
#endif /* CHECK_OVERFLOW */
|
|
#ifdef CHECK_UNDERFLOW
|
|
mem_ptr = (char *) start_ptr + page_size;
|
|
DISABLE_MEM_ACCESS(start_ptr, page_size);
|
|
#endif /* CHECK_UNDERFLOW */
|
|
s_mem_map[s_mem_map_index].start_ptr = start_ptr;
|
|
s_mem_map[s_mem_map_index].mem_ptr = mem_ptr;
|
|
s_mem_map[s_mem_map_index].num_pages = num_pages;
|
|
s_mem_map[s_mem_map_index].mem_size = size;
|
|
s_mem_map_index++;
|
|
memset(mem_ptr, INITIAL_VAL, size);
|
|
return mem_ptr;
|
|
}
|
|
|
|
#ifndef DISABLE_MALLOC_OVERLOADING
|
|
void *malloc(size_t size) {
|
|
if (s_memutils_initialized == 0) {
|
|
memutils_init();
|
|
}
|
|
#ifdef ENABLE_SELECTIVE_OVERLOADING
|
|
if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) {
|
|
return real_malloc(size);
|
|
}
|
|
#endif /* ENABLE_SELECTIVE_OVERLOADING */
|
|
return memalign(MINIMUM_ALIGNMENT, size);
|
|
}
|
|
|
|
void *calloc(size_t nitems, size_t size) {
|
|
if (s_memutils_initialized == 0) {
|
|
memutils_init();
|
|
}
|
|
#ifdef ENABLE_SELECTIVE_OVERLOADING
|
|
if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) {
|
|
return real_calloc(nitems, size);
|
|
}
|
|
#endif /* ENABLE_SELECTIVE_OVERLOADING */
|
|
void *ptr = memalign(sizeof(size_t), (nitems * size));
|
|
if (ptr)
|
|
memset(ptr, 0, (nitems * size));
|
|
return ptr;
|
|
}
|
|
|
|
void *realloc(void *ptr, size_t size) {
|
|
if (s_memutils_initialized == 0) {
|
|
memutils_init();
|
|
}
|
|
#ifdef ENABLE_SELECTIVE_OVERLOADING
|
|
if ((enable_selective_overload & ENABLE_REALLOC_CHECK) != ENABLE_REALLOC_CHECK) {
|
|
return real_realloc(ptr, size);
|
|
}
|
|
#endif /* ENABLE_SELECTIVE_OVERLOADING */
|
|
if (ptr != NULL) {
|
|
int i = 0;
|
|
for (i = 0; i < s_mem_map_index; i++) {
|
|
if (ptr == s_mem_map[i].mem_ptr) {
|
|
void* temp = malloc(size);
|
|
if (temp == NULL) {
|
|
return NULL;
|
|
}
|
|
if (s_mem_map[i].mem_size > size) {
|
|
memcpy(temp, ptr, size);
|
|
} else {
|
|
memcpy(temp, ptr, s_mem_map[i].mem_size);
|
|
}
|
|
free(s_mem_map[i].mem_ptr);
|
|
return temp;
|
|
}
|
|
}
|
|
}
|
|
return real_realloc(ptr, size);
|
|
}
|
|
#endif /* DISABLE_MALLOC_OVERLOADING */
|
|
|
|
void free(void *ptr) {
|
|
if (s_memutils_initialized == 0) {
|
|
memutils_init();
|
|
}
|
|
#ifdef ENABLE_SELECTIVE_OVERLOADING
|
|
if ((enable_selective_overload & ENABLE_FREE_CHECK) != ENABLE_FREE_CHECK) {
|
|
return real_free(ptr);
|
|
}
|
|
#endif /* ENABLE_SELECTIVE_OVERLOADING */
|
|
if (ptr != NULL) {
|
|
int i = 0;
|
|
size_t page_size = getpagesize();
|
|
for (i = 0; i < s_mem_map_index; i++) {
|
|
if (ptr == s_mem_map[i].mem_ptr) {
|
|
#ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
|
|
s_free_list[s_free_write_index].start_ptr =
|
|
s_mem_map[i].start_ptr;
|
|
s_free_list[s_free_write_index].mem_ptr = s_mem_map[i].mem_ptr;
|
|
s_free_list[s_free_write_index].num_pages =
|
|
s_mem_map[i].num_pages;
|
|
s_free_list[s_free_write_index].mem_size = s_mem_map[i].mem_size;
|
|
s_free_write_index++;
|
|
s_free_list_size += s_mem_map[i].mem_size;
|
|
DISABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
|
|
(s_mem_map[i].num_pages * page_size));
|
|
memset(&s_mem_map[i], 0, sizeof(map_struct_t));
|
|
while (s_free_list_size > CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE) {
|
|
ENABLE_MEM_ACCESS(
|
|
s_free_list[s_free_read_index].start_ptr,
|
|
(s_free_list[s_free_read_index].num_pages * page_size));
|
|
real_free(s_free_list[s_free_read_index].start_ptr);
|
|
s_free_list_size -= s_free_list[s_free_read_index].mem_size;
|
|
memset(&s_free_list[s_free_read_index], 0,
|
|
sizeof(map_struct_t));
|
|
s_free_read_index++;
|
|
if ((s_free_read_index == MAX_ENTRIES)
|
|
|| (s_free_read_index >= s_free_write_index)) {
|
|
break;
|
|
}
|
|
}
|
|
return;
|
|
#else
|
|
ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
|
|
(s_mem_map[i].num_pages * page_size));
|
|
real_free(s_mem_map[i].start_ptr);
|
|
memset(&s_mem_map[i], 0, sizeof(map_struct_t));
|
|
return;
|
|
#endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
|
|
}
|
|
}
|
|
}
|
|
real_free(ptr);
|
|
return;
|
|
}
|