Home | History | Annotate | Download | only in services
      1 // Copyright 2014 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 "sandbox/linux/services/proc_util.h"
      6 
      7 #include <dirent.h>
      8 #include <errno.h>
      9 #include <fcntl.h>
     10 #include <string.h>
     11 #include <sys/stat.h>
     12 #include <sys/types.h>
     13 
     14 #include <memory>
     15 
     16 #include "base/logging.h"
     17 #include "base/posix/eintr_wrapper.h"
     18 #include "base/strings/string_number_conversions.h"
     19 
     20 namespace sandbox {
     21 namespace {
     22 
     23 struct DIRCloser {
     24   void operator()(DIR* d) const {
     25     DCHECK(d);
     26     PCHECK(0 == closedir(d));
     27   }
     28 };
     29 
     30 typedef std::unique_ptr<DIR, DIRCloser> ScopedDIR;
     31 
     32 base::ScopedFD OpenDirectory(const char* path) {
     33   DCHECK(path);
     34   base::ScopedFD directory_fd(
     35       HANDLE_EINTR(open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
     36   PCHECK(directory_fd.is_valid());
     37   return directory_fd;
     38 }
     39 
     40 }  // namespace
     41 
     42 int ProcUtil::CountOpenFds(int proc_fd) {
     43   DCHECK_LE(0, proc_fd);
     44   int proc_self_fd = HANDLE_EINTR(
     45       openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
     46   PCHECK(0 <= proc_self_fd);
     47 
     48   // Ownership of proc_self_fd is transferred here, it must not be closed
     49   // or modified afterwards except via dir.
     50   ScopedDIR dir(fdopendir(proc_self_fd));
     51   CHECK(dir);
     52 
     53   int count = 0;
     54   struct dirent e;
     55   struct dirent* de;
     56   while (!readdir_r(dir.get(), &e, &de) && de) {
     57     if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
     58       continue;
     59     }
     60 
     61     int fd_num;
     62     CHECK(base::StringToInt(e.d_name, &fd_num));
     63     if (fd_num == proc_fd || fd_num == proc_self_fd) {
     64       continue;
     65     }
     66 
     67     ++count;
     68   }
     69   return count;
     70 }
     71 
     72 bool ProcUtil::HasOpenDirectory(int proc_fd) {
     73   DCHECK_LE(0, proc_fd);
     74   int proc_self_fd =
     75       openat(proc_fd, "self/fd/", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
     76 
     77   PCHECK(0 <= proc_self_fd);
     78 
     79   // Ownership of proc_self_fd is transferred here, it must not be closed
     80   // or modified afterwards except via dir.
     81   ScopedDIR dir(fdopendir(proc_self_fd));
     82   CHECK(dir);
     83 
     84   struct dirent e;
     85   struct dirent* de;
     86   while (!readdir_r(dir.get(), &e, &de) && de) {
     87     if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
     88       continue;
     89     }
     90 
     91     int fd_num;
     92     CHECK(base::StringToInt(e.d_name, &fd_num));
     93     if (fd_num == proc_fd || fd_num == proc_self_fd) {
     94       continue;
     95     }
     96 
     97     struct stat s;
     98     // It's OK to use proc_self_fd here, fstatat won't modify it.
     99     CHECK(fstatat(proc_self_fd, e.d_name, &s, 0) == 0);
    100     if (S_ISDIR(s.st_mode)) {
    101       return true;
    102     }
    103   }
    104 
    105   // No open unmanaged directories found.
    106   return false;
    107 }
    108 
    109 bool ProcUtil::HasOpenDirectory() {
    110   base::ScopedFD proc_fd(
    111       HANDLE_EINTR(open("/proc/", O_DIRECTORY | O_RDONLY | O_CLOEXEC)));
    112   return HasOpenDirectory(proc_fd.get());
    113 }
    114 
    115 // static
    116 base::ScopedFD ProcUtil::OpenProc() {
    117   return OpenDirectory("/proc/");
    118 }
    119 
    120 }  // namespace sandbox
    121