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