Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(933)

Side by Side Diff: content/common/sandbox_linux.cc

Issue 24055003: add a LinuxSandbox::HasOpenDirectories() sanity check (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: try to be more careful Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/common/sandbox_linux.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « content/common/sandbox_linux.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698