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