OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "util/posix/close_multiple.h" | 15 #include "util/posix/close_multiple.h" |
16 | 16 |
17 #include <dirent.h> | 17 #include <dirent.h> |
18 #include <errno.h> | 18 #include <errno.h> |
19 #include <fcntl.h> | 19 #include <fcntl.h> |
20 #include <limits.h> | 20 #include <limits.h> |
| 21 #include <stdio.h> |
21 #include <stdlib.h> | 22 #include <stdlib.h> |
22 #include <string.h> | 23 #include <string.h> |
23 #include <unistd.h> | 24 #include <unistd.h> |
24 | 25 |
25 #include <algorithm> | 26 #include <algorithm> |
26 #include <memory> | 27 #include <memory> |
27 | 28 |
| 29 #include "base/files/scoped_file.h" |
28 #include "base/logging.h" | 30 #include "base/logging.h" |
29 #include "base/posix/eintr_wrapper.h" | 31 #include "base/posix/eintr_wrapper.h" |
30 #include "build/build_config.h" | 32 #include "build/build_config.h" |
31 #include "util/misc/implicit_cast.h" | 33 #include "util/misc/implicit_cast.h" |
32 #include "util/numeric/safe_assignment.h" | 34 #include "util/numeric/safe_assignment.h" |
33 | 35 |
| 36 #if defined(OS_MACOSX) |
| 37 #include <sys/sysctl.h> |
| 38 #endif |
| 39 |
34 // Everything in this file is expected to execute between fork() and exec(), | 40 // Everything in this file is expected to execute between fork() and exec(), |
35 // so everything called here must be acceptable in this context. However, | 41 // so everything called here must be acceptable in this context. However, |
36 // logging code that is not expected to execute under normal circumstances is | 42 // logging code that is not expected to execute under normal circumstances is |
37 // currently permitted. | 43 // currently permitted. |
38 | 44 |
39 namespace crashpad { | 45 namespace crashpad { |
40 namespace { | 46 namespace { |
41 | 47 |
42 // This function attempts to close |fd| or mark it as close-on-exec. On systems | 48 // This function attempts to close |fd| or mark it as close-on-exec. On systems |
43 // where close-on-exec is attempted, a failure to mark it close-on-exec will be | 49 // where close-on-exec is attempted, a failure to mark it close-on-exec will be |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 81 |
76 using ScopedDIR = std::unique_ptr<DIR, ScopedDIRCloser>; | 82 using ScopedDIR = std::unique_ptr<DIR, ScopedDIRCloser>; |
77 | 83 |
78 // This function implements CloseMultipleNowOrOnExec() using an operating | 84 // This function implements CloseMultipleNowOrOnExec() using an operating |
79 // system-specific FD directory to determine which file descriptors are open. | 85 // system-specific FD directory to determine which file descriptors are open. |
80 // This is an advantage over looping over all possible file descriptors, because | 86 // This is an advantage over looping over all possible file descriptors, because |
81 // no attempt needs to be made to close file descriptors that are not open. | 87 // no attempt needs to be made to close file descriptors that are not open. |
82 bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) { | 88 bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) { |
83 #if defined(OS_MACOSX) | 89 #if defined(OS_MACOSX) |
84 const char kFDDir[] = "/dev/fd"; | 90 const char kFDDir[] = "/dev/fd"; |
85 #elif defined(OS_LINUX) | 91 #elif defined(OS_LINUX) || defined(OS_ANDROID) |
86 const char kFDDir[] = "/proc/self/fd"; | 92 const char kFDDir[] = "/proc/self/fd"; |
87 #endif | 93 #endif |
88 | 94 |
89 DIR* dir = opendir(kFDDir); | 95 DIR* dir = opendir(kFDDir); |
90 if (!dir) { | 96 if (!dir) { |
91 PLOG(WARNING) << "opendir"; | 97 PLOG(WARNING) << "opendir"; |
92 return false; | 98 return false; |
93 } | 99 } |
94 | 100 |
95 ScopedDIR dir_owner(dir); | 101 ScopedDIR dir_owner(dir); |
96 | 102 |
97 int dir_fd = dirfd(dir); | 103 int dir_fd = dirfd(dir); |
98 if (dir_fd == -1) { | 104 if (dir_fd == -1) { |
99 PLOG(WARNING) << "dirfd"; | 105 PLOG(WARNING) << "dirfd"; |
100 return false; | 106 return false; |
101 } | 107 } |
102 | 108 |
| 109 dirent* result; |
| 110 #if defined(OS_LINUX) |
| 111 // readdir_r() is deprecated as of glibc 2.24. See |
| 112 // https://sourceware.org/bugzilla/show_bug.cgi?id=19056 and |
| 113 // https://git.kernel.org/cgit/docs/man-pages/man-pages.git/commit?id=0c52f6d6
23636a61eacd0f7b7a3bb942793a2a05. |
| 114 const char kReaddirName[] = "readdir"; |
| 115 while ((errno = 0, result = readdir(dir)) != nullptr) |
| 116 #else |
| 117 const char kReaddirName[] = "readdir_r"; |
103 dirent entry; | 118 dirent entry; |
104 dirent* result; | 119 while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) |
105 int rv; | 120 #endif |
106 while ((rv = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) { | 121 { |
107 const char* entry_name = &(*result->d_name); | 122 const char* entry_name = &(*result->d_name); |
108 if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) { | 123 if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) { |
109 continue; | 124 continue; |
110 } | 125 } |
111 | 126 |
112 char* end; | 127 char* end; |
113 long entry_fd_long = strtol(entry_name, &end, 10); | 128 long entry_fd_long = strtol(entry_name, &end, 10); |
114 if (entry_name[0] == '\0' || *end) { | 129 if (entry_name[0] == '\0' || *end) { |
115 LOG(ERROR) << "unexpected entry " << entry_name; | 130 LOG(ERROR) << "unexpected entry " << entry_name; |
116 return false; | 131 return false; |
117 } | 132 } |
118 | 133 |
119 int entry_fd; | 134 int entry_fd; |
120 if (!AssignIfInRange(&entry_fd, entry_fd_long)) { | 135 if (!AssignIfInRange(&entry_fd, entry_fd_long)) { |
121 LOG(ERROR) << "out-of-range fd " << entry_name; | 136 LOG(ERROR) << "out-of-range fd " << entry_name; |
122 return false; | 137 return false; |
123 } | 138 } |
124 | 139 |
125 if (entry_fd >= fd && entry_fd != preserve_fd && entry_fd != dir_fd) { | 140 if (entry_fd >= fd && entry_fd != preserve_fd && entry_fd != dir_fd) { |
126 CloseNowOrOnExec(entry_fd, false); | 141 CloseNowOrOnExec(entry_fd, false); |
127 } | 142 } |
128 } | 143 } |
129 | 144 |
| 145 if (errno != 0) { |
| 146 PLOG(WARNING) << kReaddirName; |
| 147 return false; |
| 148 } |
| 149 |
130 return true; | 150 return true; |
131 } | 151 } |
132 | 152 |
133 } // namespace | 153 } // namespace |
134 | 154 |
135 void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { | 155 void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { |
136 if (CloseMultipleNowOrOnExecUsingFDDir(fd, preserve_fd)) { | 156 if (CloseMultipleNowOrOnExecUsingFDDir(fd, preserve_fd)) { |
137 return; | 157 return; |
138 } | 158 } |
139 | 159 |
140 // Fallback: close every file descriptor starting at |fd| and ending at the | 160 // Fallback: close every file descriptor starting at |fd| and ending at the |
141 // system’s file descriptor limit. Check a few values and use the highest as | 161 // system’s file descriptor limit. Check a few values and use the highest as |
142 // the limit, because these may be based on the file descriptor limit set by | 162 // the limit, because these may be based on the file descriptor limit set by |
143 // setrlimit(), and higher-numbered file descriptors may have been opened | 163 // setrlimit(), and higher-numbered file descriptors may have been opened |
144 // prior to the limit being lowered. For Mac OS X, see 10.9.2 | 164 // prior to the limit being lowered. On both macOS and Linux glibc, both |
145 // Libc-997.90.3/gen/FreeBSD/sysconf.c sysconf() and 10.9.4 | 165 // sysconf() and getdtablesize() return the current RLIMIT_NOFILE value, not |
146 // xnu-2422.110.17/bsd/kern/kern_descrip.c getdtablesize(), which both return | 166 // the maximum possible file descriptor. For macOS, see 10.11.5 |
147 // the current RLIMIT_NOFILE value, not the maximum possible file descriptor. | 167 // Libc-1082.50.1/gen/FreeBSD/sysconf.c sysconf() and 10.11.6 |
148 int max_fd = std::max(implicit_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX); | 168 // xnu-3248.60.10/bsd/kern/kern_descrip.c getdtablesize(). For Linux glibc, |
| 169 // see glibc-2.24/sysdeps/posix/sysconf.c __sysconf() and |
| 170 // glibc-2.24/sysdeps/posix/getdtsz.c __getdtablesize(). For Android, see |
| 171 // 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf() and |
| 172 // bionic/libc/bionic/ndk_cruft.cpp getdtablesize(). |
| 173 int max_fd = implicit_cast<int>(sysconf(_SC_OPEN_MAX)); |
| 174 |
| 175 #if !defined(OS_ANDROID) |
| 176 // getdtablesize() was removed effective Android 5.0.0 (API 21). Since it |
| 177 // returns the same thing as the sysconf() above, just skip it. See |
| 178 // https://android.googlesource.com/platform/bionic/+/462abab12b074c62c0999859
e65d5a32ebb41951. |
149 max_fd = std::max(max_fd, getdtablesize()); | 179 max_fd = std::max(max_fd, getdtablesize()); |
| 180 #endif |
| 181 |
| 182 #if !defined(OS_LINUX) || defined(OPEN_MAX) |
| 183 // Linux does not provide OPEN_MAX. See |
| 184 // https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit
/include/linux/limits.h?id=77293034696e3e0b6c8b8fc1f96be091104b3d2b. |
| 185 max_fd = std::max(max_fd, OPEN_MAX); |
| 186 #endif |
| 187 |
| 188 // Consult a sysctl to determine the system-wide limit on the maximum number |
| 189 // of open files per process. Note that it is possible to change this limit |
| 190 // while the system is running, but it’s still a better upper bound than the |
| 191 // current RLIMIT_NOFILE value. |
| 192 |
| 193 #if defined(OS_MACOSX) |
| 194 // See 10.11.6 xnu-3248.60.10/bsd/kern/kern_resource.c maxfilesperproc, |
| 195 // referenced by dosetrlimit(). |
| 196 int oid[] = {CTL_KERN, KERN_MAXFILESPERPROC}; |
| 197 int maxfilesperproc; |
| 198 size_t maxfilesperproc_size = sizeof(maxfilesperproc); |
| 199 if (sysctl(oid, |
| 200 arraysize(oid), |
| 201 &maxfilesperproc, |
| 202 &maxfilesperproc_size, |
| 203 nullptr, |
| 204 0) == 0) { |
| 205 max_fd = std::max(max_fd, maxfilesperproc); |
| 206 } else { |
| 207 PLOG(WARNING) << "sysctl"; |
| 208 } |
| 209 #elif defined(OS_LINUX) || defined(OS_ANDROID) |
| 210 // See linux-4.4.27/fs/file.c sysctl_nr_open, referenced by kernel/sys.c |
| 211 // do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is |
| 212 // not considered an error, because /proc may not be available or usable. |
| 213 { |
| 214 base::ScopedFILE nr_open_file(fopen("/proc/sys/fs/nr_open", "r")); |
| 215 if (nr_open_file.get() != nullptr) { |
| 216 int nr_open; |
| 217 if (fscanf(nr_open_file.get(), "%d\n", &nr_open) == 1 && |
| 218 feof(nr_open_file.get())) { |
| 219 max_fd = std::max(max_fd, nr_open); |
| 220 } else { |
| 221 LOG(WARNING) << "/proc/sys/fs/nr_open format error"; |
| 222 } |
| 223 } |
| 224 } |
| 225 #endif |
150 | 226 |
151 for (int entry_fd = fd; entry_fd < max_fd; ++entry_fd) { | 227 for (int entry_fd = fd; entry_fd < max_fd; ++entry_fd) { |
152 if (entry_fd != preserve_fd) { | 228 if (entry_fd != preserve_fd) { |
153 CloseNowOrOnExec(entry_fd, true); | 229 CloseNowOrOnExec(entry_fd, true); |
154 } | 230 } |
155 } | 231 } |
156 } | 232 } |
157 | 233 |
158 } // namespace crashpad | 234 } // namespace crashpad |
OLD | NEW |