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 3// found in the LICENSE file. 4 5#include <dirent.h> 6#include <fcntl.h> 7#include <sys/resource.h> 8#include <sys/stat.h> 9#include <sys/time.h> 10#include <sys/types.h> 11#include <unistd.h> 12 13#include <limits> 14 15#include "base/bind.h" 16#include "base/callback_helpers.h" 17#include "base/command_line.h" 18#include "base/logging.h" 19#include "base/memory/scoped_ptr.h" 20#include "base/memory/singleton.h" 21#include "base/posix/eintr_wrapper.h" 22#include "base/strings/string_number_conversions.h" 23#include "base/time/time.h" 24#include "build/build_config.h" 25#include "content/common/sandbox_linux/sandbox_linux.h" 26#include "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h" 27#include "content/public/common/content_switches.h" 28#include "content/public/common/sandbox_linux.h" 29#include "sandbox/linux/services/credentials.h" 30#include "sandbox/linux/services/thread_helpers.h" 31#include "sandbox/linux/suid/client/setuid_sandbox_client.h" 32 33namespace { 34 35struct FDCloser { 36 inline void operator()(int* fd) const { 37 DCHECK(fd); 38 PCHECK(0 == IGNORE_EINTR(close(*fd))); 39 *fd = -1; 40 } 41}; 42 43// Don't use base::ScopedFD since it doesn't CHECK that the file descriptor was 44// closed. 45typedef scoped_ptr<int, FDCloser> SafeScopedFD; 46 47void LogSandboxStarted(const std::string& sandbox_name) { 48 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 49 const std::string process_type = 50 command_line.GetSwitchValueASCII(switches::kProcessType); 51 const std::string activated_sandbox = 52 "Activated " + sandbox_name + " sandbox for process type: " + 53 process_type + "."; 54#if defined(OS_CHROMEOS) 55 LOG(WARNING) << activated_sandbox; 56#else 57 VLOG(1) << activated_sandbox; 58#endif 59} 60 61bool AddResourceLimit(int resource, rlim_t limit) { 62 struct rlimit old_rlimit; 63 if (getrlimit(resource, &old_rlimit)) 64 return false; 65 // Make sure we don't raise the existing limit. 66 const struct rlimit new_rlimit = { 67 std::min(old_rlimit.rlim_cur, limit), 68 std::min(old_rlimit.rlim_max, limit) 69 }; 70 int rc = setrlimit(resource, &new_rlimit); 71 return rc == 0; 72} 73 74bool IsRunningTSAN() { 75#if defined(THREAD_SANITIZER) 76 return true; 77#else 78 return false; 79#endif 80} 81 82// Try to open /proc/self/task/ with the help of |proc_fd|. |proc_fd| can be 83// -1. Will return -1 on error and set errno like open(2). 84int OpenProcTaskFd(int proc_fd) { 85 int proc_self_task = -1; 86 if (proc_fd >= 0) { 87 // If a handle to /proc is available, use it. This allows to bypass file 88 // system restrictions. 89 proc_self_task = openat(proc_fd, "self/task/", O_RDONLY | O_DIRECTORY); 90 } else { 91 // Otherwise, make an attempt to access the file system directly. 92 proc_self_task = open("/proc/self/task/", O_RDONLY | O_DIRECTORY); 93 } 94 return proc_self_task; 95} 96 97} // namespace 98 99namespace content { 100 101LinuxSandbox::LinuxSandbox() 102 : proc_fd_(-1), 103 seccomp_bpf_started_(false), 104 sandbox_status_flags_(kSandboxLinuxInvalid), 105 pre_initialized_(false), 106 seccomp_bpf_supported_(false), 107 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { 108 if (setuid_sandbox_client_ == NULL) { 109 LOG(FATAL) << "Failed to instantiate the setuid sandbox client."; 110 } 111} 112 113LinuxSandbox::~LinuxSandbox() { 114} 115 116LinuxSandbox* LinuxSandbox::GetInstance() { 117 LinuxSandbox* instance = Singleton<LinuxSandbox>::get(); 118 CHECK(instance); 119 return instance; 120} 121 122#if defined(ADDRESS_SANITIZER) && defined(OS_LINUX) 123// ASan API call to notify the tool the sandbox is going to be turned on. 124extern "C" void __sanitizer_sandbox_on_notify(void *reserved); 125#endif 126 127void LinuxSandbox::PreinitializeSandbox() { 128 CHECK(!pre_initialized_); 129 seccomp_bpf_supported_ = false; 130#if defined(ADDRESS_SANITIZER) && defined(OS_LINUX) 131 // ASan needs to open some resources before the sandbox is enabled. 132 // This should not fork, not launch threads, not open a directory. 133 __sanitizer_sandbox_on_notify(/*reserved*/NULL); 134#endif 135 136#if !defined(NDEBUG) 137 // Open proc_fd_ only in Debug mode so that forgetting to close it doesn't 138 // produce a sandbox escape in Release mode. 139 proc_fd_ = open("/proc", O_DIRECTORY | O_RDONLY); 140 CHECK_GE(proc_fd_, 0); 141#endif // !defined(NDEBUG) 142 // We "pre-warm" the code that detects supports for seccomp BPF. 143 if (SandboxSeccompBPF::IsSeccompBPFDesired()) { 144 if (!SandboxSeccompBPF::SupportsSandbox()) { 145 VLOG(1) << "Lacking support for seccomp-bpf sandbox."; 146 } else { 147 seccomp_bpf_supported_ = true; 148 } 149 } 150 pre_initialized_ = true; 151} 152 153bool LinuxSandbox::InitializeSandbox() { 154 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); 155 return linux_sandbox->InitializeSandboxImpl(); 156} 157 158void LinuxSandbox::StopThread(base::Thread* thread) { 159 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); 160 linux_sandbox->StopThreadImpl(thread); 161} 162 163int LinuxSandbox::GetStatus() { 164 CHECK(pre_initialized_); 165 if (kSandboxLinuxInvalid == sandbox_status_flags_) { 166 // Initialize sandbox_status_flags_. 167 sandbox_status_flags_ = 0; 168 if (setuid_sandbox_client_->IsSandboxed()) { 169 sandbox_status_flags_ |= kSandboxLinuxSUID; 170 if (setuid_sandbox_client_->IsInNewPIDNamespace()) 171 sandbox_status_flags_ |= kSandboxLinuxPIDNS; 172 if (setuid_sandbox_client_->IsInNewNETNamespace()) 173 sandbox_status_flags_ |= kSandboxLinuxNetNS; 174 } 175 176 // We report whether the sandbox will be activated when renderers, workers 177 // and PPAPI plugins go through sandbox initialization. 178 if (seccomp_bpf_supported() && 179 SandboxSeccompBPF::ShouldEnableSeccompBPF(switches::kRendererProcess)) { 180 sandbox_status_flags_ |= kSandboxLinuxSeccompBPF; 181 } 182 } 183 184 return sandbox_status_flags_; 185} 186 187// Threads are counted via /proc/self/task. This is a little hairy because of 188// PID namespaces and existing sandboxes, so "self" must really be used instead 189// of using the pid. 190bool LinuxSandbox::IsSingleThreaded() const { 191 bool is_single_threaded = false; 192 int proc_self_task = OpenProcTaskFd(proc_fd_); 193 194// In Debug mode, it's mandatory to be able to count threads to catch bugs. 195#if !defined(NDEBUG) 196 // Using CHECK here since we want to check all the cases where 197 // !defined(NDEBUG) 198 // gets built. 199 CHECK_LE(0, proc_self_task) << "Could not count threads, the sandbox was not " 200 << "pre-initialized properly."; 201#endif // !defined(NDEBUG) 202 203 if (proc_self_task < 0) { 204 // Pretend to be monothreaded if it can't be determined (for instance the 205 // setuid sandbox is already engaged but no proc_fd_ is available). 206 is_single_threaded = true; 207 } else { 208 SafeScopedFD task_closer(&proc_self_task); 209 is_single_threaded = 210 sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task); 211 } 212 213 return is_single_threaded; 214} 215 216bool LinuxSandbox::seccomp_bpf_started() const { 217 return seccomp_bpf_started_; 218} 219 220sandbox::SetuidSandboxClient* 221 LinuxSandbox::setuid_sandbox_client() const { 222 return setuid_sandbox_client_.get(); 223} 224 225// For seccomp-bpf, we use the SandboxSeccompBPF class. 226bool LinuxSandbox::StartSeccompBPF(const std::string& process_type) { 227 CHECK(!seccomp_bpf_started_); 228 CHECK(pre_initialized_); 229 if (seccomp_bpf_supported()) 230 seccomp_bpf_started_ = SandboxSeccompBPF::StartSandbox(process_type); 231 232 if (seccomp_bpf_started_) 233 LogSandboxStarted("seccomp-bpf"); 234 235 return seccomp_bpf_started_; 236} 237 238bool LinuxSandbox::InitializeSandboxImpl() { 239 const std::string process_type = 240 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 241 switches::kProcessType); 242 243 // We need to make absolutely sure that our sandbox is "sealed" before 244 // returning. 245 // Unretained() since the current object is a Singleton. 246 base::ScopedClosureRunner sandbox_sealer( 247 base::Bind(&LinuxSandbox::SealSandbox, base::Unretained(this))); 248 // Make sure that this function enables sandboxes as promised by GetStatus(). 249 // Unretained() since the current object is a Singleton. 250 base::ScopedClosureRunner sandbox_promise_keeper( 251 base::Bind(&LinuxSandbox::CheckForBrokenPromises, 252 base::Unretained(this), 253 process_type)); 254 255 // No matter what, it's always an error to call InitializeSandbox() after 256 // threads have been created. 257 if (!IsSingleThreaded()) { 258 std::string error_message = "InitializeSandbox() called with multiple " 259 "threads in process " + process_type; 260 // TSAN starts a helper thread. So we don't start the sandbox and don't 261 // even report an error about it. 262 if (IsRunningTSAN()) 263 return false; 264 // The GPU process is allowed to call InitializeSandbox() with threads for 265 // now, because it loads third-party libraries. 266 if (process_type != switches::kGpuProcess) 267 CHECK(false) << error_message; 268 LOG(ERROR) << error_message; 269 return false; 270 } 271 272 // Only one thread is running, pre-initialize if not already done. 273 if (!pre_initialized_) 274 PreinitializeSandbox(); 275 276 DCHECK(!HasOpenDirectories()) << 277 "InitializeSandbox() called after unexpected directories have been " << 278 "opened. This breaks the security of the setuid sandbox."; 279 280 // Attempt to limit the future size of the address space of the process. 281 LimitAddressSpace(process_type); 282 283 // Try to enable seccomp-bpf. 284 bool seccomp_bpf_started = StartSeccompBPF(process_type); 285 286 return seccomp_bpf_started; 287} 288 289void LinuxSandbox::StopThreadImpl(base::Thread* thread) { 290 DCHECK(thread); 291 StopThreadAndEnsureNotCounted(thread); 292} 293 294bool LinuxSandbox::seccomp_bpf_supported() const { 295 CHECK(pre_initialized_); 296 return seccomp_bpf_supported_; 297} 298 299bool LinuxSandbox::LimitAddressSpace(const std::string& process_type) { 300 (void) process_type; 301#if !defined(ADDRESS_SANITIZER) 302 CommandLine* command_line = CommandLine::ForCurrentProcess(); 303 if (command_line->HasSwitch(switches::kNoSandbox)) { 304 return false; 305 } 306 307 // Limit the address space to 4GB. 308 // This is in the hope of making some kernel exploits more complex and less 309 // reliable. It also limits sprays a little on 64-bit. 310 rlim_t address_space_limit = std::numeric_limits<uint32_t>::max(); 311#if defined(__LP64__) 312 // On 64 bits, V8 and possibly others will reserve massive memory ranges and 313 // rely on on-demand paging for allocation. Unfortunately, even 314 // MADV_DONTNEED ranges count towards RLIMIT_AS so this is not an option. 315 // See crbug.com/169327 for a discussion. 316 // On the GPU process, irrespective of V8, we can exhaust a 4GB address space 317 // under normal usage, see crbug.com/271119 318 // For now, increase limit to 16GB for renderer and worker and gpu processes 319 // to accomodate. 320 if (process_type == switches::kRendererProcess || 321 process_type == switches::kWorkerProcess || 322 process_type == switches::kGpuProcess) { 323 address_space_limit = 1L << 34; 324 } 325#endif // defined(__LP64__) 326 327 // On all platforms, add a limit to the brk() heap that would prevent 328 // allocations that can't be index by an int. 329 const rlim_t kNewDataSegmentMaxSize = std::numeric_limits<int>::max(); 330 331 bool limited_as = AddResourceLimit(RLIMIT_AS, address_space_limit); 332 bool limited_data = AddResourceLimit(RLIMIT_DATA, kNewDataSegmentMaxSize); 333 return limited_as && limited_data; 334#else 335 return false; 336#endif // !defined(ADDRESS_SANITIZER) 337} 338 339bool LinuxSandbox::HasOpenDirectories() const { 340 return sandbox::Credentials().HasOpenDirectory(proc_fd_); 341} 342 343void LinuxSandbox::SealSandbox() { 344 if (proc_fd_ >= 0) { 345 int ret = IGNORE_EINTR(close(proc_fd_)); 346 CHECK_EQ(0, ret); 347 proc_fd_ = -1; 348 } 349} 350 351void LinuxSandbox::CheckForBrokenPromises(const std::string& process_type) { 352 // Make sure that any promise made with GetStatus() wasn't broken. 353 bool promised_seccomp_bpf_would_start = false; 354 if (process_type == switches::kRendererProcess || 355 process_type == switches::kWorkerProcess || 356 process_type == switches::kPpapiPluginProcess) { 357 promised_seccomp_bpf_would_start = 358 (sandbox_status_flags_ != kSandboxLinuxInvalid) && 359 (GetStatus() & kSandboxLinuxSeccompBPF); 360 } 361 if (promised_seccomp_bpf_would_start) { 362 CHECK(seccomp_bpf_started_); 363 } 364} 365 366void LinuxSandbox::StopThreadAndEnsureNotCounted(base::Thread* thread) const { 367 DCHECK(thread); 368 int proc_self_task = OpenProcTaskFd(proc_fd_); 369 PCHECK(proc_self_task >= 0); 370 SafeScopedFD task_closer(&proc_self_task); 371 CHECK( 372 sandbox::ThreadHelpers::StopThreadAndWatchProcFS(proc_self_task, thread)); 373} 374 375} // namespace content 376