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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/common/sandbox_linux.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/common/sandbox_linux.cc
diff --git a/content/common/sandbox_linux.cc b/content/common/sandbox_linux.cc
index 2ce96b67d4514842c6a5d291a98f0f759751ca0f..78ddcccc2cf7a6db4713f807167ad9a3569f73bd 100644
--- a/content/common/sandbox_linux.cc
+++ b/content/common/sandbox_linux.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <dirent.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/stat.h>
@@ -60,6 +61,54 @@ bool IsRunningTSAN() {
#endif
}
+#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.
+// For when using DCHECK would be incorrect, since it can be enabled in
+// 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.
+#define REAL_DEBUG_CHECK(x) CHECK(x)
+#else
+#define REAL_DEBUG_CHECK(x)
+#endif // !defined(NDEBUG)
+
+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
+ public:
+
+ OpenDirDeleter() : dir_(NULL) {}
+
+ ~OpenDirDeleter() {
+ if (dir_) {
+ int result = closedir(dir_);
+ (void)result;
+ REAL_DEBUG_CHECK(result == 0);
+ }
+ }
+
+ // Just like the real fdopendir except it returns bool instead
+ // of a directory stream. Returns false if this method on this object
+ // was successfully called previously, or if the requested dir could not
+ // be opened. Assumes ownership of fd.
+ bool fdopendir(int fd) {
+ if (dir_) {
+ return false;
+ }
+
+ // The "real" fdopendir takes ownership of fd here.
+ dir_ = ::fdopendir(fd);
+ if (!dir_) {
+ return false;
+ }
+ return true;
+ }
+
+ // Call readdir_r on the directory stream descriptor and return the result.
+ int readdir_r(struct dirent *entry, struct dirent **result) {
+ return ::readdir_r(dir_, entry, result);
+ }
+
+ private:
+
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.
+ DIR *dir_;
+};
+
} // namespace
namespace content {
@@ -143,6 +192,12 @@ bool LinuxSandbox::InitializeSandbox() {
return false;
}
+ if (linux_sandbox->HasOpenDirectories()) {
+ 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.
+ "have been opened- the setuid sandbox may be at risk, if "
+ "the BPF sandbox is not running.";
+ }
+
// Attempt to limit the future size of the address space of the process.
linux_sandbox->LimitAddressSpace(process_type);
@@ -208,6 +263,111 @@ bool LinuxSandbox::IsSingleThreaded() const {
return task_stat.st_nlink == 3;
}
+bool LinuxSandbox::HasOpenDirectories() const {
+ // Note: this function won't catch the following cases:
+ // 1) proc_fd_ is valid and /proc is opened elsewhere a second time (but not
+ // closed).
+ // 2) /proc/self/fd is opened elsewhere a second time (but not closed).
+
+ // If /proc is already open, store the device/inode pair that uniquely
+ // identifies it.
+ dev_t proc_device = 0;
+ ino_t proc_inode = 0;
+
+ // To store the device/inode pair that uniquely identifies /proc/self/fd.
+ dev_t proc_self_fd_device = 0;
+ ino_t proc_self_fd_inode = 0;
+
+ int proc_self_fd = 0;
+
+ 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.
+ int stat_res;
+
+ 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
+ proc_self_fd = openat(proc_fd_, "self/fd", O_RDONLY|O_DIRECTORY);
+ 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.
+ if (proc_self_fd == -1) {
+ // We can't read the list of open file descriptors, so guess false.
+ return false;
+ }
+
+ stat_res = fstat(proc_fd_, &s);
+ 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.
+ if (stat_res != 0) {
+ // If we continue, we'll get a false positive, so guess false.
+ return false;
+ }
+ proc_device = s.st_dev;
+ proc_inode = s.st_ino;
+
+ } else {
+ proc_self_fd = open("/proc/self/fd", O_RDONLY|O_DIRECTORY);
+ 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
+ if (proc_self_fd == -1) {
+ // We can't read the list of open file descriptors, so guess false.
+ return false;
+ }
+ }
+
+ stat_res = fstat(proc_self_fd, &s);
+ 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
+ if (stat_res != 0) {
+ // If we continue we'll get a false positive, so guess false.
+ return false;
+ }
+ proc_self_fd_device = s.st_dev;
+ proc_self_fd_inode = s.st_ino;
+
+ // We now have unique identifiers for /proc/self/fd and possibly /proc,
+ // 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
+
+ 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.
+
+ // Ownership of proc_self_fd is transferred here, it must not be closed
+ // or modified afterwards except by odd.
+ if (!odd->fdopendir(proc_self_fd)) {
+ REAL_DEBUG_CHECK(false);
+ // We can't read the list of open file descriptors, so guess false.
+ return false;
+ }
+
+ struct dirent e, *de;
+ while (!odd->readdir_r(&e, &de) && de) {
+ if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0)
+ continue;
+
+ // Stat the file pointed to by the current file descriptor.
+ // It's OK to use proc_self_fd here, fstatat won't modify it.
+ stat_res = fstatat(proc_self_fd, e.d_name, &s, 0);
+ REAL_DEBUG_CHECK(stat_res == 0);
+ if (stat_res != 0) {
+ // We failed to check this file descriptor but maybe a later one will
+ // succeed(?), so let's continue rather than guessing false immediately.
+ continue;
+ }
+
+ if (S_ISDIR(s.st_mode)) {
+ // Check if this directory is one of the managed directories that are
+ // OK to have open.
+
+ if (proc_fd_ != -1 && proc_device
+ && proc_device == s.st_dev && proc_inode == s.st_ino) {
+ continue; // Skip over /proc.
+ }
+
+ if (proc_self_fd_device == s.st_dev && proc_self_fd_inode == s.st_ino) {
+ continue; // Skip over /proc/self/fd.
+ }
+
+ // We found an open dir that wasn't /proc or /proc/self/fd.
+ return true;
+ }
+ }
+
+ // No open unmanaged directories found. \o/
+ return false;
+}
+
bool LinuxSandbox::seccomp_bpf_started() const {
return seccomp_bpf_started_;
}
« 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