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