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