| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (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 | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "util/test/posix/close_multiple.h" | |
| 16 | |
| 17 #include <dirent.h> | |
| 18 #include <errno.h> | |
| 19 #include <fcntl.h> | |
| 20 #include <limits.h> | |
| 21 #include <stdlib.h> | |
| 22 #include <string.h> | |
| 23 #include <unistd.h> | |
| 24 | |
| 25 #include <algorithm> | |
| 26 | |
| 27 #include "base/basictypes.h" | |
| 28 #include "base/logging.h" | |
| 29 #include "base/memory/scoped_ptr.h" | |
| 30 #include "base/posix/eintr_wrapper.h" | |
| 31 #include "build/build_config.h" | |
| 32 #include "util/numeric/safe_assignment.h" | |
| 33 | |
| 34 // Everything in this file is expected to execute between fork() and exec(), | |
| 35 // so everything called here must be acceptable in this context. However, | |
| 36 // logging code that is not expected to execute under normal circumstances is | |
| 37 // currently permitted. | |
| 38 | |
| 39 namespace crashpad { | |
| 40 namespace { | |
| 41 | |
| 42 // 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 | |
| 44 // followed by an attempt to close it. |ebadf_ok| should be set to |true| if | |
| 45 // the caller is attempting to close the file descriptor “blind,” that is, | |
| 46 // without knowledge that it is or is not a valid file descriptor. | |
| 47 void CloseNowOrOnExec(int fd, bool ebadf_ok) { | |
| 48 int rv; | |
| 49 | |
| 50 #if defined(OS_MACOSX) | |
| 51 // Try to set close-on-exec, to avoid attempting to close a guarded FD with | |
| 52 // a close guard set. | |
| 53 rv = fcntl(fd, F_SETFD, FD_CLOEXEC); | |
| 54 if (rv != -1 || (ebadf_ok && errno == EBADF)) { | |
| 55 return; | |
| 56 } | |
| 57 PLOG(WARNING) << "fcntl"; | |
| 58 #endif | |
| 59 | |
| 60 rv = IGNORE_EINTR(close(fd)); | |
| 61 if (rv != 0 && !(ebadf_ok && errno == EBADF)) { | |
| 62 PLOG(WARNING) << "close"; | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 struct ScopedDIRCloser { | |
| 67 void operator()(DIR* dir) const { | |
| 68 if (dir) { | |
| 69 if (closedir(dir) < 0) { | |
| 70 PLOG(ERROR) << "closedir"; | |
| 71 } | |
| 72 } | |
| 73 } | |
| 74 }; | |
| 75 | |
| 76 using ScopedDIR = scoped_ptr<DIR, ScopedDIRCloser>; | |
| 77 | |
| 78 // This function implements CloseMultipleNowOrOnExec() using an operating | |
| 79 // system-specific FD directory to determine which file descriptors are open. | |
| 80 // 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. | |
| 82 bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) { | |
| 83 #if defined(OS_MACOSX) | |
| 84 const char kFDDir[] = "/dev/fd"; | |
| 85 #elif defined(OS_LINUX) | |
| 86 const char kFDDir[] = "/proc/self/fd"; | |
| 87 #endif | |
| 88 | |
| 89 DIR* dir = opendir(kFDDir); | |
| 90 if (!dir) { | |
| 91 PLOG(WARNING) << "opendir"; | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 ScopedDIR dir_owner(dir); | |
| 96 | |
| 97 int dir_fd = dirfd(dir); | |
| 98 if (dir_fd == -1) { | |
| 99 PLOG(WARNING) << "dirfd"; | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 dirent entry; | |
| 104 dirent* result; | |
| 105 int rv; | |
| 106 while ((rv = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) { | |
| 107 const char* entry_name = &(*result->d_name); | |
| 108 if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) { | |
| 109 continue; | |
| 110 } | |
| 111 | |
| 112 char* end; | |
| 113 long entry_fd_long = strtol(entry_name, &end, 10); | |
| 114 if (entry_name[0] == '\0' || *end) { | |
| 115 LOG(ERROR) << "unexpected entry " << entry_name; | |
| 116 return false; | |
| 117 } | |
| 118 | |
| 119 int entry_fd; | |
| 120 if (!AssignIfInRange(&entry_fd, entry_fd_long)) { | |
| 121 LOG(ERROR) << "out-of-range fd " << entry_name; | |
| 122 return false; | |
| 123 } | |
| 124 | |
| 125 if (entry_fd >= fd && entry_fd != preserve_fd && entry_fd != dir_fd) { | |
| 126 CloseNowOrOnExec(entry_fd, false); | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 return true; | |
| 131 } | |
| 132 | |
| 133 } // namespace | |
| 134 | |
| 135 void CloseMultipleNowOrOnExec(int fd, int preserve_fd) { | |
| 136 if (CloseMultipleNowOrOnExecUsingFDDir(fd, preserve_fd)) { | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 // 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 | |
| 142 // 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 | |
| 144 // prior to the limit being lowered. For Mac OS X, see 10.9.2 | |
| 145 // Libc-997.90.3/gen/FreeBSD/sysconf.c sysconf() and 10.9.4 | |
| 146 // xnu-2422.110.17/bsd/kern/kern_descrip.c getdtablesize(), which both return | |
| 147 // the current RLIMIT_NOFILE value, not the maximum possible file descriptor. | |
| 148 int max_fd = std::max(implicit_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX); | |
| 149 max_fd = std::max(max_fd, getdtablesize()); | |
| 150 | |
| 151 for (int entry_fd = fd; entry_fd < max_fd; ++entry_fd) { | |
| 152 if (entry_fd != preserve_fd) { | |
| 153 CloseNowOrOnExec(entry_fd, true); | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 | |
| 158 } // namespace crashpad | |
| OLD | NEW |