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