Home | History | Annotate | Download | only in sandbox_linux
      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