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 "content/common/sandbox_linux/sandbox_seccomp_bpf_linux.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <sys/socket.h> 10 #include <sys/stat.h> 11 #include <sys/stat.h> 12 #include <sys/types.h> 13 #include <sys/types.h> 14 15 #include "base/basictypes.h" 16 #include "base/command_line.h" 17 #include "base/logging.h" 18 #include "build/build_config.h" 19 #include "content/public/common/content_switches.h" 20 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" 21 22 #if defined(USE_SECCOMP_BPF) 23 24 #include "base/posix/eintr_wrapper.h" 25 #include "content/common/sandbox_linux/bpf_cros_arm_gpu_policy_linux.h" 26 #include "content/common/sandbox_linux/bpf_gpu_policy_linux.h" 27 #include "content/common/sandbox_linux/bpf_ppapi_policy_linux.h" 28 #include "content/common/sandbox_linux/bpf_renderer_policy_linux.h" 29 #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h" 30 #include "content/common/sandbox_linux/sandbox_linux.h" 31 #include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h" 32 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" 33 #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" 34 #include "sandbox/linux/seccomp-bpf-helpers/syscall_sets.h" 35 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" 36 #include "sandbox/linux/services/linux_syscalls.h" 37 38 using sandbox::BaselinePolicy; 39 using sandbox::SyscallSets; 40 41 #else 42 43 // Make sure that seccomp-bpf does not get disabled by mistake. Also make sure 44 // that we think twice about this when adding a new architecture. 45 #if !defined(ARCH_CPU_MIPS_FAMILY) && !defined(ARCH_CPU_ARM64) 46 #error "Seccomp-bpf disabled on supported architecture!" 47 #endif // !defined(ARCH_CPU_MIPS_FAMILY) && !defined(ARCH_CPU_ARM64) 48 49 #endif // 50 51 namespace content { 52 53 #if defined(USE_SECCOMP_BPF) 54 namespace { 55 56 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy); 57 58 inline bool IsChromeOS() { 59 #if defined(OS_CHROMEOS) 60 return true; 61 #else 62 return false; 63 #endif 64 } 65 66 inline bool IsArchitectureArm() { 67 #if defined(__arm__) 68 return true; 69 #else 70 return false; 71 #endif 72 } 73 74 class BlacklistDebugAndNumaPolicy : public SandboxBPFBasePolicy { 75 public: 76 BlacklistDebugAndNumaPolicy() {} 77 virtual ~BlacklistDebugAndNumaPolicy() {} 78 79 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, 80 int system_call_number) const OVERRIDE; 81 82 private: 83 DISALLOW_COPY_AND_ASSIGN(BlacklistDebugAndNumaPolicy); 84 }; 85 86 ErrorCode BlacklistDebugAndNumaPolicy::EvaluateSyscall(SandboxBPF* sandbox, 87 int sysno) const { 88 if (!SandboxBPF::IsValidSyscallNumber(sysno)) { 89 // TODO(jln) we should not have to do that in a trivial policy. 90 return ErrorCode(ENOSYS); 91 } 92 if (SyscallSets::IsDebug(sysno) || SyscallSets::IsNuma(sysno)) 93 return sandbox->Trap(sandbox::CrashSIGSYS_Handler, NULL); 94 95 return ErrorCode(ErrorCode::ERR_ALLOWED); 96 } 97 98 class AllowAllPolicy : public SandboxBPFBasePolicy { 99 public: 100 AllowAllPolicy() {} 101 virtual ~AllowAllPolicy() {} 102 103 virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, 104 int system_call_number) const OVERRIDE; 105 106 private: 107 DISALLOW_COPY_AND_ASSIGN(AllowAllPolicy); 108 }; 109 110 // Allow all syscalls. 111 // This will still deny x32 or IA32 calls in 64 bits mode or 112 // 64 bits system calls in compatibility mode. 113 ErrorCode AllowAllPolicy::EvaluateSyscall(SandboxBPF*, int sysno) const { 114 if (!SandboxBPF::IsValidSyscallNumber(sysno)) { 115 // TODO(jln) we should not have to do that in a trivial policy. 116 return ErrorCode(ENOSYS); 117 } else { 118 return ErrorCode(ErrorCode::ERR_ALLOWED); 119 } 120 } 121 122 // If a BPF policy is engaged for |process_type|, run a few sanity checks. 123 void RunSandboxSanityChecks(const std::string& process_type) { 124 if (process_type == switches::kRendererProcess || 125 process_type == switches::kWorkerProcess || 126 process_type == switches::kGpuProcess || 127 process_type == switches::kPpapiPluginProcess) { 128 int syscall_ret; 129 errno = 0; 130 131 // Without the sandbox, this would EBADF. 132 syscall_ret = fchmod(-1, 07777); 133 CHECK_EQ(-1, syscall_ret); 134 CHECK_EQ(EPERM, errno); 135 136 // Run most of the sanity checks only in DEBUG mode to avoid a perf. 137 // impact. 138 #if !defined(NDEBUG) 139 // open() must be restricted. 140 syscall_ret = open("/etc/passwd", O_RDONLY); 141 CHECK_EQ(-1, syscall_ret); 142 CHECK_EQ(SandboxBPFBasePolicy::GetFSDeniedErrno(), errno); 143 144 // We should never allow the creation of netlink sockets. 145 syscall_ret = socket(AF_NETLINK, SOCK_DGRAM, 0); 146 CHECK_EQ(-1, syscall_ret); 147 CHECK_EQ(EPERM, errno); 148 #endif // !defined(NDEBUG) 149 } 150 } 151 152 153 // This function takes ownership of |policy|. 154 void StartSandboxWithPolicy(sandbox::SandboxBPFPolicy* policy) { 155 // Starting the sandbox is a one-way operation. The kernel doesn't allow 156 // us to unload a sandbox policy after it has been started. Nonetheless, 157 // in order to make the use of the "Sandbox" object easier, we allow for 158 // the object to be destroyed after the sandbox has been started. Note that 159 // doing so does not stop the sandbox. 160 SandboxBPF sandbox; 161 sandbox.SetSandboxPolicy(policy); 162 CHECK(sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)); 163 } 164 165 // nacl_helper needs to be tiny and includes only part of content/ 166 // in its dependencies. Make sure to not link things that are not needed. 167 #if !defined(IN_NACL_HELPER) 168 scoped_ptr<SandboxBPFBasePolicy> GetGpuProcessSandbox() { 169 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 170 bool allow_sysv_shm = false; 171 if (command_line.HasSwitch(switches::kGpuSandboxAllowSysVShm)) { 172 DCHECK(IsArchitectureArm()); 173 allow_sysv_shm = true; 174 } 175 176 if (IsChromeOS() && IsArchitectureArm()) { 177 return scoped_ptr<SandboxBPFBasePolicy>( 178 new CrosArmGpuProcessPolicy(allow_sysv_shm)); 179 } else { 180 return scoped_ptr<SandboxBPFBasePolicy>(new GpuProcessPolicy); 181 } 182 } 183 184 // Initialize the seccomp-bpf sandbox. 185 bool StartBPFSandbox(const CommandLine& command_line, 186 const std::string& process_type) { 187 scoped_ptr<SandboxBPFBasePolicy> policy; 188 189 if (process_type == switches::kGpuProcess) { 190 policy.reset(GetGpuProcessSandbox().release()); 191 } else if (process_type == switches::kRendererProcess || 192 process_type == switches::kWorkerProcess) { 193 policy.reset(new RendererProcessPolicy); 194 } else if (process_type == switches::kPpapiPluginProcess) { 195 policy.reset(new PpapiProcessPolicy); 196 } else if (process_type == switches::kUtilityProcess) { 197 policy.reset(new BlacklistDebugAndNumaPolicy); 198 } else { 199 NOTREACHED(); 200 policy.reset(new AllowAllPolicy); 201 } 202 203 CHECK(policy->PreSandboxHook()); 204 StartSandboxWithPolicy(policy.release()); 205 206 RunSandboxSanityChecks(process_type); 207 return true; 208 } 209 #else // defined(IN_NACL_HELPER) 210 bool StartBPFSandbox(const CommandLine& command_line, 211 const std::string& process_type) { 212 NOTREACHED(); 213 // Avoid -Wunused-function with no-op code. 214 ignore_result(IsChromeOS); 215 ignore_result(IsArchitectureArm); 216 ignore_result(RunSandboxSanityChecks); 217 return false; 218 } 219 #endif // !defined(IN_NACL_HELPER) 220 221 } // namespace 222 223 #endif // USE_SECCOMP_BPF 224 225 // Is seccomp BPF globally enabled? 226 bool SandboxSeccompBPF::IsSeccompBPFDesired() { 227 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 228 if (!command_line.HasSwitch(switches::kNoSandbox) && 229 !command_line.HasSwitch(switches::kDisableSeccompFilterSandbox)) { 230 return true; 231 } else { 232 return false; 233 } 234 } 235 236 bool SandboxSeccompBPF::ShouldEnableSeccompBPF( 237 const std::string& process_type) { 238 #if defined(USE_SECCOMP_BPF) 239 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 240 if (process_type == switches::kGpuProcess) 241 return !command_line.HasSwitch(switches::kDisableGpuSandbox); 242 243 return true; 244 #endif // USE_SECCOMP_BPF 245 return false; 246 } 247 248 bool SandboxSeccompBPF::SupportsSandbox() { 249 #if defined(USE_SECCOMP_BPF) 250 // TODO(jln): pass the saved proc_fd_ from the LinuxSandbox singleton 251 // here. 252 SandboxBPF::SandboxStatus bpf_sandbox_status = 253 SandboxBPF::SupportsSeccompSandbox(-1); 254 // Kernel support is what we are interested in here. Other status 255 // such as STATUS_UNAVAILABLE (has threads) still indicate kernel support. 256 // We make this a negative check, since if there is a bug, we would rather 257 // "fail closed" (expect a sandbox to be available and try to start it). 258 if (bpf_sandbox_status != SandboxBPF::STATUS_UNSUPPORTED) { 259 return true; 260 } 261 #endif 262 return false; 263 } 264 265 bool SandboxSeccompBPF::StartSandbox(const std::string& process_type) { 266 #if defined(USE_SECCOMP_BPF) 267 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); 268 269 if (IsSeccompBPFDesired() && // Global switches policy. 270 ShouldEnableSeccompBPF(process_type) && // Process-specific policy. 271 SupportsSandbox()) { 272 // If the kernel supports the sandbox, and if the command line says we 273 // should enable it, enable it or die. 274 bool started_sandbox = StartBPFSandbox(command_line, process_type); 275 CHECK(started_sandbox); 276 return true; 277 } 278 #endif 279 return false; 280 } 281 282 bool SandboxSeccompBPF::StartSandboxWithExternalPolicy( 283 scoped_ptr<sandbox::SandboxBPFPolicy> policy) { 284 #if defined(USE_SECCOMP_BPF) 285 if (IsSeccompBPFDesired() && SupportsSandbox()) { 286 CHECK(policy); 287 StartSandboxWithPolicy(policy.release()); 288 return true; 289 } 290 #endif // defined(USE_SECCOMP_BPF) 291 return false; 292 } 293 294 scoped_ptr<sandbox::SandboxBPFPolicy> 295 SandboxSeccompBPF::GetBaselinePolicy() { 296 #if defined(USE_SECCOMP_BPF) 297 return scoped_ptr<sandbox::SandboxBPFPolicy>(new BaselinePolicy); 298 #else 299 return scoped_ptr<sandbox::SandboxBPFPolicy>(); 300 #endif // defined(USE_SECCOMP_BPF) 301 } 302 303 } // namespace content 304