Index: content/common/sandbox_linux.cc |
diff --git a/content/common/sandbox_linux.cc b/content/common/sandbox_linux.cc |
index 2ce96b67d4514842c6a5d291a98f0f759751ca0f..94d3d4ecac67528c3ac1d38f34ee66e79bdba250 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); |
jln (very slow on Chromium)
2013/11/02 00:10:56
You can even use PCHECK().
Mostyn Bramley-Moore
2013/11/02 07:30:07
Done.
|
+ } |
+}; |
+ |
} // 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. |
@@ -118,6 +128,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 +154,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 " |
jln (very slow on Chromium)
2013/11/02 00:10:56
I would drop the detail about the BPF sandbox and
Mostyn Bramley-Moore
2013/11/02 07:30:07
Done.
|
+ "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 +225,50 @@ bool LinuxSandbox::IsSingleThreaded() const { |
return task_stat.st_nlink == 3; |
} |
+bool LinuxSandbox::HasOpenDirectories() { |
+ CHECK(!sealed_); |
+ |
+ int proc_self_fd = -1; |
+ if (proc_fd_ >= 0) { |
+ proc_self_fd = openat(proc_fd_, "self/fd", O_DIRECTORY | O_RDONLY); |
+ } else { |
+ proc_self_fd = openat(AT_FDCWD, "/proc/self/fd", O_DIRECTORY | O_RDONLY); |
+ if ((proc_self_fd < 0) && errno == ENOENT) { |
+ // Guess false. |
+ return false; |
+ } |
+ } |
+ CHECK_GE(proc_self_fd, 0); |
+ |
+ // Ownership of proc_self_fd is transferred here, it must not be closed |
+ // or modified afterwards except via dir. |
+ scoped_ptr<DIR, DIRDeleter> dir(fdopendir(proc_self_fd)); |
+ CHECK(dir); |
+ |
+ struct dirent e; |
+ struct dirent* de; |
+ while (!readdir_r(dir.get(), &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. |
+ 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 +343,7 @@ void LinuxSandbox::SealSandbox() { |
CHECK_EQ(0, ret); |
proc_fd_ = -1; |
} |
+ sealed_ = true; |
} |
} // namespace content |