Index: content/common/sandbox_linux/sandbox_linux.cc |
=================================================================== |
--- content/common/sandbox_linux/sandbox_linux.cc (revision 251104) |
+++ content/common/sandbox_linux/sandbox_linux.cc (working copy) |
@@ -8,6 +8,7 @@ |
#include <sys/stat.h> |
#include <sys/time.h> |
#include <sys/types.h> |
+#include <unistd.h> |
#include <limits> |
@@ -15,6 +16,7 @@ |
#include "base/callback_helpers.h" |
#include "base/command_line.h" |
#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
#include "base/memory/singleton.h" |
#include "base/posix/eintr_wrapper.h" |
#include "base/strings/string_number_conversions.h" |
@@ -25,10 +27,23 @@ |
#include "content/public/common/content_switches.h" |
#include "content/public/common/sandbox_linux.h" |
#include "sandbox/linux/services/credentials.h" |
+#include "sandbox/linux/services/thread_helpers.h" |
#include "sandbox/linux/suid/client/setuid_sandbox_client.h" |
namespace { |
+struct FDCloser { |
+ inline void operator()(int* fd) const { |
+ DCHECK(fd); |
+ PCHECK(0 == IGNORE_EINTR(close(*fd))); |
+ *fd = -1; |
+ } |
+}; |
+ |
+// Don't use base::ScopedFD since it doesn't CHECK that the file descriptor was |
+// closed. |
+typedef scoped_ptr<int, FDCloser> SafeScopedFD; |
+ |
void LogSandboxStarted(const std::string& sandbox_name) { |
const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
const std::string process_type = |
@@ -64,6 +79,21 @@ |
#endif |
} |
+// Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be |
+// -1. Will return -1 on error and set errno like open(2). |
+int OpenProcTaskFd(int proc_fd) { |
+ int proc_self_task = -1; |
+ if (proc_fd >= 0) { |
+ // If a handle to /proc is available, use it. This allows to bypass file |
+ // system restrictions. |
+ proc_self_task = openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY); |
+ } else { |
+ // Otherwise, make an attempt to access the file system directly. |
+ proc_self_task = open("/proc/self/task/", O_RDONLY | O_DIRECTORY); |
+ } |
+ return proc_self_task; |
+} |
+ |
} // namespace |
namespace content { |
@@ -125,6 +155,11 @@ |
return linux_sandbox->InitializeSandboxImpl(); |
} |
+void LinuxSandbox::StopThread(base::Thread* thread) { |
+ LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
+ linux_sandbox->StopThreadImpl(thread); |
+} |
+ |
int LinuxSandbox::GetStatus() { |
CHECK(pre_initialized_); |
if (kSandboxLinuxInvalid == sandbox_status_flags_) { |
@@ -153,35 +188,29 @@ |
// PID namespaces and existing sandboxes, so "self" must really be used instead |
// of using the pid. |
bool LinuxSandbox::IsSingleThreaded() const { |
- struct stat task_stat; |
- int fstat_ret; |
- if (proc_fd_ >= 0) { |
- // If a handle to /proc is available, use it. This allows to bypass file |
- // system restrictions. |
- fstat_ret = fstatat(proc_fd_, "self/task/", &task_stat, 0); |
- } else { |
- // Otherwise, make an attempt to access the file system directly. |
- fstat_ret = fstatat(AT_FDCWD, "/proc/self/task/", &task_stat, 0); |
- } |
- // In Debug mode, it's mandatory to be able to count threads to catch bugs. |
+ bool is_single_threaded = false; |
+ int proc_self_task = OpenProcTaskFd(proc_fd_); |
+ |
+// In Debug mode, it's mandatory to be able to count threads to catch bugs. |
#if !defined(NDEBUG) |
- // Using DCHECK here would be incorrect. DCHECK can be enabled in non |
- // official release mode. |
- CHECK_EQ(0, fstat_ret) << "Could not count threads, the sandbox was not " |
- << "pre-initialized properly."; |
+ // Using CHECK here since we want to check all the cases where |
+ // !defined(NDEBUG) |
+ // gets built. |
+ CHECK_LE(0, proc_self_task) << "Could not count threads, the sandbox was not " |
+ << "pre-initialized properly."; |
#endif // !defined(NDEBUG) |
- if (fstat_ret) { |
+ |
+ if (proc_self_task < 0) { |
// Pretend to be monothreaded if it can't be determined (for instance the |
// setuid sandbox is already engaged but no proc_fd_ is available). |
- return true; |
+ is_single_threaded = true; |
+ } else { |
+ SafeScopedFD task_closer(&proc_self_task); |
+ is_single_threaded = |
+ sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task); |
} |
- // At least "..", "." and the current thread should be present. |
- CHECK_LE(3UL, task_stat.st_nlink); |
- // Counting threads via /proc/self/task could be racy. For the purpose of |
- // determining if the current proces is monothreaded it works: if at any |
- // time it becomes monothreaded, it'll stay so. |
- return task_stat.st_nlink == 3; |
+ return is_single_threaded; |
} |
bool LinuxSandbox::seccomp_bpf_started() const { |
@@ -257,6 +286,10 @@ |
return seccomp_bpf_started; |
} |
+void LinuxSandbox::StopThreadImpl(base::Thread* thread) { |
+ DCHECK(thread); |
+ StopThreadAndEnsureNotCounted(thread); |
+} |
bool LinuxSandbox::seccomp_bpf_supported() const { |
CHECK(pre_initialized_); |
@@ -303,7 +336,7 @@ |
#endif // !defined(ADDRESS_SANITIZER) |
} |
-bool LinuxSandbox::HasOpenDirectories() { |
+bool LinuxSandbox::HasOpenDirectories() const { |
return sandbox::Credentials().HasOpenDirectory(proc_fd_); |
} |
@@ -330,4 +363,13 @@ |
} |
} |
+void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { |
+ DCHECK(thread); |
+ int proc_self_task = OpenProcTaskFd(proc_fd_); |
+ PCHECK(proc_self_task >= 0); |
+ SafeScopedFD task_closer(&proc_self_task); |
+ CHECK( |
+ sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task, thread)); |
+} |
+ |
} // namespace content |