OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <dirent.h> | |
5 #include <fcntl.h> | 6 #include <fcntl.h> |
6 #include <sys/resource.h> | 7 #include <sys/resource.h> |
7 #include <sys/stat.h> | 8 #include <sys/stat.h> |
8 #include <sys/time.h> | 9 #include <sys/time.h> |
9 #include <sys/types.h> | 10 #include <sys/types.h> |
10 | 11 |
11 #include <limits> | 12 #include <limits> |
12 | 13 |
13 #include "base/bind.h" | 14 #include "base/bind.h" |
14 #include "base/callback_helpers.h" | 15 #include "base/callback_helpers.h" |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 } | 54 } |
54 | 55 |
55 bool IsRunningTSAN() { | 56 bool IsRunningTSAN() { |
56 #if defined(THREAD_SANITIZER) | 57 #if defined(THREAD_SANITIZER) |
57 return true; | 58 return true; |
58 #else | 59 #else |
59 return false; | 60 return false; |
60 #endif | 61 #endif |
61 } | 62 } |
62 | 63 |
64 #if !defined(NDEBUG) | |
jln (very slow on Chromium)
2013/10/25 19:49:52
Maybe do DEBUG_NOTREACHED() instead which does CHE
Mostyn Bramley-Moore
2013/10/26 07:53:44
Removed this in favour of DIRDeleter.
| |
65 // For when using DCHECK would be incorrect, since it can be enabled in | |
66 // non official release mode. | |
jln (very slow on Chromium)
2013/10/25 19:49:52
Just explain what it does, the "for when using DCH
Mostyn Bramley-Moore
2013/10/26 07:53:44
Removed this in favour of DIRDeleter.
| |
67 #define REAL_DEBUG_CHECK(x) CHECK(x) | |
68 #else | |
69 #define REAL_DEBUG_CHECK(x) | |
70 #endif // !defined(NDEBUG) | |
71 | |
72 class OpenDirDeleter { | |
jln (very slow on Chromium)
2013/10/25 19:49:52
Sorry, what I meant by creating an OpenDirDeleter(
Mostyn Bramley-Moore
2013/10/26 07:53:44
I hadn't noticed this version of scoped_ptr- looks
| |
73 public: | |
74 | |
75 OpenDirDeleter() : dir_(NULL) {} | |
76 | |
77 ~OpenDirDeleter() { | |
78 if (dir_) { | |
79 int result = closedir(dir_); | |
80 (void)result; | |
81 REAL_DEBUG_CHECK(result == 0); | |
82 } | |
83 } | |
84 | |
85 // Just like the real fdopendir except it returns bool instead | |
86 // of a directory stream. Returns false if this method on this object | |
87 // was successfully called previously, or if the requested dir could not | |
88 // be opened. Assumes ownership of fd. | |
89 bool fdopendir(int fd) { | |
90 if (dir_) { | |
91 return false; | |
92 } | |
93 | |
94 // The "real" fdopendir takes ownership of fd here. | |
95 dir_ = ::fdopendir(fd); | |
96 if (!dir_) { | |
97 return false; | |
98 } | |
99 return true; | |
100 } | |
101 | |
102 // Call readdir_r on the directory stream descriptor and return the result. | |
103 int readdir_r(struct dirent *entry, struct dirent **result) { | |
104 return ::readdir_r(dir_, entry, result); | |
105 } | |
106 | |
107 private: | |
108 | |
jln (very slow on Chromium)
2013/10/25 19:49:52
FYI (since this class may disappear): always add D
Mostyn Bramley-Moore
2013/10/25 20:41:15
Will do, thanks for the tip.
| |
109 DIR *dir_; | |
110 }; | |
111 | |
63 } // namespace | 112 } // namespace |
64 | 113 |
65 namespace content { | 114 namespace content { |
66 | 115 |
67 LinuxSandbox::LinuxSandbox() | 116 LinuxSandbox::LinuxSandbox() |
68 : proc_fd_(-1), | 117 : proc_fd_(-1), |
69 seccomp_bpf_started_(false), | 118 seccomp_bpf_started_(false), |
70 pre_initialized_(false), | 119 pre_initialized_(false), |
71 seccomp_bpf_supported_(false), | 120 seccomp_bpf_supported_(false), |
72 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { | 121 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
136 if (IsRunningTSAN()) | 185 if (IsRunningTSAN()) |
137 return false; | 186 return false; |
138 // The GPU process is allowed to call InitializeSandbox() with threads for | 187 // The GPU process is allowed to call InitializeSandbox() with threads for |
139 // now, because it loads third party libraries. | 188 // now, because it loads third party libraries. |
140 if (process_type != switches::kGpuProcess) | 189 if (process_type != switches::kGpuProcess) |
141 CHECK(false) << error_message; | 190 CHECK(false) << error_message; |
142 LOG(ERROR) << error_message; | 191 LOG(ERROR) << error_message; |
143 return false; | 192 return false; |
144 } | 193 } |
145 | 194 |
195 if (linux_sandbox->HasOpenDirectories()) { | |
196 LOG(FATAL) << "InitializeSandbox() called after unexpected directries " | |
jln (very slow on Chromium)
2013/10/25 19:49:52
nit: directories
Mostyn Bramley-Moore
2013/10/26 07:53:44
Done.
| |
197 "have been opened- the setuid sandbox may be at risk, if " | |
198 "the BPF sandbox is not running."; | |
199 } | |
200 | |
146 // Attempt to limit the future size of the address space of the process. | 201 // Attempt to limit the future size of the address space of the process. |
147 linux_sandbox->LimitAddressSpace(process_type); | 202 linux_sandbox->LimitAddressSpace(process_type); |
148 | 203 |
149 // First, try to enable seccomp-bpf. | 204 // First, try to enable seccomp-bpf. |
150 seccomp_bpf_started = linux_sandbox->StartSeccompBpf(process_type); | 205 seccomp_bpf_started = linux_sandbox->StartSeccompBpf(process_type); |
151 | 206 |
152 return seccomp_bpf_started; | 207 return seccomp_bpf_started; |
153 } | 208 } |
154 | 209 |
155 int LinuxSandbox::GetStatus() const { | 210 int LinuxSandbox::GetStatus() const { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 } | 256 } |
202 | 257 |
203 // At least "..", "." and the current thread should be present. | 258 // At least "..", "." and the current thread should be present. |
204 CHECK_LE(3UL, task_stat.st_nlink); | 259 CHECK_LE(3UL, task_stat.st_nlink); |
205 // Counting threads via /proc/self/task could be racy. For the purpose of | 260 // Counting threads via /proc/self/task could be racy. For the purpose of |
206 // determining if the current proces is monothreaded it works: if at any | 261 // determining if the current proces is monothreaded it works: if at any |
207 // time it becomes monothreaded, it'll stay so. | 262 // time it becomes monothreaded, it'll stay so. |
208 return task_stat.st_nlink == 3; | 263 return task_stat.st_nlink == 3; |
209 } | 264 } |
210 | 265 |
266 bool LinuxSandbox::HasOpenDirectories() const { | |
267 // Note: this function won't catch the following cases: | |
268 // 1) proc_fd_ is valid and /proc is opened elsewhere a second time (but not | |
269 // closed). | |
270 // 2) /proc/self/fd is opened elsewhere a second time (but not closed). | |
271 | |
272 // If /proc is already open, store the device/inode pair that uniquely | |
273 // identifies it. | |
274 dev_t proc_device = 0; | |
275 ino_t proc_inode = 0; | |
276 | |
277 // To store the device/inode pair that uniquely identifies /proc/self/fd. | |
278 dev_t proc_self_fd_device = 0; | |
279 ino_t proc_self_fd_inode = 0; | |
280 | |
281 int proc_self_fd = 0; | |
282 | |
283 struct stat s; | |
jln (very slow on Chromium)
2013/10/25 19:49:52
Please, scope your variables as much as possible.
Mostyn Bramley-Moore
2013/10/26 07:53:44
Done.
| |
284 int stat_res; | |
285 | |
286 if (proc_fd_ >= 0) { | |
jln (very slow on Chromium)
2013/10/25 19:49:52
You're handling the case where we don't have proc_
Mostyn Bramley-Moore
2013/10/25 20:41:15
I could leave a "the code after this point can ass
jln (very slow on Chromium)
2013/10/26 01:15:15
We should check that in debug mode we have proc_fd
Mostyn Bramley-Moore
2013/10/26 07:53:44
Rather than create a local proc_fd and having to b
| |
287 proc_self_fd = openat(proc_fd_, "self/fd", O_RDONLY|O_DIRECTORY); | |
288 REAL_DEBUG_CHECK(proc_self_fd != -1); | |
jln (very slow on Chromium)
2013/10/25 19:49:52
This should be a normal CHECK.
Mostyn Bramley-Moore
2013/10/26 07:53:44
Done.
| |
289 if (proc_self_fd == -1) { | |
290 // We can't read the list of open file descriptors, so guess false. | |
291 return false; | |
292 } | |
293 | |
294 stat_res = fstat(proc_fd_, &s); | |
295 REAL_DEBUG_CHECK(stat_res == 0); | |
jln (very slow on Chromium)
2013/10/25 19:49:52
This could be a normal check
Mostyn Bramley-Moore
2013/10/26 07:53:44
Removed this, since we don't need to stat /proc.
| |
296 if (stat_res != 0) { | |
297 // If we continue, we'll get a false positive, so guess false. | |
298 return false; | |
299 } | |
300 proc_device = s.st_dev; | |
301 proc_inode = s.st_ino; | |
302 | |
303 } else { | |
304 proc_self_fd = open("/proc/self/fd", O_RDONLY|O_DIRECTORY); | |
305 REAL_DEBUG_CHECK(proc_self_fd != -1); | |
jln (very slow on Chromium)
2013/10/25 19:49:52
This should be a normal CHECK
Mostyn Bramley-Moore
2013/10/26 07:53:44
Removed this case, since we return early if proc_f
| |
306 if (proc_self_fd == -1) { | |
307 // We can't read the list of open file descriptors, so guess false. | |
308 return false; | |
309 } | |
310 } | |
311 | |
312 stat_res = fstat(proc_self_fd, &s); | |
313 REAL_DEBUG_CHECK(stat_res == 0); | |
jln (very slow on Chromium)
2013/10/25 19:49:52
This should be a normal CHECK
Mostyn Bramley-Moore
2013/10/26 07:53:44
Removed this, since we don't need to stat /proc/se
| |
314 if (stat_res != 0) { | |
315 // If we continue we'll get a false positive, so guess false. | |
316 return false; | |
317 } | |
318 proc_self_fd_device = s.st_dev; | |
319 proc_self_fd_inode = s.st_ino; | |
320 | |
321 // We now have unique identifiers for /proc/self/fd and possibly /proc, | |
322 // let's see if there are any other directories open. | |
jln (very slow on Chromium)
2013/10/25 19:49:52
Are you hitting issue with implementation details
Mostyn Bramley-Moore
2013/10/25 20:41:15
No, I'm just trying to be more thorough and cover
jln (very slow on Chromium)
2013/10/26 01:15:15
No, we absolutely need to fail in this case, that'
Mostyn Bramley-Moore
2013/10/26 07:53:44
Ah right, I misunderstood this part of the dup man
| |
323 | |
324 scoped_ptr<OpenDirDeleter> odd(new OpenDirDeleter()); | |
jln (very slow on Chromium)
2013/10/25 19:49:52
As explained above, I was thinking of a custom del
Mostyn Bramley-Moore
2013/10/26 07:53:44
Done.
| |
325 | |
326 // Ownership of proc_self_fd is transferred here, it must not be closed | |
327 // or modified afterwards except by odd. | |
328 if (!odd->fdopendir(proc_self_fd)) { | |
329 REAL_DEBUG_CHECK(false); | |
330 // We can't read the list of open file descriptors, so guess false. | |
331 return false; | |
332 } | |
333 | |
334 struct dirent e, *de; | |
335 while (!odd->readdir_r(&e, &de) && de) { | |
336 if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) | |
337 continue; | |
338 | |
339 // Stat the file pointed to by the current file descriptor. | |
340 // It's OK to use proc_self_fd here, fstatat won't modify it. | |
341 stat_res = fstatat(proc_self_fd, e.d_name, &s, 0); | |
342 REAL_DEBUG_CHECK(stat_res == 0); | |
343 if (stat_res != 0) { | |
344 // We failed to check this file descriptor but maybe a later one will | |
345 // succeed(?), so let's continue rather than guessing false immediately. | |
346 continue; | |
347 } | |
348 | |
349 if (S_ISDIR(s.st_mode)) { | |
350 // Check if this directory is one of the managed directories that are | |
351 // OK to have open. | |
352 | |
353 if (proc_fd_ != -1 && proc_device | |
354 && proc_device == s.st_dev && proc_inode == s.st_ino) { | |
355 continue; // Skip over /proc. | |
356 } | |
357 | |
358 if (proc_self_fd_device == s.st_dev && proc_self_fd_inode == s.st_ino) { | |
359 continue; // Skip over /proc/self/fd. | |
360 } | |
361 | |
362 // We found an open dir that wasn't /proc or /proc/self/fd. | |
363 return true; | |
364 } | |
365 } | |
366 | |
367 // No open unmanaged directories found. \o/ | |
368 return false; | |
369 } | |
370 | |
211 bool LinuxSandbox::seccomp_bpf_started() const { | 371 bool LinuxSandbox::seccomp_bpf_started() const { |
212 return seccomp_bpf_started_; | 372 return seccomp_bpf_started_; |
213 } | 373 } |
214 | 374 |
215 sandbox::SetuidSandboxClient* | 375 sandbox::SetuidSandboxClient* |
216 LinuxSandbox::setuid_sandbox_client() const { | 376 LinuxSandbox::setuid_sandbox_client() const { |
217 return setuid_sandbox_client_.get(); | 377 return setuid_sandbox_client_.get(); |
218 } | 378 } |
219 | 379 |
220 // For seccomp-bpf, we use the SandboxSeccompBpf class. | 380 // For seccomp-bpf, we use the SandboxSeccompBpf class. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
279 void LinuxSandbox::SealSandbox() { | 439 void LinuxSandbox::SealSandbox() { |
280 if (proc_fd_ >= 0) { | 440 if (proc_fd_ >= 0) { |
281 int ret = HANDLE_EINTR(close(proc_fd_)); | 441 int ret = HANDLE_EINTR(close(proc_fd_)); |
282 CHECK_EQ(0, ret); | 442 CHECK_EQ(0, ret); |
283 proc_fd_ = -1; | 443 proc_fd_ = -1; |
284 } | 444 } |
285 } | 445 } |
286 | 446 |
287 } // namespace content | 447 } // namespace content |
288 | 448 |
OLD | NEW |