1 /**
2 * Copyright (C) 2020 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 <stdbool.h>
21 #include <stdlib.h>
22 #include <dlfcn.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include "common.h"
26 #include "memutils_track.h"
27
memutils_init(void)28 void memutils_init(void) {
29 real_memalign = dlsym(RTLD_NEXT, "memalign");
30 if (!real_memalign) {
31 return;
32 }
33 real_malloc = dlsym(RTLD_NEXT, "malloc");
34 if (!real_malloc) {
35 return;
36 }
37 real_free = dlsym(RTLD_NEXT, "free");
38 if (!real_free) {
39 return;
40 }
41
42 #ifdef CHECK_MEMORY_LEAK
43 real_calloc = dlsym(RTLD_NEXT, "calloc");
44 if (!real_calloc) {
45 return;
46 }
47 atexit(exit_vulnerable_if_memory_leak_detected);
48 #endif /* CHECK_MEMORY_LEAK */
49
50 s_memutils_initialized = true;
51 }
52
memalign(size_t alignment,size_t size)53 void *memalign(size_t alignment, size_t size) {
54 if (!s_memutils_initialized) {
55 memutils_init();
56 }
57 void* mem_ptr = real_memalign(alignment, size);
58
59 #ifdef CHECK_UNINITIALIZED_MEMORY
60 if(mem_ptr) {
61 memset(mem_ptr, INITIAL_VAL, size);
62 }
63 #endif /* CHECK_UNINITIALIZED_MEMORY */
64
65 #ifdef ENABLE_SELECTIVE_OVERLOADING
66 if ((enable_selective_overload & ENABLE_MEMALIGN_CHECK) != ENABLE_MEMALIGN_CHECK) {
67 return mem_ptr;
68 }
69 #endif /* ENABLE_SELECTIVE_OVERLOADING */
70
71 if (!is_tracking_required(size)) {
72 return mem_ptr;
73 }
74 if (s_allocation_index >= MAX_ENTRIES) {
75 return mem_ptr;
76 }
77 s_allocation_list[s_allocation_index].mem_ptr = mem_ptr;
78 s_allocation_list[s_allocation_index].mem_size = size;
79 ++s_allocation_index;
80 return mem_ptr;
81 }
82
malloc(size_t size)83 void *malloc(size_t size) {
84 if (!s_memutils_initialized) {
85 memutils_init();
86 }
87 void* mem_ptr = real_malloc(size);
88
89 #ifdef CHECK_UNINITIALIZED_MEMORY
90 if(mem_ptr) {
91 memset(mem_ptr, INITIAL_VAL, size);
92 }
93 #endif /* CHECK_UNINITIALIZED_MEMORY */
94
95 #ifdef ENABLE_SELECTIVE_OVERLOADING
96 if ((enable_selective_overload & ENABLE_MALLOC_CHECK) != ENABLE_MALLOC_CHECK) {
97 return mem_ptr;
98 }
99 #endif /* ENABLE_SELECTIVE_OVERLOADING */
100
101 if (!is_tracking_required(size)) {
102 return mem_ptr;
103 }
104 if (s_allocation_index >= MAX_ENTRIES) {
105 return mem_ptr;
106 }
107 s_allocation_list[s_allocation_index].mem_ptr = mem_ptr;
108 s_allocation_list[s_allocation_index].mem_size = size;
109 ++s_allocation_index;
110 return mem_ptr;
111 }
112
free(void * ptr)113 void free(void *ptr) {
114 if (!s_memutils_initialized) {
115 memutils_init();
116 }
117 if (ptr) {
118 for (int i = 0; i < s_allocation_index; ++i) {
119 if (ptr == s_allocation_list[i].mem_ptr) {
120 real_free(ptr);
121 memset(&s_allocation_list[i], 0,
122 sizeof(allocated_memory_struct));
123 return;
124 }
125 }
126 }
127 return real_free(ptr);
128 }
129
130 #ifdef CHECK_MEMORY_LEAK
calloc(size_t nitems,size_t size)131 void *calloc(size_t nitems, size_t size) {
132 if (!s_memutils_initialized) {
133 memutils_init();
134 }
135 void* mem_ptr = real_calloc(nitems, size);
136
137 #ifdef ENABLE_SELECTIVE_OVERLOADING
138 if ((enable_selective_overload & ENABLE_CALLOC_CHECK) != ENABLE_CALLOC_CHECK) {
139 return mem_ptr;
140 }
141 #endif /* ENABLE_SELECTIVE_OVERLOADING */
142
143 if (!is_tracking_required((nitems *size))) {
144 return mem_ptr;
145 }
146 if (s_allocation_index >= MAX_ENTRIES) {
147 return mem_ptr;
148 }
149 s_allocation_list[s_allocation_index].mem_ptr = mem_ptr;
150 s_allocation_list[s_allocation_index].mem_size = nitems * size;
151 ++s_allocation_index;
152 return mem_ptr;
153 }
154
exit_vulnerable_if_memory_leak_detected(void)155 void exit_vulnerable_if_memory_leak_detected(void) {
156 bool memory_leak_detected = false;
157 for (int i = 0; i < s_allocation_index; ++i) {
158 if (s_allocation_list[i].mem_ptr) {
159 real_free(s_allocation_list[i].mem_ptr);
160 memset(&s_allocation_list[i], 0,
161 sizeof(allocated_memory_struct));
162 memory_leak_detected = true;
163 }
164 }
165 if(memory_leak_detected) {
166 exit(EXIT_VULNERABLE);
167 }
168 return;
169 }
170 #endif /* CHECK_MEMORY_LEAK */
171
172 #ifdef CHECK_UNINITIALIZED_MEMORY
is_memory_uninitialized()173 bool is_memory_uninitialized() {
174 for (int i = 0; i < s_allocation_index; ++i) {
175 uint8_t *mem_ptr = s_allocation_list[i].mem_ptr;
176 size_t mem_size = s_allocation_list[i].mem_size;
177 if (mem_ptr) {
178
179 #ifdef CHECK_FOUR_BYTES
180 if(mem_size > (2 * sizeof(uint32_t))) {
181 uint8_t *mem_ptr_start = (uint8_t *) s_allocation_list[i].mem_ptr;
182 uint8_t *mem_ptr_end = (uint8_t *) s_allocation_list[i].mem_ptr + mem_size - 1;
183 for (size_t j = 0; j < sizeof(uint32_t); ++j) {
184 if (*mem_ptr_start++ == INITIAL_VAL) {
185 return true;
186 }
187 if (*mem_ptr_end-- == INITIAL_VAL) {
188 return true;
189 }
190 }
191 continue;
192 }
193 #endif /* CHECK_FOUR_BYTES */
194
195 for (size_t j = 0; j < mem_size; ++j) {
196 if (*mem_ptr++ == INITIAL_VAL) {
197 return true;
198 }
199 }
200 }
201 }
202 return false;
203 }
204
205 #endif /* CHECK_UNINITIALIZED_MEMORY */
206