Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "fd_utils.h"
     18 
     19 #include <algorithm>
     20 
     21 #include <fcntl.h>
     22 #include <grp.h>
     23 #include <stdlib.h>
     24 #include <sys/socket.h>
     25 #include <sys/types.h>
     26 #include <sys/un.h>
     27 #include <unistd.h>
     28 
     29 #include <android-base/file.h>
     30 #include <android-base/logging.h>
     31 #include <android-base/stringprintf.h>
     32 #include <android-base/strings.h>
     33 
     34 // Static whitelist of open paths that the zygote is allowed to keep open.
     35 static const char* kPathWhitelist[] = {
     36   "/dev/null",
     37   "/dev/socket/zygote",
     38   "/dev/socket/zygote_secondary",
     39   "/dev/socket/webview_zygote",
     40   "/sys/kernel/debug/tracing/trace_marker",
     41   "/system/framework/framework-res.apk",
     42   "/dev/urandom",
     43   "/dev/ion",
     44   "/dev/dri/renderD129", // Fixes b/31172436
     45 };
     46 
     47 static const char kFdPath[] = "/proc/self/fd";
     48 
     49 // static
     50 FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
     51   if (instance_ == nullptr) {
     52     instance_ = new FileDescriptorWhitelist();
     53   }
     54   return instance_;
     55 }
     56 
     57 bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
     58   // Check the static whitelist path.
     59   for (const auto& whitelist_path : kPathWhitelist) {
     60     if (path == whitelist_path)
     61       return true;
     62   }
     63 
     64   // Check any paths added to the dynamic whitelist.
     65   for (const auto& whitelist_path : whitelist_) {
     66     if (path == whitelist_path)
     67       return true;
     68   }
     69 
     70   static const char* kFrameworksPrefix = "/system/framework/";
     71   static const char* kJarSuffix = ".jar";
     72   if (android::base::StartsWith(path, kFrameworksPrefix)
     73       && android::base::EndsWith(path, kJarSuffix)) {
     74     return true;
     75   }
     76 
     77   // Whitelist files needed for Runtime Resource Overlay, like these:
     78   // /system/vendor/overlay/framework-res.apk
     79   // /system/vendor/overlay-subdir/pg/framework-res.apk
     80   // /vendor/overlay/framework-res.apk
     81   // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
     82   // /data/resource-cache/system@vendor@overlay (at) framework-res.apk@idmap
     83   // /data/resource-cache/system@vendor@overlay-subdir@pg (at) framework-res.apk@idmap
     84   // See AssetManager.cpp for more details on overlay-subdir.
     85   static const char* kOverlayDir = "/system/vendor/overlay/";
     86   static const char* kVendorOverlayDir = "/vendor/overlay";
     87   static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
     88   static const char* kSystemProductOverlayDir = "/system/product/overlay/";
     89   static const char* kProductOverlayDir = "/product/overlay";
     90   static const char* kApkSuffix = ".apk";
     91 
     92   if ((android::base::StartsWith(path, kOverlayDir)
     93        || android::base::StartsWith(path, kOverlaySubdir)
     94        || android::base::StartsWith(path, kVendorOverlayDir)
     95        || android::base::StartsWith(path, kSystemProductOverlayDir)
     96        || android::base::StartsWith(path, kProductOverlayDir))
     97       && android::base::EndsWith(path, kApkSuffix)
     98       && path.find("/../") == std::string::npos) {
     99     return true;
    100   }
    101 
    102   static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
    103   static const char* kOverlayIdmapSuffix = ".apk@idmap";
    104   if (android::base::StartsWith(path, kOverlayIdmapPrefix)
    105       && android::base::EndsWith(path, kOverlayIdmapSuffix)
    106       && path.find("/../") == std::string::npos) {
    107     return true;
    108   }
    109 
    110   // All regular files that are placed under this path are whitelisted automatically.
    111   static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
    112   if (android::base::StartsWith(path, kZygoteWhitelistPath)
    113       && path.find("/../") == std::string::npos) {
    114     return true;
    115   }
    116 
    117   return false;
    118 }
    119 
    120 FileDescriptorWhitelist::FileDescriptorWhitelist()
    121     : whitelist_() {
    122 }
    123 
    124 FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
    125 
    126 // Keeps track of all relevant information (flags, offset etc.) of an
    127 // open zygote file descriptor.
    128 class FileDescriptorInfo {
    129  public:
    130   // Create a FileDescriptorInfo for a given file descriptor. Returns
    131   // |NULL| if an error occurred.
    132   static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
    133 
    134   // Checks whether the file descriptor associated with this object
    135   // refers to the same description.
    136   bool Restat() const;
    137 
    138   bool ReopenOrDetach(std::string* error_msg) const;
    139 
    140   const int fd;
    141   const struct stat stat;
    142   const std::string file_path;
    143   const int open_flags;
    144   const int fd_flags;
    145   const int fs_flags;
    146   const off_t offset;
    147   const bool is_sock;
    148 
    149  private:
    150   FileDescriptorInfo(int fd);
    151 
    152   FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
    153                      int fd_flags, int fs_flags, off_t offset);
    154 
    155   // Returns the locally-bound name of the socket |fd|. Returns true
    156   // iff. all of the following hold :
    157   //
    158   // - the socket's sa_family is AF_UNIX.
    159   // - the length of the path is greater than zero (i.e, not an unnamed socket).
    160   // - the first byte of the path isn't zero (i.e, not a socket with an abstract
    161   //   address).
    162   static bool GetSocketName(const int fd, std::string* result);
    163 
    164   bool DetachSocket(std::string* error_msg) const;
    165 
    166   DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
    167 };
    168 
    169 // static
    170 FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
    171   struct stat f_stat;
    172   // This should never happen; the zygote should always have the right set
    173   // of permissions required to stat all its open files.
    174   if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
    175     *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
    176     return nullptr;
    177   }
    178 
    179   const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
    180 
    181   if (S_ISSOCK(f_stat.st_mode)) {
    182     std::string socket_name;
    183     if (!GetSocketName(fd, &socket_name)) {
    184       *error_msg = "Unable to get socket name";
    185       return nullptr;
    186     }
    187 
    188     if (!whitelist->IsAllowed(socket_name)) {
    189       *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
    190                                                socket_name.c_str(),
    191                                                fd);
    192       return nullptr;
    193     }
    194 
    195     return new FileDescriptorInfo(fd);
    196   }
    197 
    198   // We only handle whitelisted regular files and character devices. Whitelisted
    199   // character devices must provide a guarantee of sensible behaviour when
    200   // reopened.
    201   //
    202   // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
    203   // S_ISLINK : Not supported.
    204   // S_ISBLK : Not supported.
    205   // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
    206   // with the child process across forks but those should have been closed
    207   // before we got to this point.
    208   if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
    209     *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
    210     return nullptr;
    211   }
    212 
    213   std::string file_path;
    214   const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
    215   if (!android::base::Readlink(fd_path, &file_path)) {
    216     *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
    217                                              fd_path.c_str(),
    218                                              strerror(errno));
    219     return nullptr;
    220   }
    221 
    222   if (!whitelist->IsAllowed(file_path)) {
    223     *error_msg = std::string("Not whitelisted : ").append(file_path);
    224     return nullptr;
    225   }
    226 
    227   // File descriptor flags : currently on FD_CLOEXEC. We can set these
    228   // using F_SETFD - we're single threaded at this point of execution so
    229   // there won't be any races.
    230   const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
    231   if (fd_flags == -1) {
    232     *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
    233                                              fd,
    234                                              file_path.c_str(),
    235                                              strerror(errno));
    236     return nullptr;
    237   }
    238 
    239   // File status flags :
    240   // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
    241   //   to the open() call.
    242   //
    243   // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
    244   //   do about these, since the file has already been created. We shall ignore
    245   //   them here.
    246   //
    247   // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
    248   //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
    249   //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
    250   //   their presence and pass them in to open().
    251   int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
    252   if (fs_flags == -1) {
    253     *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
    254                                              fd,
    255                                              file_path.c_str(),
    256                                              strerror(errno));
    257     return nullptr;
    258   }
    259 
    260   // File offset : Ignore the offset for non seekable files.
    261   const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
    262 
    263   // We pass the flags that open accepts to open, and use F_SETFL for
    264   // the rest of them.
    265   static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
    266   int open_flags = fs_flags & (kOpenFlags);
    267   fs_flags = fs_flags & (~(kOpenFlags));
    268 
    269   return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
    270 }
    271 
    272 bool FileDescriptorInfo::Restat() const {
    273   struct stat f_stat;
    274   if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
    275     PLOG(ERROR) << "Unable to restat fd " << fd;
    276     return false;
    277   }
    278 
    279   return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
    280 }
    281 
    282 bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
    283   if (is_sock) {
    284     return DetachSocket(error_msg);
    285   }
    286 
    287   // NOTE: This might happen if the file was unlinked after being opened.
    288   // It's a common pattern in the case of temporary files and the like but
    289   // we should not allow such usage from the zygote.
    290   const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
    291 
    292   if (new_fd == -1) {
    293     *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
    294                                              file_path.c_str(),
    295                                              open_flags,
    296                                              strerror(errno));
    297     return false;
    298   }
    299 
    300   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
    301     close(new_fd);
    302     *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
    303                                              new_fd,
    304                                              fd_flags,
    305                                              file_path.c_str(),
    306                                              strerror(errno));
    307     return false;
    308   }
    309 
    310   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
    311     close(new_fd);
    312     *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
    313                                              new_fd,
    314                                              fs_flags,
    315                                              file_path.c_str(),
    316                                              strerror(errno));
    317     return false;
    318   }
    319 
    320   if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
    321     close(new_fd);
    322     *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
    323                                              new_fd,
    324                                              file_path.c_str(),
    325                                              strerror(errno));
    326     return false;
    327   }
    328 
    329   if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
    330     close(new_fd);
    331     *error_msg = android::base::StringPrintf("Failed dup2(%d, %d) (%s): %s",
    332                                              fd,
    333                                              new_fd,
    334                                              file_path.c_str(),
    335                                              strerror(errno));
    336     return false;
    337   }
    338 
    339   close(new_fd);
    340 
    341   return true;
    342 }
    343 
    344 FileDescriptorInfo::FileDescriptorInfo(int fd) :
    345   fd(fd),
    346   stat(),
    347   open_flags(0),
    348   fd_flags(0),
    349   fs_flags(0),
    350   offset(0),
    351   is_sock(true) {
    352 }
    353 
    354 FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path,
    355                                        int fd, int open_flags, int fd_flags, int fs_flags,
    356                                        off_t offset) :
    357   fd(fd),
    358   stat(stat),
    359   file_path(file_path),
    360   open_flags(open_flags),
    361   fd_flags(fd_flags),
    362   fs_flags(fs_flags),
    363   offset(offset),
    364   is_sock(false) {
    365 }
    366 
    367 // static
    368 bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
    369   sockaddr_storage ss;
    370   sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
    371   socklen_t addr_len = sizeof(ss);
    372 
    373   if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
    374     PLOG(ERROR) << "Failed getsockname(" << fd << ")";
    375     return false;
    376   }
    377 
    378   if (addr->sa_family != AF_UNIX) {
    379     LOG(ERROR) << "Unsupported socket (fd=" << fd << ") with family " << addr->sa_family;
    380     return false;
    381   }
    382 
    383   const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
    384 
    385   size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
    386   // This is an unnamed local socket, we do not accept it.
    387   if (path_len == 0) {
    388     LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with empty path.";
    389     return false;
    390   }
    391 
    392   // This is a local socket with an abstract address. Remove the leading NUL byte and
    393   // add a human-readable "ABSTRACT/" prefix.
    394   if (unix_addr->sun_path[0] == '\0') {
    395     *result = "ABSTRACT/";
    396     result->append(&unix_addr->sun_path[1], path_len - 1);
    397     return true;
    398   }
    399 
    400   // If we're here, sun_path must refer to a null terminated filesystem
    401   // pathname (man 7 unix). Remove the terminator before assigning it to an
    402   // std::string.
    403   if (unix_addr->sun_path[path_len - 1] ==  '\0') {
    404     --path_len;
    405   }
    406 
    407   result->assign(unix_addr->sun_path, path_len);
    408   return true;
    409 }
    410 
    411 bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
    412   const int dev_null_fd = open("/dev/null", O_RDWR);
    413   if (dev_null_fd < 0) {
    414     *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
    415     return false;
    416   }
    417 
    418   if (dup2(dev_null_fd, fd) == -1) {
    419     *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
    420                                              fd,
    421                                              strerror(errno));
    422     return false;
    423   }
    424 
    425   if (close(dev_null_fd) == -1) {
    426     *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
    427     return false;
    428   }
    429 
    430   return true;
    431 }
    432 
    433 // static
    434 FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
    435                                                  std::string* error_msg) {
    436   DIR* d = opendir(kFdPath);
    437   if (d == nullptr) {
    438     *error_msg = std::string("Unable to open directory ").append(kFdPath);
    439     return nullptr;
    440   }
    441   int dir_fd = dirfd(d);
    442   dirent* e;
    443 
    444   std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
    445   while ((e = readdir(d)) != NULL) {
    446     const int fd = ParseFd(e, dir_fd);
    447     if (fd == -1) {
    448       continue;
    449     }
    450     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
    451       LOG(INFO) << "Ignoring open file descriptor " << fd;
    452       continue;
    453     }
    454 
    455     FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
    456     if (info == NULL) {
    457       if (closedir(d) == -1) {
    458         PLOG(ERROR) << "Unable to close directory";
    459       }
    460       return NULL;
    461     }
    462     open_fd_map[fd] = info;
    463   }
    464 
    465   if (closedir(d) == -1) {
    466     *error_msg = "Unable to close directory";
    467     return nullptr;
    468   }
    469   return new FileDescriptorTable(open_fd_map);
    470 }
    471 
    472 bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
    473   std::set<int> open_fds;
    474 
    475   // First get the list of open descriptors.
    476   DIR* d = opendir(kFdPath);
    477   if (d == NULL) {
    478     *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
    479                                              kFdPath,
    480                                              strerror(errno));
    481     return false;
    482   }
    483 
    484   int dir_fd = dirfd(d);
    485   dirent* e;
    486   while ((e = readdir(d)) != NULL) {
    487     const int fd = ParseFd(e, dir_fd);
    488     if (fd == -1) {
    489       continue;
    490     }
    491     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
    492       LOG(INFO) << "Ignoring open file descriptor " << fd;
    493       continue;
    494     }
    495 
    496     open_fds.insert(fd);
    497   }
    498 
    499   if (closedir(d) == -1) {
    500     *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
    501     return false;
    502   }
    503 
    504   return RestatInternal(open_fds, error_msg);
    505 }
    506 
    507 // Reopens all file descriptors that are contained in the table. Returns true
    508 // if all descriptors were successfully re-opened or detached, and false if an
    509 // error occurred.
    510 bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
    511   std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
    512   for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
    513     const FileDescriptorInfo* info = it->second;
    514     if (info == NULL || !info->ReopenOrDetach(error_msg)) {
    515       return false;
    516     }
    517   }
    518 
    519   return true;
    520 }
    521 
    522 FileDescriptorTable::FileDescriptorTable(
    523     const std::unordered_map<int, FileDescriptorInfo*>& map)
    524     : open_fd_map_(map) {
    525 }
    526 
    527 bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
    528   bool error = false;
    529 
    530   // Iterate through the list of file descriptors we've already recorded
    531   // and check whether :
    532   //
    533   // (a) they continue to be open.
    534   // (b) they refer to the same file.
    535   //
    536   // We'll only store the last error message.
    537   std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
    538   while (it != open_fd_map_.end()) {
    539     std::set<int>::const_iterator element = open_fds.find(it->first);
    540     if (element == open_fds.end()) {
    541       // The entry from the file descriptor table is no longer in the list
    542       // of open files. We warn about this condition and remove it from
    543       // the list of FDs under consideration.
    544       //
    545       // TODO(narayan): This will be an error in a future android release.
    546       // error = true;
    547       // ALOGW("Zygote closed file descriptor %d.", it->first);
    548       it = open_fd_map_.erase(it);
    549     } else {
    550       // The entry from the file descriptor table is still open. Restat
    551       // it and check whether it refers to the same file.
    552       const bool same_file = it->second->Restat();
    553       if (!same_file) {
    554         // The file descriptor refers to a different description. We must
    555         // update our entry in the table.
    556         delete it->second;
    557         it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
    558         if (it->second == NULL) {
    559           // The descriptor no longer no longer refers to a whitelisted file.
    560           // We flag an error and remove it from the list of files we're
    561           // tracking.
    562           error = true;
    563           it = open_fd_map_.erase(it);
    564         } else {
    565           // Successfully restatted the file, move on to the next open FD.
    566           ++it;
    567         }
    568       } else {
    569         // It's the same file. Nothing to do here. Move on to the next open
    570         // FD.
    571         ++it;
    572       }
    573 
    574       // Finally, remove the FD from the set of open_fds. We do this last because
    575       // |element| will not remain valid after a call to erase.
    576       open_fds.erase(element);
    577     }
    578   }
    579 
    580   if (open_fds.size() > 0) {
    581     // The zygote has opened new file descriptors since our last inspection.
    582     // We warn about this condition and add them to our table.
    583     //
    584     // TODO(narayan): This will be an error in a future android release.
    585     // error = true;
    586     // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
    587 
    588     // TODO(narayan): This code will be removed in a future android release.
    589     std::set<int>::const_iterator it;
    590     for (it = open_fds.begin(); it != open_fds.end(); ++it) {
    591       const int fd = (*it);
    592       FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
    593       if (info == NULL) {
    594         // A newly opened file is not on the whitelist. Flag an error and
    595         // continue.
    596         error = true;
    597       } else {
    598         // Track the newly opened file.
    599         open_fd_map_[fd] = info;
    600       }
    601     }
    602   }
    603 
    604   return !error;
    605 }
    606 
    607 // static
    608 int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
    609   char* end;
    610   const int fd = strtol(e->d_name, &end, 10);
    611   if ((*end) != '\0') {
    612     return -1;
    613   }
    614 
    615   // Don't bother with the standard input/output/error, they're handled
    616   // specially post-fork anyway.
    617   if (fd <= STDERR_FILENO || fd == dir_fd) {
    618     return -1;
    619   }
    620 
    621   return fd;
    622 }
    623