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 33 namespace { 34 35 struct 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. 45 typedef scoped_ptr<int, FDCloser> SafeScopedFD; 46 47 void 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 61 bool 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 74 bool 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). 84 int 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 99 namespace content { 100 101 LinuxSandbox::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 113 LinuxSandbox::~LinuxSandbox() { 114 } 115 116 LinuxSandbox* 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. 124 extern "C" void __sanitizer_sandbox_on_notify(void *reserved); 125 #endif 126 127 void 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 153 bool LinuxSandbox::InitializeSandbox() { 154 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); 155 return linux_sandbox->InitializeSandboxImpl(); 156 } 157 158 void LinuxSandbox::StopThread(base::Thread* thread) { 159 LinuxSandbox* linux_sandbox = LinuxSandbox::GetInstance(); 160 linux_sandbox->StopThreadImpl(thread); 161 } 162 163 int 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. 190 bool 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 216 bool LinuxSandbox::seccomp_bpf_started() const { 217 return seccomp_bpf_started_; 218 } 219 220 sandbox::SetuidSandboxClient* 221 LinuxSandbox::setuid_sandbox_client() const { 222 return setuid_sandbox_client_.get(); 223 } 224 225 // For seccomp-bpf, we use the SandboxSeccompBPF class. 226 bool 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 238 bool 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 289 void LinuxSandbox::StopThreadImpl(base::Thread* thread) { 290 DCHECK(thread); 291 StopThreadAndEnsureNotCounted(thread); 292 } 293 294 bool LinuxSandbox::seccomp_bpf_supported() const { 295 CHECK(pre_initialized_); 296 return seccomp_bpf_supported_; 297 } 298 299 bool 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 339 bool LinuxSandbox::HasOpenDirectories() const { 340 return sandbox::Credentials().HasOpenDirectory(proc_fd_); 341 } 342 343 void 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 351 void 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 366 void 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