Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / sandbox / linux / seccomp-bpf / sandbox_bpf.h
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 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
6 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
7
8 #include <stddef.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11
12 #include <algorithm>
13 #include <limits>
14 #include <map>
15 #include <set>
16 #include <utility>
17 #include <vector>
18
19 #include "base/compiler_specific.h"
20 #include "base/memory/scoped_ptr.h"
21 #include "sandbox/linux/sandbox_export.h"
22 #include "sandbox/linux/seccomp-bpf/die.h"
23 #include "sandbox/linux/seccomp-bpf/errorcode.h"
24 #include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
25
26 namespace sandbox {
27
28 struct arch_seccomp_data {
29   int nr;
30   uint32_t arch;
31   uint64_t instruction_pointer;
32   uint64_t args[6];
33 };
34
35 struct arch_sigsys {
36   void* ip;
37   int nr;
38   unsigned int arch;
39 };
40
41 class CodeGen;
42 class SandboxBPFPolicy;
43 class SandboxUnittestHelper;
44 struct Instruction;
45
46 class SANDBOX_EXPORT SandboxBPF {
47  public:
48   enum SandboxStatus {
49     STATUS_UNKNOWN,      // Status prior to calling supportsSeccompSandbox()
50     STATUS_UNSUPPORTED,  // The kernel does not appear to support sandboxing
51     STATUS_UNAVAILABLE,  // Currently unavailable but might work again later
52     STATUS_AVAILABLE,    // Sandboxing is available but not currently active
53     STATUS_ENABLED       // The sandbox is now active
54   };
55
56   // Depending on the level of kernel support, seccomp-bpf may require the
57   // process to be single-threaded in order to enable it. When calling
58   // StartSandbox(), the program should indicate whether or not the sandbox
59   // should try and engage with multi-thread support.
60   enum SandboxThreadState {
61     PROCESS_INVALID,
62     PROCESS_SINGLE_THREADED,  // The program is currently single-threaded.
63     // Note: PROCESS_MULTI_THREADED requires experimental kernel support that
64     // has not been contributed to upstream Linux.
65     PROCESS_MULTI_THREADED,   // The program may be multi-threaded.
66   };
67
68   // When calling setSandboxPolicy(), the caller can provide an arbitrary
69   // pointer in |aux|. This pointer will then be forwarded to the sandbox
70   // policy each time a call is made through an EvaluateSyscall function
71   // pointer.  One common use case would be to pass the "aux" pointer as an
72   // argument to Trap() functions.
73   typedef ErrorCode (*EvaluateSyscall)(SandboxBPF* sandbox_compiler,
74                                        int system_call_number,
75                                        void* aux);
76   // A vector of BPF instructions that need to be installed as a filter
77   // program in the kernel.
78   typedef std::vector<struct sock_filter> Program;
79
80   // Constructors and destructors.
81   // NOTE: Setting a policy and starting the sandbox is a one-way operation.
82   //       The kernel does not provide any option for unloading a loaded
83   //       sandbox. Strictly speaking, that means we should disallow calling
84   //       the destructor, if StartSandbox() has ever been called. In practice,
85   //       this makes it needlessly complicated to operate on "Sandbox"
86   //       objects. So, we instead opted to allow object destruction. But it
87   //       should be noted that during its lifetime, the object probably made
88   //       irreversible state changes to the runtime environment. These changes
89   //       stay in effect even after the destructor has been run.
90   SandboxBPF();
91   ~SandboxBPF();
92
93   // Checks whether a particular system call number is valid on the current
94   // architecture. E.g. on ARM there's a non-contiguous range of private
95   // system calls.
96   static bool IsValidSyscallNumber(int sysnum);
97
98   // There are a lot of reasons why the Seccomp sandbox might not be available.
99   // This could be because the kernel does not support Seccomp mode, or it
100   // could be because another sandbox is already active.
101   // "proc_fd" should be a file descriptor for "/proc", or -1 if not
102   // provided by the caller.
103   static SandboxStatus SupportsSeccompSandbox(int proc_fd);
104
105   // The sandbox needs to be able to access files in "/proc/self". If this
106   // directory is not accessible when "startSandbox()" gets called, the caller
107   // can provide an already opened file descriptor by calling "set_proc_fd()".
108   // The sandbox becomes the new owner of this file descriptor and will
109   // eventually close it when "StartSandbox()" executes.
110   void set_proc_fd(int proc_fd);
111
112   // The system call evaluator function is called with the system
113   // call number. It can decide to allow the system call unconditionally
114   // by returning ERR_ALLOWED; it can deny the system call unconditionally by
115   // returning an appropriate "errno" value; or it can request inspection
116   // of system call argument(s) by returning a suitable ErrorCode.
117   // The "aux" parameter can be used to pass optional data to the system call
118   // evaluator. There are different possible uses for this data, but one of the
119   // use cases would be for the policy to then forward this pointer to a Trap()
120   // handler. In this case, of course, the data that is pointed to must remain
121   // valid for the entire time that Trap() handlers can be called; typically,
122   // this would be the lifetime of the program.
123   // DEPRECATED: use the policy interface below.
124   void SetSandboxPolicyDeprecated(EvaluateSyscall syscallEvaluator, void* aux);
125
126   // Set the BPF policy as |policy|. Ownership of |policy| is transfered here
127   // to the sandbox object.
128   void SetSandboxPolicy(SandboxBPFPolicy* policy);
129
130   // We can use ErrorCode to request calling of a trap handler. This method
131   // performs the required wrapping of the callback function into an
132   // ErrorCode object.
133   // The "aux" field can carry a pointer to arbitrary data. See EvaluateSyscall
134   // for a description of how to pass data from SetSandboxPolicy() to a Trap()
135   // handler.
136   ErrorCode Trap(Trap::TrapFnc fnc, const void* aux);
137
138   // Calls a user-space trap handler and disables all sandboxing for system
139   // calls made from this trap handler.
140   // This feature is available only if explicitly enabled by the user having
141   // set the CHROME_SANDBOX_DEBUGGING environment variable.
142   // Returns an ET_INVALID ErrorCode, if called when not enabled.
143   // NOTE: This feature, by definition, disables all security features of
144   //   the sandbox. It should never be used in production, but it can be
145   //   very useful to diagnose code that is incompatible with the sandbox.
146   //   If even a single system call returns "UnsafeTrap", the security of
147   //   entire sandbox should be considered compromised.
148   ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void* aux);
149
150   // From within an UnsafeTrap() it is often useful to be able to execute
151   // the system call that triggered the trap. The ForwardSyscall() method
152   // makes this easy. It is more efficient than calling glibc's syscall()
153   // function, as it avoid the extra round-trip to the signal handler. And
154   // it automatically does the correct thing to report kernel-style error
155   // conditions, rather than setting errno. See the comments for TrapFnc for
156   // details. In other words, the return value from ForwardSyscall() is
157   // directly suitable as a return value for a trap handler.
158   static intptr_t ForwardSyscall(const struct arch_seccomp_data& args);
159
160   // We can also use ErrorCode to request evaluation of a conditional
161   // statement based on inspection of system call parameters.
162   // This method wrap an ErrorCode object around the conditional statement.
163   // Argument "argno" (1..6) will be compared to "value" using comparator
164   // "op". If the condition is true "passed" will be returned, otherwise
165   // "failed".
166   // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1)
167   // If it is outside this range, the sandbox treats the system call just
168   // the same as any other ABI violation (i.e. it aborts with an error
169   // message).
170   ErrorCode Cond(int argno,
171                  ErrorCode::ArgType is_32bit,
172                  ErrorCode::Operation op,
173                  uint64_t value,
174                  const ErrorCode& passed,
175                  const ErrorCode& failed);
176
177   // Kill the program and print an error message.
178   ErrorCode Kill(const char* msg);
179
180   // This is the main public entry point. It finds all system calls that
181   // need rewriting, sets up the resources needed by the sandbox, and
182   // enters Seccomp mode.
183   // The calling process must specify its current SandboxThreadState, as a way
184   // to tell the sandbox which type of kernel support it should engage.
185   // It is possible to stack multiple sandboxes by creating separate "Sandbox"
186   // objects and calling "StartSandbox()" on each of them. Please note, that
187   // this requires special care, though, as newly stacked sandboxes can never
188   // relax restrictions imposed by earlier sandboxes. Furthermore, installing
189   // a new policy requires making system calls, that might already be
190   // disallowed.
191   // Finally, stacking does add more kernel overhead than having a single
192   // combined policy. So, it should only be used if there are no alternatives.
193   bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT;
194
195   // Assembles a BPF filter program from the current policy. After calling this
196   // function, you must not call any other sandboxing function.
197   // Typically, AssembleFilter() is only used by unit tests and by sandbox
198   // internals. It should not be used by production code.
199   // For performance reasons, we normally only run the assembled BPF program
200   // through the verifier, iff the program was built in debug mode.
201   // But by setting "force_verification", the caller can request that the
202   // verifier is run unconditionally. This is useful for unittests.
203   Program* AssembleFilter(bool force_verification);
204
205   // Returns the fatal ErrorCode that is used to indicate that somebody
206   // attempted to pass a 64bit value in a 32bit system call argument.
207   // This method is primarily needed for testing purposes.
208   ErrorCode Unexpected64bitArgument();
209
210  private:
211   friend class CodeGen;
212   friend class SandboxUnittestHelper;
213   friend class ErrorCode;
214
215   struct Range {
216     Range(uint32_t f, uint32_t t, const ErrorCode& e)
217         : from(f), to(t), err(e) {}
218     uint32_t from, to;
219     ErrorCode err;
220   };
221   typedef std::vector<Range> Ranges;
222   typedef std::map<uint32_t, ErrorCode> ErrMap;
223   typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds;
224
225   // Get a file descriptor pointing to "/proc", if currently available.
226   int proc_fd() { return proc_fd_; }
227
228   // Creates a subprocess and runs "code_in_sandbox" inside of the specified
229   // policy. The caller has to make sure that "this" has not yet been
230   // initialized with any other policies.
231   bool RunFunctionInPolicy(void (*code_in_sandbox)(),
232                            EvaluateSyscall syscall_evaluator,
233                            void* aux);
234
235   // Performs a couple of sanity checks to verify that the kernel supports the
236   // features that we need for successful sandboxing.
237   // The caller has to make sure that "this" has not yet been initialized with
238   // any other policies.
239   bool KernelSupportSeccompBPF();
240
241   // Verify that the current policy passes some basic sanity checks.
242   void PolicySanityChecks(SandboxBPFPolicy* policy);
243
244   // Assembles and installs a filter based on the policy that has previously
245   // been configured with SetSandboxPolicy().
246   void InstallFilter(SandboxThreadState thread_state);
247
248   // Verify the correctness of a compiled program by comparing it against the
249   // current policy. This function should only ever be called by unit tests and
250   // by the sandbox internals. It should not be used by production code.
251   void VerifyProgram(const Program& program, bool has_unsafe_traps);
252
253   // Finds all the ranges of system calls that need to be handled. Ranges are
254   // sorted in ascending order of system call numbers. There are no gaps in the
255   // ranges. System calls with identical ErrorCodes are coalesced into a single
256   // range.
257   void FindRanges(Ranges* ranges);
258
259   // Returns a BPF program snippet that implements a jump table for the
260   // given range of system call numbers. This function runs recursively.
261   Instruction* AssembleJumpTable(CodeGen* gen,
262                                  Ranges::const_iterator start,
263                                  Ranges::const_iterator stop);
264
265   // Returns a BPF program snippet that makes the BPF filter program exit
266   // with the given ErrorCode "err". N.B. the ErrorCode may very well be a
267   // conditional expression; if so, this function will recursively call
268   // CondExpression() and possibly RetExpression() to build a complex set of
269   // instructions.
270   Instruction* RetExpression(CodeGen* gen, const ErrorCode& err);
271
272   // Returns a BPF program that evaluates the conditional expression in
273   // "cond" and returns the appropriate value from the BPF filter program.
274   // This function recursively calls RetExpression(); it should only ever be
275   // called from RetExpression().
276   Instruction* CondExpression(CodeGen* gen, const ErrorCode& cond);
277
278   static SandboxStatus status_;
279
280   bool quiet_;
281   int proc_fd_;
282   scoped_ptr<const SandboxBPFPolicy> policy_;
283   Conds* conds_;
284   bool sandbox_has_started_;
285
286   DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
287 };
288
289 }  // namespace sandbox
290
291 #endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__