Home | History | Annotate | Download | only in process
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/process/memory.h"
      6 
      7 #include <new>
      8 
      9 #include "base/file_util.h"
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/process/internal_linux.h"
     13 #include "base/strings/string_number_conversions.h"
     14 
     15 namespace base {
     16 
     17 size_t g_oom_size = 0U;
     18 
     19 namespace {
     20 
     21 #if !defined(OS_ANDROID)
     22 void OnNoMemorySize(size_t size) {
     23   g_oom_size = size;
     24 
     25   if (size != 0)
     26     LOG(FATAL) << "Out of memory, size = " << size;
     27   LOG(FATAL) << "Out of memory.";
     28 }
     29 
     30 void OnNoMemory() {
     31   OnNoMemorySize(0);
     32 }
     33 #endif  // !defined(OS_ANDROID)
     34 
     35 }  // namespace
     36 
     37 #if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
     38     !defined(THREAD_SANITIZER) && !defined(LEAK_SANITIZER)
     39 
     40 #if defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
     41 
     42 extern "C" {
     43 void* __libc_malloc(size_t size);
     44 void* __libc_realloc(void* ptr, size_t size);
     45 void* __libc_calloc(size_t nmemb, size_t size);
     46 void* __libc_valloc(size_t size);
     47 void* __libc_pvalloc(size_t size);
     48 void* __libc_memalign(size_t alignment, size_t size);
     49 
     50 // Overriding the system memory allocation functions:
     51 //
     52 // For security reasons, we want malloc failures to be fatal. Too much code
     53 // doesn't check for a NULL return value from malloc and unconditionally uses
     54 // the resulting pointer. If the first offset that they try to access is
     55 // attacker controlled, then the attacker can direct the code to access any
     56 // part of memory.
     57 //
     58 // Thus, we define all the standard malloc functions here and mark them as
     59 // visibility 'default'. This means that they replace the malloc functions for
     60 // all Chromium code and also for all code in shared libraries. There are tests
     61 // for this in process_util_unittest.cc.
     62 //
     63 // If we are using tcmalloc, then the problem is moot since tcmalloc handles
     64 // this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
     65 //
     66 // If we are testing the binary with AddressSanitizer, we should not
     67 // redefine malloc and let AddressSanitizer do it instead.
     68 //
     69 // We call the real libc functions in this code by using __libc_malloc etc.
     70 // Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
     71 // the link order. Since ld.so needs calloc during symbol resolution, it
     72 // defines its own versions of several of these functions in dl-minimal.c.
     73 // Depending on the runtime library order, dlsym ended up giving us those
     74 // functions and bad things happened. See crbug.com/31809
     75 //
     76 // This means that any code which calls __libc_* gets the raw libc versions of
     77 // these functions.
     78 
     79 #define DIE_ON_OOM_1(function_name) \
     80   void* function_name(size_t) __attribute__ ((visibility("default"))); \
     81   \
     82   void* function_name(size_t size) { \
     83     void* ret = __libc_##function_name(size); \
     84     if (ret == NULL && size != 0) \
     85       OnNoMemorySize(size); \
     86     return ret; \
     87   }
     88 
     89 #define DIE_ON_OOM_2(function_name, arg1_type) \
     90   void* function_name(arg1_type, size_t) \
     91       __attribute__ ((visibility("default"))); \
     92   \
     93   void* function_name(arg1_type arg1, size_t size) { \
     94     void* ret = __libc_##function_name(arg1, size); \
     95     if (ret == NULL && size != 0) \
     96       OnNoMemorySize(size); \
     97     return ret; \
     98   }
     99 
    100 DIE_ON_OOM_1(malloc)
    101 DIE_ON_OOM_1(valloc)
    102 DIE_ON_OOM_1(pvalloc)
    103 
    104 DIE_ON_OOM_2(calloc, size_t)
    105 DIE_ON_OOM_2(realloc, void*)
    106 DIE_ON_OOM_2(memalign, size_t)
    107 
    108 // posix_memalign has a unique signature and doesn't have a __libc_ variant.
    109 int posix_memalign(void** ptr, size_t alignment, size_t size)
    110     __attribute__ ((visibility("default")));
    111 
    112 int posix_memalign(void** ptr, size_t alignment, size_t size) {
    113   // This will use the safe version of memalign, above.
    114   *ptr = memalign(alignment, size);
    115   return 0;
    116 }
    117 
    118 }  // extern C
    119 
    120 #else
    121 
    122 // TODO(mostynb (at) opera.com): dlsym dance
    123 
    124 #endif  // LIBC_GLIBC && !USE_TCMALLOC
    125 
    126 #endif  // !*_SANITIZER
    127 
    128 void EnableTerminationOnHeapCorruption() {
    129   // On Linux, there nothing to do AFAIK.
    130 }
    131 
    132 void EnableTerminationOnOutOfMemory() {
    133 #if defined(OS_ANDROID)
    134   // Android doesn't support setting a new handler.
    135   DLOG(WARNING) << "Not feasible.";
    136 #else
    137   // Set the new-out of memory handler.
    138   std::set_new_handler(&OnNoMemory);
    139   // If we're using glibc's allocator, the above functions will override
    140   // malloc and friends and make them die on out of memory.
    141 #endif
    142 }
    143 
    144 // NOTE: This is not the only version of this function in the source:
    145 // the setuid sandbox (in process_util_linux.c, in the sandbox source)
    146 // also has its own C version.
    147 bool AdjustOOMScore(ProcessId process, int score) {
    148   if (score < 0 || score > kMaxOomScore)
    149     return false;
    150 
    151   FilePath oom_path(internal::GetProcPidDir(process));
    152 
    153   // Attempt to write the newer oom_score_adj file first.
    154   FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
    155   if (PathExists(oom_file)) {
    156     std::string score_str = IntToString(score);
    157     DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
    158              << score_str;
    159     int score_len = static_cast<int>(score_str.length());
    160     return (score_len == file_util::WriteFile(oom_file,
    161                                               score_str.c_str(),
    162                                               score_len));
    163   }
    164 
    165   // If the oom_score_adj file doesn't exist, then we write the old
    166   // style file and translate the oom_adj score to the range 0-15.
    167   oom_file = oom_path.AppendASCII("oom_adj");
    168   if (PathExists(oom_file)) {
    169     // Max score for the old oom_adj range.  Used for conversion of new
    170     // values to old values.
    171     const int kMaxOldOomScore = 15;
    172 
    173     int converted_score = score * kMaxOldOomScore / kMaxOomScore;
    174     std::string score_str = IntToString(converted_score);
    175     DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
    176     int score_len = static_cast<int>(score_str.length());
    177     return (score_len == file_util::WriteFile(oom_file,
    178                                               score_str.c_str(),
    179                                               score_len));
    180   }
    181 
    182   return false;
    183 }
    184 
    185 }  // namespace base
    186