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