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