Chromium Code Reviews| 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_; |
| } |