1 // Copyright 2016 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/memory/shared_memory_helper.h" 6 7 #if defined(OS_CHROMEOS) 8 #include <sys/resource.h> 9 #include <sys/time.h> 10 11 #include "base/debug/alias.h" 12 #endif // defined(OS_CHROMEOS) 13 14 #include "base/threading/thread_restrictions.h" 15 16 namespace base { 17 18 struct ScopedPathUnlinkerTraits { InvalidValuebase::ScopedPathUnlinkerTraits19 static const FilePath* InvalidValue() { return nullptr; } 20 Freebase::ScopedPathUnlinkerTraits21 static void Free(const FilePath* path) { 22 if (unlink(path->value().c_str())) 23 PLOG(WARNING) << "unlink"; 24 } 25 }; 26 27 // Unlinks the FilePath when the object is destroyed. 28 using ScopedPathUnlinker = 29 ScopedGeneric<const FilePath*, ScopedPathUnlinkerTraits>; 30 31 #if !defined(OS_ANDROID) CreateAnonymousSharedMemory(const SharedMemoryCreateOptions & options,ScopedFD * fd,ScopedFD * readonly_fd,FilePath * path)32 bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options, 33 ScopedFD* fd, 34 ScopedFD* readonly_fd, 35 FilePath* path) { 36 #if defined(OS_LINUX) 37 // It doesn't make sense to have a open-existing private piece of shmem 38 DCHECK(!options.open_existing_deprecated); 39 #endif // defined(OS_LINUX) 40 // Q: Why not use the shm_open() etc. APIs? 41 // A: Because they're limited to 4mb on OS X. FFFFFFFUUUUUUUUUUU 42 FilePath directory; 43 ScopedPathUnlinker path_unlinker; 44 if (!GetShmemTempDir(options.executable, &directory)) 45 return false; 46 47 fd->reset(base::CreateAndOpenFdForTemporaryFileInDir(directory, path)); 48 49 if (!fd->is_valid()) 50 return false; 51 52 // Deleting the file prevents anyone else from mapping it in (making it 53 // private), and prevents the need for cleanup (once the last fd is 54 // closed, it is truly freed). 55 path_unlinker.reset(path); 56 57 if (options.share_read_only) { 58 // Also open as readonly so that we can GetReadOnlyHandle. 59 readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY))); 60 if (!readonly_fd->is_valid()) { 61 DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed"; 62 fd->reset(); 63 return false; 64 } 65 } 66 return true; 67 } 68 PrepareMapFile(ScopedFD fd,ScopedFD readonly_fd,int * mapped_file,int * readonly_mapped_file)69 bool PrepareMapFile(ScopedFD fd, 70 ScopedFD readonly_fd, 71 int* mapped_file, 72 int* readonly_mapped_file) { 73 DCHECK_EQ(-1, *mapped_file); 74 DCHECK_EQ(-1, *readonly_mapped_file); 75 if (!fd.is_valid()) 76 return false; 77 78 // This function theoretically can block on the disk, but realistically 79 // the temporary files we create will just go into the buffer cache 80 // and be deleted before they ever make it out to disk. 81 base::ThreadRestrictions::ScopedAllowIO allow_io; 82 83 if (readonly_fd.is_valid()) { 84 struct stat st = {}; 85 if (fstat(fd.get(), &st)) 86 NOTREACHED(); 87 88 struct stat readonly_st = {}; 89 if (fstat(readonly_fd.get(), &readonly_st)) 90 NOTREACHED(); 91 if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) { 92 LOG(ERROR) << "writable and read-only inodes don't match; bailing"; 93 return false; 94 } 95 } 96 97 *mapped_file = HANDLE_EINTR(dup(fd.get())); 98 if (*mapped_file == -1) { 99 NOTREACHED() << "Call to dup failed, errno=" << errno; 100 101 #if defined(OS_CHROMEOS) 102 if (errno == EMFILE) { 103 // We're out of file descriptors and are probably about to crash somewhere 104 // else in Chrome anyway. Let's collect what FD information we can and 105 // crash. 106 // Added for debugging crbug.com/733718 107 int original_fd_limit = 16384; 108 struct rlimit rlim; 109 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 110 original_fd_limit = rlim.rlim_cur; 111 if (rlim.rlim_max > rlim.rlim_cur) { 112 // Increase fd limit so breakpad has a chance to write a minidump. 113 rlim.rlim_cur = rlim.rlim_max; 114 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { 115 PLOG(ERROR) << "setrlimit() failed"; 116 } 117 } 118 } else { 119 PLOG(ERROR) << "getrlimit() failed"; 120 } 121 122 const char kFileDataMarker[] = "FDATA"; 123 char buf[PATH_MAX]; 124 char fd_path[PATH_MAX]; 125 char crash_buffer[32 * 1024] = {0}; 126 char* crash_ptr = crash_buffer; 127 base::debug::Alias(crash_buffer); 128 129 // Put a marker at the start of our data so we can confirm where it 130 // begins. 131 crash_ptr = strncpy(crash_ptr, kFileDataMarker, strlen(kFileDataMarker)); 132 for (int i = original_fd_limit; i >= 0; --i) { 133 memset(buf, 0, arraysize(buf)); 134 memset(fd_path, 0, arraysize(fd_path)); 135 snprintf(fd_path, arraysize(fd_path) - 1, "/proc/self/fd/%d", i); 136 ssize_t count = readlink(fd_path, buf, arraysize(buf) - 1); 137 if (count < 0) { 138 PLOG(ERROR) << "readlink failed for: " << fd_path; 139 continue; 140 } 141 142 if (crash_ptr + count + 1 < crash_buffer + arraysize(crash_buffer)) { 143 crash_ptr = strncpy(crash_ptr, buf, count + 1); 144 } 145 LOG(ERROR) << i << ": " << buf; 146 } 147 LOG(FATAL) << "Logged for file descriptor exhaustion, crashing now"; 148 } 149 #endif // defined(OS_CHROMEOS) 150 } 151 *readonly_mapped_file = readonly_fd.release(); 152 153 return true; 154 } 155 #endif // !defined(OS_ANDROID) 156 157 } // namespace base 158