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