• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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