1 /**
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define _GNU_SOURCE
17 #include <sys/types.h>
18 #include <sys/wait.h>
19 #include <sys/mman.h>
20 #include <stdlib.h>
21 #include <dlfcn.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <signal.h>
25 #include "memutils.h"
26
exit_handler(void)27 void exit_handler(void) {
28 size_t page_size = getpagesize();
29 for (int i = 0; i < s_mem_map_index; i++) {
30 if (NULL != s_mem_map[i].start_ptr) {
31 ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
32 (s_mem_map[i].num_pages * page_size));
33 }
34 }
35 #ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
36 for (int i = 0; i < MAX_ENTRIES; i++) {
37 if (NULL != s_free_list[i].start_ptr) {
38 ENABLE_MEM_ACCESS(s_free_list[i].start_ptr,
39 (s_free_list[i].num_pages * page_size));
40 real_free(s_free_list[i].start_ptr);
41 memset(&s_free_list[i], 0, sizeof(map_struct_t));
42 }
43 }
44 #endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
45 }
46
sigsegv_handler(int signum,siginfo_t * info,void * context)47 void sigsegv_handler(int signum, siginfo_t *info, void* context) {
48 exit_handler();
49 (*old_sa.sa_sigaction)(signum, info, context);
50 }
51
sighandler_init(void)52 void sighandler_init(void) {
53 sigemptyset(&new_sa.sa_mask);
54 new_sa.sa_flags = SA_SIGINFO;
55 new_sa.sa_sigaction = sigsegv_handler;
56 sigaction(SIGSEGV, &new_sa, &old_sa);
57 }
58
memutils_init(void)59 void memutils_init(void) {
60 real_memalign = dlsym(RTLD_NEXT, "memalign");
61 if (NULL == real_memalign) {
62 return;
63 }
64 real_calloc = dlsym(RTLD_NEXT, "calloc");
65 if (NULL == real_calloc) {
66 return;
67 }
68 real_malloc = dlsym(RTLD_NEXT, "malloc");
69 if (NULL == real_malloc) {
70 return;
71 }
72 real_realloc = dlsym(RTLD_NEXT, "realloc");
73 if (NULL == real_realloc) {
74 return;
75 }
76 real_free = dlsym(RTLD_NEXT, "free");
77 if (NULL == real_free) {
78 return;
79 }
80 memset(&s_mem_map, 0, MAX_ENTRIES * sizeof(map_struct_t));
81 sighandler_init();
82 atexit(exit_handler);
83 s_memutils_initialized = 1;
84 }
85
memalign(size_t alignment,size_t size)86 void *memalign(size_t alignment, size_t size) {
87 if (s_memutils_initialized == 0) {
88 memutils_init();
89 }
90 #ifdef ENABLE_SELECTIVE_OVERLOADING
91 if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) {
92 return real_memalign(alignment, size);
93 }
94 #endif /* ENABLE_SELECTIVE_OVERLOADING */
95 char* start_ptr;
96 char* mem_ptr;
97 size_t total_size;
98 size_t aligned_size = size;
99 size_t num_pages;
100 size_t page_size = getpagesize();
101
102 /* User specified alignment is not respected and is overridden by
103 * "new_alignment". This is required to catch OOB read when read offset is
104 * less than user specified alignment. "new_alignment" is derived based on
105 * size_t, and helps to avoid bus errors due to non-aligned memory.
106 * "new_alignment", whenever used, is checked to ensure sizeof(size_t)
107 * has returned proper value */
108 size_t new_alignment = sizeof(size_t);
109
110 if (s_mem_map_index == MAX_ENTRIES) {
111 return real_memalign(alignment, size);
112 }
113
114 if (alignment > page_size) {
115 return real_memalign(alignment, size);
116 }
117
118 if ((0 == page_size) || (0 == alignment) || (0 == size)
119 || (0 == new_alignment)) {
120 return real_memalign(alignment, size);
121 }
122 #ifdef CHECK_OVERFLOW
123 if (0 != (size % new_alignment)) {
124 aligned_size = size + (new_alignment - (size % new_alignment));
125 }
126 #endif
127
128 if (0 != (aligned_size % page_size)) {
129 num_pages = (aligned_size / page_size) + 2;
130 } else {
131 num_pages = (aligned_size / page_size) + 1;
132 }
133
134 total_size = (num_pages * page_size);
135 start_ptr = (char *) real_memalign(page_size, total_size);
136 #ifdef CHECK_OVERFLOW
137 #ifdef FORCE_UNALIGN
138 mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - size;
139 #else
140 mem_ptr = (char *) start_ptr + ((num_pages - 1) * page_size) - aligned_size;
141 #endif /* FORCE_UNALIGN */
142 DISABLE_MEM_ACCESS((start_ptr + ((num_pages - 1) * page_size)), page_size);
143 #endif /* CHECK_OVERFLOW */
144 #ifdef CHECK_UNDERFLOW
145 mem_ptr = (char *) start_ptr + page_size;
146 DISABLE_MEM_ACCESS(start_ptr, page_size);
147 #endif /* CHECK_UNDERFLOW */
148 s_mem_map[s_mem_map_index].start_ptr = start_ptr;
149 s_mem_map[s_mem_map_index].mem_ptr = mem_ptr;
150 s_mem_map[s_mem_map_index].num_pages = num_pages;
151 s_mem_map[s_mem_map_index].mem_size = size;
152 s_mem_map_index++;
153 memset(mem_ptr, INITIAL_VAL, size);
154 return mem_ptr;
155 }
156
malloc(size_t size)157 void *malloc(size_t size) {
158 if (s_memutils_initialized == 0) {
159 memutils_init();
160 }
161 #ifdef ENABLE_SELECTIVE_OVERLOADING
162 if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) {
163 return real_malloc(size);
164 }
165 #endif /* ENABLE_SELECTIVE_OVERLOADING */
166 return memalign(sizeof(size_t), size);
167 }
168
calloc(size_t nitems,size_t size)169 void *calloc(size_t nitems, size_t size) {
170 if (s_memutils_initialized == 0) {
171 memutils_init();
172 }
173 #ifdef ENABLE_SELECTIVE_OVERLOADING
174 if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) {
175 return real_calloc(nitems, size);
176 }
177 #endif /* ENABLE_SELECTIVE_OVERLOADING */
178 void *ptr = memalign(sizeof(size_t), (nitems * size));
179 if (ptr)
180 memset(ptr, 0, (nitems * size));
181 return ptr;
182 }
183
realloc(void * ptr,size_t size)184 void *realloc(void *ptr, size_t size) {
185 if (s_memutils_initialized == 0) {
186 memutils_init();
187 }
188 #ifdef ENABLE_SELECTIVE_OVERLOADING
189 if ((enable_selective_overload & ENABLE_REALLOC_CHECK) != ENABLE_REALLOC_CHECK) {
190 return real_realloc(ptr, size);
191 }
192 #endif /* ENABLE_SELECTIVE_OVERLOADING */
193 if (ptr != NULL) {
194 int i = 0;
195 for (i = 0; i < s_mem_map_index; i++) {
196 if (ptr == s_mem_map[i].mem_ptr) {
197 void* temp = malloc(size);
198 if (temp == NULL) {
199 return NULL;
200 }
201 if (s_mem_map[i].mem_size > size) {
202 memcpy(temp, ptr, size);
203 } else {
204 memcpy(temp, ptr, s_mem_map[i].mem_size);
205 }
206 free(s_mem_map[i].mem_ptr);
207 return temp;
208 }
209 }
210 }
211 return real_realloc(ptr, size);
212 }
213
free(void * ptr)214 void free(void *ptr) {
215 if (s_memutils_initialized == 0) {
216 memutils_init();
217 }
218 #ifdef ENABLE_SELECTIVE_OVERLOADING
219 if ((enable_selective_overload & ENABLE_FREE_CHECK) != ENABLE_FREE_CHECK) {
220 return real_free(ptr);
221 }
222 #endif /* ENABLE_SELECTIVE_OVERLOADING */
223 if (ptr != NULL) {
224 int i = 0;
225 size_t page_size = getpagesize();
226 for (i = 0; i < s_mem_map_index; i++) {
227 if (ptr == s_mem_map[i].mem_ptr) {
228 #ifdef CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE
229 s_free_list[s_free_write_index].start_ptr =
230 s_mem_map[i].start_ptr;
231 s_free_list[s_free_write_index].mem_ptr = s_mem_map[i].mem_ptr;
232 s_free_list[s_free_write_index].num_pages =
233 s_mem_map[i].num_pages;
234 s_free_list[s_free_write_index].mem_size = s_mem_map[i].mem_size;
235 s_free_write_index++;
236 s_free_list_size += s_mem_map[i].mem_size;
237 DISABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
238 (s_mem_map[i].num_pages * page_size));
239 memset(&s_mem_map[i], 0, sizeof(map_struct_t));
240 while (s_free_list_size > CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE) {
241 ENABLE_MEM_ACCESS(
242 s_free_list[s_free_read_index].start_ptr,
243 (s_free_list[s_free_read_index].num_pages * page_size));
244 real_free(s_free_list[s_free_read_index].start_ptr);
245 s_free_list_size -= s_free_list[s_free_read_index].mem_size;
246 memset(&s_free_list[s_free_read_index], 0,
247 sizeof(map_struct_t));
248 s_free_read_index++;
249 if ((s_free_read_index == MAX_ENTRIES)
250 || (s_free_read_index >= s_free_write_index)) {
251 break;
252 }
253 }
254 return;
255 #else
256 ENABLE_MEM_ACCESS(s_mem_map[i].start_ptr,
257 (s_mem_map[i].num_pages * page_size));
258 real_free(s_mem_map[i].start_ptr);
259 memset(&s_mem_map[i], 0, sizeof(map_struct_t));
260 return;
261 #endif /* CHECK_USE_AFTER_FREE_WITH_WINDOW_SIZE */
262 }
263 }
264 }
265 real_free(ptr);
266 return;
267 }
268