| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dirent.h> | 5 #include <dirent.h> |
| 6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <sys/resource.h> | 7 #include <sys/resource.h> |
| 8 #include <sys/stat.h> | 8 #include <sys/stat.h> |
| 9 #include <sys/time.h> | 9 #include <sys/time.h> |
| 10 #include <sys/types.h> | 10 #include <sys/types.h> |
| 11 #include <unistd.h> | 11 #include <unistd.h> |
| 12 | 12 |
| 13 #include <limits> | 13 #include <limits> |
| 14 #include <string> |
| 15 #include <vector> |
| 14 | 16 |
| 15 #include "base/bind.h" | 17 #include "base/bind.h" |
| 16 #include "base/callback_helpers.h" | 18 #include "base/callback_helpers.h" |
| 17 #include "base/command_line.h" | 19 #include "base/command_line.h" |
| 18 #include "base/debug/stack_trace.h" | 20 #include "base/debug/stack_trace.h" |
| 19 #include "base/files/scoped_file.h" | 21 #include "base/files/scoped_file.h" |
| 20 #include "base/logging.h" | 22 #include "base/logging.h" |
| 21 #include "base/macros.h" | 23 #include "base/macros.h" |
| 22 #include "base/memory/scoped_ptr.h" | 24 #include "base/memory/scoped_ptr.h" |
| 23 #include "base/memory/singleton.h" | 25 #include "base/memory/singleton.h" |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 #endif | 85 #endif |
| 84 } | 86 } |
| 85 | 87 |
| 86 // Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be | 88 // Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be |
| 87 // -1. Will return -1 on error and set errno like open(2). | 89 // -1. Will return -1 on error and set errno like open(2). |
| 88 int OpenProcTaskFd(int proc_fd) { | 90 int OpenProcTaskFd(int proc_fd) { |
| 89 int proc_self_task = -1; | 91 int proc_self_task = -1; |
| 90 if (proc_fd >= 0) { | 92 if (proc_fd >= 0) { |
| 91 // If a handle to /proc is available, use it. This allows to bypass file | 93 // If a handle to /proc is available, use it. This allows to bypass file |
| 92 // system restrictions. | 94 // system restrictions. |
| 93 proc_self_task = openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY); | 95 proc_self_task = |
| 96 openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); |
| 94 } else { | 97 } else { |
| 95 // Otherwise, make an attempt to access the file system directly. | 98 // Otherwise, make an attempt to access the file system directly. |
| 96 proc_self_task = open("/proc/self/task/", O_RDONLY | O_DIRECTORY); | 99 proc_self_task = |
| 100 open("/proc/self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); |
| 97 } | 101 } |
| 98 return proc_self_task; | 102 return proc_self_task; |
| 99 } | 103 } |
| 100 | 104 |
| 101 } // namespace | 105 } // namespace |
| 102 | 106 |
| 103 namespace content { | 107 namespace content { |
| 104 | 108 |
| 105 LinuxSandbox::LinuxSandbox() | 109 LinuxSandbox::LinuxSandbox() |
| 106 : proc_fd_(-1), | 110 : proc_fd_(-1), |
| 107 seccomp_bpf_started_(false), | 111 seccomp_bpf_started_(false), |
| 108 sandbox_status_flags_(kSandboxLinuxInvalid), | 112 sandbox_status_flags_(kSandboxLinuxInvalid), |
| 109 pre_initialized_(false), | 113 pre_initialized_(false), |
| 110 seccomp_bpf_supported_(false), | 114 seccomp_bpf_supported_(false), |
| 111 yama_is_enforcing_(false), | 115 yama_is_enforcing_(false), |
| 116 initialize_sandbox_ran_(false), |
| 112 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) | 117 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) |
| 113 { | 118 { |
| 114 if (setuid_sandbox_client_ == NULL) { | 119 if (setuid_sandbox_client_ == NULL) { |
| 115 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; | 120 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; |
| 116 } | 121 } |
| 117 #if defined(ANY_OF_AMTLU_SANITIZER) | 122 #if defined(ANY_OF_AMTLU_SANITIZER) |
| 118 sanitizer_args_ = make_scoped_ptr(new __sanitizer_sandbox_arguments); | 123 sanitizer_args_ = make_scoped_ptr(new __sanitizer_sandbox_arguments); |
| 119 *sanitizer_args_ = {0}; | 124 *sanitizer_args_ = {0}; |
| 120 #endif | 125 #endif |
| 121 } | 126 } |
| 122 | 127 |
| 123 LinuxSandbox::~LinuxSandbox() { | 128 LinuxSandbox::~LinuxSandbox() { |
| 129 if (pre_initialized_) { |
| 130 CHECK(initialize_sandbox_ran_); |
| 131 } |
| 124 } | 132 } |
| 125 | 133 |
| 126 LinuxSandbox* LinuxSandbox::GetInstance() { | 134 LinuxSandbox* LinuxSandbox::GetInstance() { |
| 127 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); | 135 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); |
| 128 CHECK(instance); | 136 CHECK(instance); |
| 129 return instance; | 137 return instance; |
| 130 } | 138 } |
| 131 | 139 |
| 132 void LinuxSandbox::PreinitializeSandbox() { | 140 void LinuxSandbox::PreinitializeSandbox() { |
| 133 CHECK(!pre_initialized_); | 141 CHECK(!pre_initialized_); |
| 134 seccomp_bpf_supported_ = false; | 142 seccomp_bpf_supported_ = false; |
| 135 #if defined(ANY_OF_AMTLU_SANITIZER) | 143 #if defined(ANY_OF_AMTLU_SANITIZER) |
| 136 // Sanitizers need to open some resources before the sandbox is enabled. | 144 // Sanitizers need to open some resources before the sandbox is enabled. |
| 137 // This should not fork, not launch threads, not open a directory. | 145 // This should not fork, not launch threads, not open a directory. |
| 138 __sanitizer_sandbox_on_notify(sanitizer_args()); | 146 __sanitizer_sandbox_on_notify(sanitizer_args()); |
| 139 sanitizer_args_.reset(); | 147 sanitizer_args_.reset(); |
| 140 #endif | 148 #endif |
| 141 | 149 |
| 142 #if !defined(NDEBUG) | 150 #if !defined(NDEBUG) |
| 143 // The in-process stack dumping needs to open /proc/self/maps and cache | 151 // The in-process stack dumping needs to open /proc/self/maps and cache |
| 144 // its contents before the sandbox is enabled. It also pre-opens the | 152 // its contents before the sandbox is enabled. It also pre-opens the |
| 145 // object files that are already loaded in the process address space. | 153 // object files that are already loaded in the process address space. |
| 146 base::debug::EnableInProcessStackDumpingForSandbox(); | 154 base::debug::EnableInProcessStackDumpingForSandbox(); |
| 155 #endif // !defined(NDEBUG) |
| 147 | 156 |
| 148 // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't | 157 // Open proc_fd_. It would break the security of the setuid sandbox if it was |
| 149 // produce a sandbox escape in Release mode. | 158 // not closed. |
| 159 // If LinuxSandbox::PreinitializeSandbox() runs, InitializeSandbox() must run |
| 160 // as well. |
| 150 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); | 161 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC); |
| 151 CHECK_GE(proc_fd_, 0); | 162 CHECK_GE(proc_fd_, 0); |
| 152 #endif // !defined(NDEBUG) | |
| 153 // We "pre-warm" the code that detects supports for seccomp BPF. | 163 // We "pre-warm" the code that detects supports for seccomp BPF. |
| 154 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { | 164 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { |
| 155 if (!SandboxSeccompBPF::SupportsSandbox()) { | 165 if (!SandboxSeccompBPF::SupportsSandbox()) { |
| 156 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; | 166 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; |
| 157 } else { | 167 } else { |
| 158 seccomp_bpf_supported_ = true; | 168 seccomp_bpf_supported_ = true; |
| 159 } | 169 } |
| 160 } | 170 } |
| 161 | 171 |
| 162 // Yama is a "global", system-level status. We assume it will not regress | 172 // Yama is a "global", system-level status. We assume it will not regress |
| 163 // after startup. | 173 // after startup. |
| 164 const int yama_status = Yama::GetStatus(); | 174 const int yama_status = Yama::GetStatus(); |
| 165 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && | 175 yama_is_enforcing_ = (yama_status & Yama::STATUS_PRESENT) && |
| 166 (yama_status & Yama::STATUS_ENFORCING); | 176 (yama_status & Yama::STATUS_ENFORCING); |
| 167 pre_initialized_ = true; | 177 pre_initialized_ = true; |
| 168 } | 178 } |
| 169 | 179 |
| 180 std::vector<int> LinuxSandbox::GetFileDescriptorsToClose() { |
| 181 return std::vector<int>{proc_fd_}; |
| 182 } |
| 183 |
| 170 bool LinuxSandbox::InitializeSandbox() { | 184 bool LinuxSandbox::InitializeSandbox() { |
| 171 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 185 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
| 172 return linux_sandbox->InitializeSandboxImpl(); | 186 return linux_sandbox->InitializeSandboxImpl(); |
| 173 } | 187 } |
| 174 | 188 |
| 175 void LinuxSandbox::StopThread(base::Thread* thread) { | 189 void LinuxSandbox::StopThread(base::Thread* thread) { |
| 176 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); | 190 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); |
| 177 linux_sandbox->StopThreadImpl(thread); | 191 linux_sandbox->StopThreadImpl(thread); |
| 178 } | 192 } |
| 179 | 193 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 202 } | 216 } |
| 203 } | 217 } |
| 204 | 218 |
| 205 return sandbox_status_flags_; | 219 return sandbox_status_flags_; |
| 206 } | 220 } |
| 207 | 221 |
| 208 // Threads are counted via /proc/self/task. This is a little hairy because of | 222 // Threads are counted via /proc/self/task. This is a little hairy because of |
| 209 // PID namespaces and existing sandboxes, so "self" must really be used instead | 223 // PID namespaces and existing sandboxes, so "self" must really be used instead |
| 210 // of using the pid. | 224 // of using the pid. |
| 211 bool LinuxSandbox::IsSingleThreaded() const { | 225 bool LinuxSandbox::IsSingleThreaded() const { |
| 212 bool is_single_threaded = false; | |
| 213 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 226 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
| 214 | 227 |
| 215 // In Debug mode, it's mandatory to be able to count threads to catch bugs. | |
| 216 #if !defined(NDEBUG) | |
| 217 // Using CHECK here since we want to check all the cases where | |
| 218 // !defined(NDEBUG) | |
| 219 // gets built. | |
| 220 CHECK(proc_self_task.is_valid()) | 228 CHECK(proc_self_task.is_valid()) |
| 221 << "Could not count threads, the sandbox was not " | 229 << "Could not count threads, the sandbox was not " |
| 222 << "pre-initialized properly."; | 230 << "pre-initialized properly."; |
| 223 #endif // !defined(NDEBUG) | |
| 224 | 231 |
| 225 if (!proc_self_task.is_valid()) { | 232 const bool is_single_threaded = |
| 226 // Pretend to be monothreaded if it can't be determined (for instance the | 233 sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); |
| 227 // setuid sandbox is already engaged but no proc_fd_ is available). | |
| 228 is_single_threaded = true; | |
| 229 } else { | |
| 230 is_single_threaded = | |
| 231 sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); | |
| 232 } | |
| 233 | 234 |
| 234 return is_single_threaded; | 235 return is_single_threaded; |
| 235 } | 236 } |
| 236 | 237 |
| 237 bool LinuxSandbox::seccomp_bpf_started() const { | 238 bool LinuxSandbox::seccomp_bpf_started() const { |
| 238 return seccomp_bpf_started_; | 239 return seccomp_bpf_started_; |
| 239 } | 240 } |
| 240 | 241 |
| 241 sandbox::SetuidSandboxClient* | 242 sandbox::SetuidSandboxClient* |
| 242 LinuxSandbox::setuid_sandbox_client() const { | 243 LinuxSandbox::setuid_sandbox_client() const { |
| 243 return setuid_sandbox_client_.get(); | 244 return setuid_sandbox_client_.get(); |
| 244 } | 245 } |
| 245 | 246 |
| 246 // For seccomp-bpf, we use the SandboxSeccompBPF class. | 247 // For seccomp-bpf, we use the SandboxSeccompBPF class. |
| 247 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { | 248 bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { |
| 248 CHECK(!seccomp_bpf_started_); | 249 CHECK(!seccomp_bpf_started_); |
| 249 CHECK(pre_initialized_); | 250 CHECK(pre_initialized_); |
| 250 if (seccomp_bpf_supported()) | 251 if (seccomp_bpf_supported()) { |
| 251 seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type); | 252 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
| 253 seccomp_bpf_started_ = |
| 254 SandboxSeccompBPF::StartSandbox(process_type, proc_self_task.Pass()); |
| 255 } |
| 252 | 256 |
| 253 if (seccomp_bpf_started_) | 257 if (seccomp_bpf_started_) { |
| 254 LogSandboxStarted("seccomp-bpf"); | 258 LogSandboxStarted("seccomp-bpf"); |
| 259 } |
| 255 | 260 |
| 256 return seccomp_bpf_started_; | 261 return seccomp_bpf_started_; |
| 257 } | 262 } |
| 258 | 263 |
| 259 bool LinuxSandbox::InitializeSandboxImpl() { | 264 bool LinuxSandbox::InitializeSandboxImpl() { |
| 265 DCHECK(!initialize_sandbox_ran_); |
| 266 initialize_sandbox_ran_ = true; |
| 267 |
| 260 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | 268 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); |
| 261 const std::string process_type = | 269 const std::string process_type = |
| 262 command_line->GetSwitchValueASCII(switches::kProcessType); | 270 command_line->GetSwitchValueASCII(switches::kProcessType); |
| 263 | 271 |
| 264 // We need to make absolutely sure that our sandbox is "sealed" before | 272 // We need to make absolutely sure that our sandbox is "sealed" before |
| 265 // returning. | 273 // returning. |
| 266 // Unretained() since the current object is a Singleton. | 274 // Unretained() since the current object is a Singleton. |
| 267 base::ScopedClosureRunner sandbox_sealer( | 275 base::ScopedClosureRunner sandbox_sealer( |
| 268 base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); | 276 base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); |
| 269 // Make sure that this function enables sandboxes as promised by GetStatus(). | 277 // Make sure that this function enables sandboxes as promised by GetStatus(). |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 | 414 |
| 407 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { | 415 void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { |
| 408 DCHECK(thread); | 416 DCHECK(thread); |
| 409 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); | 417 base::ScopedFD proc_self_task(OpenProcTaskFd(proc_fd_)); |
| 410 PCHECK(proc_self_task.is_valid()); | 418 PCHECK(proc_self_task.is_valid()); |
| 411 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), | 419 CHECK(sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task.get(), |
| 412 thread)); | 420 thread)); |
| 413 } | 421 } |
| 414 | 422 |
| 415 } // namespace content | 423 } // namespace content |
| OLD | NEW |