1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <alloca.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <stddef.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38
39 #include "gwp_asan/guarded_pool_allocator.h"
40 #include "gwp_asan/options.h"
41 #include "gwp_asan_wrappers.h"
42 #include "malloc_common.h"
43 #include "platform/bionic/android_unsafe_frame_pointer_chase.h"
44 #include "platform/bionic/macros.h"
45 #include "platform/bionic/malloc.h"
46 #include "private/bionic_arc4random.h"
47 #include "private/bionic_globals.h"
48 #include "private/bionic_malloc_dispatch.h"
49 #include "sys/system_properties.h"
50 #include "sysprop_helpers.h"
51
52 #ifndef LIBC_STATIC
53 #include "bionic/malloc_common_dynamic.h"
54 #endif // LIBC_STATIC
55
56 static gwp_asan::GuardedPoolAllocator GuardedAlloc;
57 static const MallocDispatch* prev_dispatch;
58
59 using Action = android_mallopt_gwp_asan_options_t::Action;
60 using Options = gwp_asan::options::Options;
61
62 // basename() is a mess, see the manpage. Let's be explicit what handling we
63 // want (don't touch my string!).
64 extern "C" const char* __gnu_basename(const char* path);
65
66 namespace {
67
68 // ============================================================================
69 // Implementation of GWP-ASan malloc wrappers.
70 // ============================================================================
71
gwp_asan_calloc(size_t n_elements,size_t elem_size)72 void* gwp_asan_calloc(size_t n_elements, size_t elem_size) {
73 if (__predict_false(GuardedAlloc.shouldSample())) {
74 size_t bytes;
75 if (!__builtin_mul_overflow(n_elements, elem_size, &bytes)) {
76 if (void* result = GuardedAlloc.allocate(bytes)) {
77 return result;
78 }
79 }
80 }
81 return prev_dispatch->calloc(n_elements, elem_size);
82 }
83
gwp_asan_free(void * mem)84 void gwp_asan_free(void* mem) {
85 if (__predict_false(GuardedAlloc.pointerIsMine(mem))) {
86 GuardedAlloc.deallocate(mem);
87 return;
88 }
89 prev_dispatch->free(mem);
90 }
91
gwp_asan_malloc(size_t bytes)92 void* gwp_asan_malloc(size_t bytes) {
93 if (__predict_false(GuardedAlloc.shouldSample())) {
94 if (void* result = GuardedAlloc.allocate(bytes)) {
95 return result;
96 }
97 }
98 return prev_dispatch->malloc(bytes);
99 }
100
gwp_asan_malloc_usable_size(const void * mem)101 size_t gwp_asan_malloc_usable_size(const void* mem) {
102 if (__predict_false(GuardedAlloc.pointerIsMine(mem))) {
103 return GuardedAlloc.getSize(mem);
104 }
105 return prev_dispatch->malloc_usable_size(mem);
106 }
107
gwp_asan_realloc(void * old_mem,size_t bytes)108 void* gwp_asan_realloc(void* old_mem, size_t bytes) {
109 // GPA::pointerIsMine(p) always returns false where `p == nullptr` (and thus
110 // malloc(bytes) is requested). We always fall back to the backing allocator,
111 // technically missing some coverage, but reducing an extra conditional
112 // branch.
113 if (__predict_false(GuardedAlloc.pointerIsMine(old_mem))) {
114 if (__predict_false(bytes == 0)) {
115 GuardedAlloc.deallocate(old_mem);
116 return nullptr;
117 }
118 void* new_ptr = gwp_asan_malloc(bytes);
119 // If malloc() fails, then don't destroy the old memory.
120 if (__predict_false(new_ptr == nullptr)) return nullptr;
121
122 size_t old_size = GuardedAlloc.getSize(old_mem);
123 memcpy(new_ptr, old_mem, (bytes < old_size) ? bytes : old_size);
124 GuardedAlloc.deallocate(old_mem);
125 return new_ptr;
126 }
127 return prev_dispatch->realloc(old_mem, bytes);
128 }
129
gwp_asan_malloc_iterate(uintptr_t base,size_t size,void (* callback)(uintptr_t base,size_t size,void * arg),void * arg)130 int gwp_asan_malloc_iterate(uintptr_t base, size_t size,
131 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
132 if (__predict_false(GuardedAlloc.pointerIsMine(reinterpret_cast<void*>(base)))) {
133 // TODO(mitchp): GPA::iterate() returns void, but should return int.
134 // TODO(mitchp): GPA::iterate() should take uintptr_t, not void*.
135 GuardedAlloc.iterate(reinterpret_cast<void*>(base), size, callback, arg);
136 return 0;
137 }
138 return prev_dispatch->malloc_iterate(base, size, callback, arg);
139 }
140
gwp_asan_malloc_disable()141 void gwp_asan_malloc_disable() {
142 GuardedAlloc.disable();
143 prev_dispatch->malloc_disable();
144 }
145
gwp_asan_malloc_enable()146 void gwp_asan_malloc_enable() {
147 GuardedAlloc.enable();
148 prev_dispatch->malloc_enable();
149 }
150
151 const MallocDispatch gwp_asan_dispatch __attribute__((unused)) = {
152 gwp_asan_calloc,
153 gwp_asan_free,
154 Malloc(mallinfo),
155 gwp_asan_malloc,
156 gwp_asan_malloc_usable_size,
157 Malloc(memalign),
158 Malloc(posix_memalign),
159 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
160 Malloc(pvalloc),
161 #endif
162 gwp_asan_realloc,
163 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
164 Malloc(valloc),
165 #endif
166 gwp_asan_malloc_iterate,
167 gwp_asan_malloc_disable,
168 gwp_asan_malloc_enable,
169 Malloc(mallopt),
170 Malloc(aligned_alloc),
171 Malloc(malloc_info),
172 };
173
isPowerOfTwo(uint64_t x)174 bool isPowerOfTwo(uint64_t x) {
175 assert(x != 0);
176 return (x & (x - 1)) == 0;
177 }
178
ShouldGwpAsanSampleProcess(unsigned sample_rate)179 bool ShouldGwpAsanSampleProcess(unsigned sample_rate) {
180 if (!isPowerOfTwo(sample_rate)) {
181 warning_log(
182 "GWP-ASan process sampling rate of %u is not a power-of-two, and so modulo bias occurs.",
183 sample_rate);
184 }
185
186 uint8_t random_number;
187 __libc_safe_arc4random_buf(&random_number, sizeof(random_number));
188 return random_number % sample_rate == 0;
189 }
190
191 bool GwpAsanInitialized = false;
192
193 // The probability (1 / SampleRate) that an allocation gets chosen to be put
194 // into the special GWP-ASan pool.
195 using SampleRate_t = typeof(gwp_asan::options::Options::SampleRate);
196 constexpr SampleRate_t kDefaultSampleRate = 2500;
197 static const char* kSampleRateSystemSysprop = "libc.debug.gwp_asan.sample_rate.system_default";
198 static const char* kSampleRateAppSysprop = "libc.debug.gwp_asan.sample_rate.app_default";
199 static const char* kSampleRateTargetedSyspropPrefix = "libc.debug.gwp_asan.sample_rate.";
200 static const char* kSampleRateEnvVar = "GWP_ASAN_SAMPLE_RATE";
201
202 // The probability (1 / ProcessSampling) that a process will be randomly
203 // selected for sampling, for system apps and system processes. The process
204 // sampling rate should always be a power of two to avoid modulo bias.
205 constexpr unsigned kDefaultProcessSampling = 128;
206 static const char* kProcessSamplingSystemSysprop =
207 "libc.debug.gwp_asan.process_sampling.system_default";
208 static const char* kProcessSamplingAppSysprop = "libc.debug.gwp_asan.process_sampling.app_default";
209 static const char* kProcessSamplingTargetedSyspropPrefix = "libc.debug.gwp_asan.process_sampling.";
210 static const char* kProcessSamplingEnvVar = "GWP_ASAN_PROCESS_SAMPLING";
211
212 // The upper limit of simultaneous allocations supported by GWP-ASan. Any
213 // allocations in excess of this limit will be passed to the backing allocator
214 // and can't be sampled. This value, if unspecified, will be automatically
215 // calculated to keep the same ratio as the default (2500 sampling : 32 allocs).
216 // So, if you specify GWP_ASAN_SAMPLE_RATE=1250 (i.e. twice as frequent), we'll
217 // automatically calculate that we need double the slots (64).
218 using SimultaneousAllocations_t = typeof(gwp_asan::options::Options::MaxSimultaneousAllocations);
219 constexpr SimultaneousAllocations_t kDefaultMaxAllocs = 32;
220 static const char* kMaxAllocsSystemSysprop = "libc.debug.gwp_asan.max_allocs.system_default";
221 static const char* kMaxAllocsAppSysprop = "libc.debug.gwp_asan.max_allocs.app_default";
222 static const char* kMaxAllocsTargetedSyspropPrefix = "libc.debug.gwp_asan.max_allocs.";
223 static const char* kMaxAllocsEnvVar = "GWP_ASAN_MAX_ALLOCS";
224
225 static const char kPersistPrefix[] = "persist.";
226
SetDefaultGwpAsanOptions(Options * options,unsigned * process_sample_rate,const android_mallopt_gwp_asan_options_t & mallopt_options)227 void SetDefaultGwpAsanOptions(Options* options, unsigned* process_sample_rate,
228 const android_mallopt_gwp_asan_options_t& mallopt_options) {
229 options->Enabled = true;
230 options->InstallSignalHandlers = false;
231 options->InstallForkHandlers = true;
232 options->Backtrace = android_unsafe_frame_pointer_chase;
233 options->SampleRate = kDefaultSampleRate;
234 options->MaxSimultaneousAllocations = kDefaultMaxAllocs;
235
236 *process_sample_rate = 1;
237 if (mallopt_options.desire == Action::TURN_ON_WITH_SAMPLING) {
238 *process_sample_rate = kDefaultProcessSampling;
239 }
240 }
241
GetGwpAsanOption(unsigned long long * result,const android_mallopt_gwp_asan_options_t & mallopt_options,const char * system_sysprop,const char * app_sysprop,const char * targeted_sysprop_prefix,const char * env_var,const char * descriptive_name)242 bool GetGwpAsanOption(unsigned long long* result,
243 const android_mallopt_gwp_asan_options_t& mallopt_options,
244 const char* system_sysprop, const char* app_sysprop,
245 const char* targeted_sysprop_prefix, const char* env_var,
246 const char* descriptive_name) {
247 const char* basename = "";
248 if (mallopt_options.program_name) basename = __gnu_basename(mallopt_options.program_name);
249
250 constexpr size_t kSyspropMaxLen = 512;
251 char program_specific_sysprop[kSyspropMaxLen] = {};
252 char persist_program_specific_sysprop[kSyspropMaxLen] = {};
253 char persist_default_sysprop[kSyspropMaxLen] = {};
254 const char* sysprop_names[4] = {};
255 // Tests use a blank program name to specify that system properties should not
256 // be used. Tests still continue to use the environment variable though.
257 if (*basename != '\0') {
258 const char* default_sysprop = system_sysprop;
259 if (mallopt_options.desire == Action::TURN_ON_FOR_APP) {
260 default_sysprop = app_sysprop;
261 }
262 async_safe_format_buffer(&program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
263 targeted_sysprop_prefix, basename);
264 async_safe_format_buffer(&persist_program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
265 kPersistPrefix, program_specific_sysprop);
266 async_safe_format_buffer(&persist_default_sysprop[0], kSyspropMaxLen, "%s%s", kPersistPrefix,
267 default_sysprop);
268
269 // In order of precedence, always take the program-specific sysprop (e.g.
270 // '[persist.]libc.debug.gwp_asan.sample_rate.cameraserver') over the
271 // generic sysprop (e.g.
272 // '[persist.]libc.debug.gwp_asan.(system_default|app_default)'). In
273 // addition, always take the non-persistent option over the persistent
274 // option.
275 sysprop_names[0] = program_specific_sysprop;
276 sysprop_names[1] = persist_program_specific_sysprop;
277 sysprop_names[2] = default_sysprop;
278 sysprop_names[3] = persist_default_sysprop;
279 }
280
281 char settings_buf[PROP_VALUE_MAX];
282 if (!get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
283 settings_buf, PROP_VALUE_MAX)) {
284 return false;
285 }
286
287 char* end;
288 unsigned long long value = strtoull(settings_buf, &end, 10);
289 if (value == ULLONG_MAX || *end != '\0') {
290 warning_log("Invalid GWP-ASan %s: \"%s\". Using default value instead.", descriptive_name,
291 settings_buf);
292 return false;
293 }
294
295 *result = value;
296 return true;
297 }
298
299 // Initialize the GWP-ASan options structure in *options, taking into account whether someone has
300 // asked for specific GWP-ASan settings. The order of priority is:
301 // 1. Environment variables.
302 // 2. Process-specific system properties.
303 // 3. Global system properties.
304 // If any of these overrides are found, we return true. Otherwise, use the default values, and
305 // return false.
GetGwpAsanOptions(Options * options,unsigned * process_sample_rate,const android_mallopt_gwp_asan_options_t & mallopt_options)306 bool GetGwpAsanOptions(Options* options, unsigned* process_sample_rate,
307 const android_mallopt_gwp_asan_options_t& mallopt_options) {
308 SetDefaultGwpAsanOptions(options, process_sample_rate, mallopt_options);
309
310 bool had_overrides = false;
311
312 unsigned long long buf;
313 if (GetGwpAsanOption(&buf, mallopt_options, kSampleRateSystemSysprop, kSampleRateAppSysprop,
314 kSampleRateTargetedSyspropPrefix, kSampleRateEnvVar, "sample rate")) {
315 options->SampleRate = buf;
316 had_overrides = true;
317 }
318
319 if (GetGwpAsanOption(&buf, mallopt_options, kProcessSamplingSystemSysprop,
320 kProcessSamplingAppSysprop, kProcessSamplingTargetedSyspropPrefix,
321 kProcessSamplingEnvVar, "process sampling rate")) {
322 *process_sample_rate = buf;
323 had_overrides = true;
324 }
325
326 if (GetGwpAsanOption(&buf, mallopt_options, kMaxAllocsSystemSysprop, kMaxAllocsAppSysprop,
327 kMaxAllocsTargetedSyspropPrefix, kMaxAllocsEnvVar,
328 "maximum simultaneous allocations")) {
329 options->MaxSimultaneousAllocations = buf;
330 had_overrides = true;
331 } else if (had_overrides) {
332 // Multiply the number of slots available, such that the ratio between
333 // sampling rate and slots is kept the same as the default. For example, a
334 // sampling rate of 1000 is 2.5x more frequent than default, and so
335 // requires 80 slots (32 * 2.5).
336 float frequency_multiplier = static_cast<float>(options->SampleRate) / kDefaultSampleRate;
337 options->MaxSimultaneousAllocations =
338 /* default */ kDefaultMaxAllocs / frequency_multiplier;
339 }
340 return had_overrides;
341 }
342
MaybeInitGwpAsan(libc_globals * globals,const android_mallopt_gwp_asan_options_t & mallopt_options)343 bool MaybeInitGwpAsan(libc_globals* globals,
344 const android_mallopt_gwp_asan_options_t& mallopt_options) {
345 if (GwpAsanInitialized) {
346 error_log("GWP-ASan was already initialized for this process.");
347 return false;
348 }
349
350 Options options;
351 unsigned process_sample_rate = kDefaultProcessSampling;
352 if (!GetGwpAsanOptions(&options, &process_sample_rate, mallopt_options) &&
353 mallopt_options.desire == Action::DONT_TURN_ON_UNLESS_OVERRIDDEN) {
354 return false;
355 }
356
357 if (options.SampleRate == 0 || process_sample_rate == 0 ||
358 options.MaxSimultaneousAllocations == 0) {
359 return false;
360 }
361
362 if (!ShouldGwpAsanSampleProcess(process_sample_rate)) {
363 return false;
364 }
365
366 // GWP-ASan is compatible with heapprofd/malloc_debug/malloc_hooks iff
367 // GWP-ASan was installed first. If one of these other libraries was already
368 // installed, we don't enable GWP-ASan. These libraries are normally enabled
369 // in libc_init after GWP-ASan, but if the new process is a zygote child and
370 // trying to initialize GWP-ASan through mallopt(), one of these libraries may
371 // be installed. It may be possible to change this in future by modifying the
372 // internal dispatch pointers of these libraries at this point in time, but
373 // given that they're all debug-only, we don't really mind for now.
374 if (GetDefaultDispatchTable() != nullptr) {
375 // Something else is installed.
376 return false;
377 }
378
379 // GWP-ASan's initialization is always called in a single-threaded context, so
380 // we can initialize lock-free.
381 // Set GWP-ASan as the malloc dispatch table.
382 globals->malloc_dispatch_table = gwp_asan_dispatch;
383 atomic_store(&globals->default_dispatch_table, &gwp_asan_dispatch);
384
385 // If malloc_limit isn't installed, we can skip the default_dispatch_table
386 // lookup.
387 if (GetDispatchTable() == nullptr) {
388 atomic_store(&globals->current_dispatch_table, &gwp_asan_dispatch);
389 }
390
391 GwpAsanInitialized = true;
392
393 prev_dispatch = NativeAllocatorDispatch();
394
395 GuardedAlloc.init(options);
396
397 __libc_shared_globals()->gwp_asan_state = GuardedAlloc.getAllocatorState();
398 __libc_shared_globals()->gwp_asan_metadata = GuardedAlloc.getMetadataRegion();
399
400 return true;
401 }
402 }; // anonymous namespace
403
MaybeInitGwpAsanFromLibc(libc_globals * globals)404 bool MaybeInitGwpAsanFromLibc(libc_globals* globals) {
405 // Never initialize the Zygote here. A Zygote chosen for sampling would also
406 // have all of its children sampled. Instead, the Zygote child will choose
407 // whether it samples or not just after the Zygote forks. Note that the Zygote
408 // changes its name after it's started, at this point it's still called
409 // "app_process" or "app_process64".
410 static const char kAppProcessNamePrefix[] = "app_process";
411 const char* progname = getprogname();
412 if (strncmp(progname, kAppProcessNamePrefix, sizeof(kAppProcessNamePrefix) - 1) == 0)
413 return false;
414
415 android_mallopt_gwp_asan_options_t mallopt_options;
416 mallopt_options.program_name = progname;
417 mallopt_options.desire = Action::TURN_ON_WITH_SAMPLING;
418
419 return MaybeInitGwpAsan(globals, mallopt_options);
420 }
421
DispatchIsGwpAsan(const MallocDispatch * dispatch)422 bool DispatchIsGwpAsan(const MallocDispatch* dispatch) {
423 return dispatch == &gwp_asan_dispatch;
424 }
425
EnableGwpAsan(const android_mallopt_gwp_asan_options_t & options)426 bool EnableGwpAsan(const android_mallopt_gwp_asan_options_t& options) {
427 if (GwpAsanInitialized) {
428 return true;
429 }
430
431 bool ret_value;
432 __libc_globals.mutate(
433 [&](libc_globals* globals) { ret_value = MaybeInitGwpAsan(globals, options); });
434 return ret_value;
435 }
436