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..a805bd869b0c692996241ffc97c5c48b6a698c72 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> |
| @@ -16,6 +17,7 @@ |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| #include "base/posix/eintr_wrapper.h" |
| +#include "base/strings/string_number_conversions.h" |
| #include "base/time/time.h" |
| #include "content/common/sandbox_linux.h" |
| #include "content/common/sandbox_seccomp_bpf_linux.h" |
| @@ -60,6 +62,12 @@ bool IsRunningTSAN() { |
| #endif |
| } |
| +struct DIRDeleter { |
| + void operator()(DIR *d) { |
| + CHECK(closedir(d) == 0); |
| + } |
| +}; |
| + |
| } // namespace |
| namespace content { |
| @@ -68,6 +76,7 @@ LinuxSandbox::LinuxSandbox() |
| : proc_fd_(-1), |
| seccomp_bpf_started_(false), |
| pre_initialized_(false), |
| + sealed_(false), |
| seccomp_bpf_supported_(false), |
| setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { |
| if (setuid_sandbox_client_ == NULL) { |
| @@ -91,6 +100,7 @@ extern "C" void __sanitizer_sandbox_on_notify(void *reserved); |
| void LinuxSandbox::PreinitializeSandbox() { |
| CHECK(!pre_initialized_); |
| + CHECK(!sealed_); |
| seccomp_bpf_supported_ = false; |
| #if defined(ADDRESS_SANITIZER) && defined(OS_LINUX) |
| // ASan needs to open some resources before the sandbox is enabled. |
| @@ -98,12 +108,8 @@ void LinuxSandbox::PreinitializeSandbox() { |
| __sanitizer_sandbox_on_notify(/*reserved*/NULL); |
| #endif |
| -#if !defined(NDEBUG) |
| - // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't |
| - // produce a sandbox escape in Release mode. |
| - proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); |
| - CHECK_GE(proc_fd_, 0); |
| -#endif // !defined(NDEBUG) |
| + OpenProc(); |
| + |
| // We "pre-warm" the code that detects supports for seccomp BPF. |
| if (SandboxSeccompBpf::IsSeccompBpfDesired()) { |
| if (!SandboxSeccompBpf::SupportsSandbox()) { |
| @@ -118,6 +124,7 @@ void LinuxSandbox::PreinitializeSandbox() { |
| bool LinuxSandbox::InitializeSandbox() { |
| bool seccomp_bpf_started = false; |
| LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
| + CHECK(!linux_sandbox->sealed_); |
| // We need to make absolutely sure that our sandbox is "sealed" before |
| // InitializeSandbox does exit. |
| base::ScopedClosureRunner sandbox_sealer( |
| @@ -143,6 +150,12 @@ bool LinuxSandbox::InitializeSandbox() { |
| return false; |
| } |
| + if (linux_sandbox->HasOpenDirectories()) { |
| + LOG(FATAL) << "InitializeSandbox() called after unexpected directories " |
| + "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 +221,60 @@ bool LinuxSandbox::IsSingleThreaded() const { |
| return task_stat.st_nlink == 3; |
| } |
| +bool LinuxSandbox::OpenProc() { |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
Please, remove this.
Mostyn Bramley-Moore
2013/11/01 22:22:40
Done.
|
| + CHECK(!sealed_); |
| +#if !defined(NDEBUG) |
| + if (proc_fd_ == -1) { |
| + // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't |
| + // produce a sandbox escape in Release mode. |
| + proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); |
| + CHECK_GE(proc_fd_, 0); |
| + } |
| + return true; |
| +#else |
| + return false; |
| +#endif // !defined(NDEBUG) |
| +} |
| + |
| +bool LinuxSandbox::HasOpenDirectories() { |
| + CHECK(!sealed_); |
| + if (!OpenProc()) { |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
You don't need to do the OpenProc() thing, it adds
Mostyn Bramley-Moore
2013/11/01 22:22:40
Done- I assume you mean errno == ENOENT ?
|
| + // We must not be in debug mode, so guess false; |
| + return false; |
| + } |
| + |
| + int proc_self_fd = openat(proc_fd_, "self/fd", O_RDONLY|O_DIRECTORY); |
| + CHECK(proc_self_fd != -1); |
| + |
| + // Ownership of proc_self_fd is transferred here, it must not be closed |
| + // or modified afterwards except via dir. |
| + DIR *dir = fdopendir(proc_self_fd); |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
Style: I don't like it but the style is T* ptr, no
Mostyn Bramley-Moore
2013/11/01 22:22:40
Done.
|
| + CHECK(dir); |
| + scoped_ptr<DIR, DIRDeleter> dir_fd(dir); |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
Just have directly:
scoped_ptr<DIR, DIRDeleter> d
Mostyn Bramley-Moore
2013/11/01 22:22:40
Done.
|
| + |
| + struct dirent e, *de; |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
Style: on two different lines
Unfortunately the st
Mostyn Bramley-Moore
2013/11/01 22:22:40
Done.
|
| + while (!readdir_r(dir, &e, &de) && de) { |
| + if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) |
| + continue; |
| + |
| + int fd_num; |
| + CHECK(base::StringToInt(e.d_name, &fd_num)); |
| + if (fd_num == proc_fd_ || fd_num == proc_self_fd) { |
| + continue; |
| + } |
| + |
| + struct stat s; |
| + // It's OK to use proc_self_fd here, fstatat won't modify it. |
|
jln (very slow on Chromium)
2013/11/01 18:55:37
Maybe it's more readable with dirfd(dir.get()) ? Y
Mostyn Bramley-Moore
2013/11/01 22:22:40
IMO it's more obvious to people reading this code
|
| + CHECK(fstatat(proc_self_fd, e.d_name, &s, 0) == 0); |
| + if (S_ISDIR(s.st_mode)) { |
| + return true; |
| + } |
| + } |
| + |
| + // No open unmanaged directories found. \o/ |
| + return false; |
| +} |
| + |
| bool LinuxSandbox::seccomp_bpf_started() const { |
| return seccomp_bpf_started_; |
| } |
| @@ -282,6 +349,7 @@ void LinuxSandbox::SealSandbox() { |
| CHECK_EQ(0, ret); |
| proc_fd_ = -1; |
| } |
| + sealed_ = true; |
| } |
| } // namespace content |