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 {
operator ()sandbox::__anon7fa5a7a90111::DIRCloser24 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
OpenDirectory(const char * path)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
CountOpenFds(int proc_fd)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
HasOpenDirectory(int proc_fd)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
HasOpenDirectory()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
OpenProc()116 base::ScopedFD ProcUtil::OpenProc() {
117 return OpenDirectory("/proc/");
118 }
119
120 } // namespace sandbox
121