Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / common / sandbox_linux / sandbox_seccomp_bpf_linux.cc
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