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/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