Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / sandbox / linux / seccomp-bpf / sandbox_bpf.h
index f2653b0..d7fb1ff 100644 (file)
@@ -5,43 +5,27 @@
 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
 #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__
 
-#include <stddef.h>
-#include <sys/types.h>
-#include <sys/wait.h>
+#include <stdint.h>
 
-#include <algorithm>
-#include <limits>
 #include <map>
 #include <set>
-#include <utility>
 #include <vector>
 
-#include "sandbox/linux/seccomp-bpf/die.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "sandbox/linux/seccomp-bpf/errorcode.h"
-#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
-#include "sandbox/linux/seccomp-bpf/port.h"
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy_forward.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
+#include "sandbox/sandbox_export.h"
 
-namespace playground2 {
-
-struct arch_seccomp_data {
-  int      nr;
-  uint32_t arch;
-  uint64_t instruction_pointer;
-  uint64_t args[6];
-};
-
-struct arch_sigsys {
-  void         *ip;
-  int          nr;
-  unsigned int arch;
-};
+struct sock_filter;
 
+namespace sandbox {
 class CodeGen;
+class SandboxBPFPolicy;
 class SandboxUnittestHelper;
 struct Instruction;
 
-class Sandbox {
+class SANDBOX_EXPORT SandboxBPF {
  public:
   enum SandboxStatus {
     STATUS_UNKNOWN,      // Status prior to calling supportsSeccompSandbox()
@@ -51,15 +35,17 @@ class Sandbox {
     STATUS_ENABLED       // The sandbox is now active
   };
 
-  // BpfSandboxPolicy is the following type:
-  // ErrorCode (Sandbox *sb, int sysnum, void *aux);
-  // When calling setSandboxPolicy(), the caller can provide an arbitrary
-  // pointer in |aux|. This pointer will then be forwarded to the sandbox
-  // policy each time a call is made through an EvaluateSyscall function
-  // pointer.  One common use case would be to pass the "aux" pointer as an
-  // argument to Trap() functions.
-  typedef BpfSandboxPolicy* EvaluateSyscall;
-  typedef std::vector<std::pair<EvaluateSyscall, void *> >Evaluators;
+  // Depending on the level of kernel support, seccomp-bpf may require the
+  // process to be single-threaded in order to enable it. When calling
+  // StartSandbox(), the program should indicate whether or not the sandbox
+  // should try and engage with multi-thread support.
+  enum SandboxThreadState {
+    PROCESS_INVALID,
+    PROCESS_SINGLE_THREADED,  // The program is currently single-threaded.
+    // Note: PROCESS_MULTI_THREADED requires experimental kernel support that
+    // has not been contributed to upstream Linux.
+    PROCESS_MULTI_THREADED,   // The program may be multi-threaded.
+  };
 
   // A vector of BPF instructions that need to be installed as a filter
   // program in the kernel.
@@ -75,8 +61,8 @@ class Sandbox {
   //       should be noted that during its lifetime, the object probably made
   //       irreversible state changes to the runtime environment. These changes
   //       stay in effect even after the destructor has been run.
-  Sandbox();
-  ~Sandbox();
+  SandboxBPF();
+  ~SandboxBPF();
 
   // Checks whether a particular system call number is valid on the current
   // architecture. E.g. on ARM there's a non-contiguous range of private
@@ -90,6 +76,10 @@ class Sandbox {
   // provided by the caller.
   static SandboxStatus SupportsSeccompSandbox(int proc_fd);
 
+  // Determines if the kernel has support for the seccomp() system call to
+  // synchronize BPF filters across a thread group.
+  static SandboxStatus SupportsSeccompThreadFilterSynchronization();
+
   // The sandbox needs to be able to access files in "/proc/self". If this
   // directory is not accessible when "startSandbox()" gets called, the caller
   // can provide an already opened file descriptor by calling "set_proc_fd()".
@@ -97,18 +87,9 @@ class Sandbox {
   // eventually close it when "StartSandbox()" executes.
   void set_proc_fd(int proc_fd);
 
-  // The system call evaluator function is called with the system
-  // call number. It can decide to allow the system call unconditionally
-  // by returning ERR_ALLOWED; it can deny the system call unconditionally by
-  // returning an appropriate "errno" value; or it can request inspection
-  // of system call argument(s) by returning a suitable ErrorCode.
-  // The "aux" parameter can be used to pass optional data to the system call
-  // evaluator. There are different possible uses for this data, but one of the
-  // use cases would be for the policy to then forward this pointer to a Trap()
-  // handler. In this case, of course, the data that is pointed to must remain
-  // valid for the entire time that Trap() handlers can be called; typically,
-  // this would be the lifetime of the program.
-  void SetSandboxPolicy(EvaluateSyscall syscallEvaluator, void *aux);
+  // Set the BPF policy as |policy|. Ownership of |policy| is transfered here
+  // to the sandbox object.
+  void SetSandboxPolicy(SandboxBPFPolicy* policy);
 
   // We can use ErrorCode to request calling of a trap handler. This method
   // performs the required wrapping of the callback function into an
@@ -116,7 +97,7 @@ class Sandbox {
   // The "aux" field can carry a pointer to arbitrary data. See EvaluateSyscall
   // for a description of how to pass data from SetSandboxPolicy() to a Trap()
   // handler.
-  ErrorCode Trap(Trap::TrapFnc fnc, const void *aux);
+  static ErrorCode Trap(Trap::TrapFnc fnc, const void* aux);
 
   // Calls a user-space trap handler and disables all sandboxing for system
   // calls made from this trap handler.
@@ -128,7 +109,11 @@ class Sandbox {
   //   very useful to diagnose code that is incompatible with the sandbox.
   //   If even a single system call returns "UnsafeTrap", the security of
   //   entire sandbox should be considered compromised.
-  ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void *aux);
+  static ErrorCode UnsafeTrap(Trap::TrapFnc fnc, const void* aux);
+
+  // UnsafeTraps require some syscalls to always be allowed.
+  // This helper function returns true for these calls.
+  static bool IsRequiredForUnsafeTrap(int sysno);
 
   // From within an UnsafeTrap() it is often useful to be able to execute
   // the system call that triggered the trap. The ForwardSyscall() method
@@ -143,24 +128,36 @@ class Sandbox {
   // We can also use ErrorCode to request evaluation of a conditional
   // statement based on inspection of system call parameters.
   // This method wrap an ErrorCode object around the conditional statement.
-  // Argument "argno" (1..6) will be compared to "value" using comparator
-  // "op". If the condition is true "passed" will be returned, otherwise
-  // "failed".
+  // Argument "argno" (1..6) will be bitwise-AND'd with "mask" and compared
+  // to "value"; if equal, then "passed" will be returned, otherwise "failed".
   // If "is32bit" is set, the argument must in the range of 0x0..(1u << 32 - 1)
   // If it is outside this range, the sandbox treats the system call just
   // the same as any other ABI violation (i.e. it aborts with an error
   // message).
-  ErrorCode Cond(int argno, ErrorCode::ArgType is_32bit,
+  ErrorCode CondMaskedEqual(int argno,
+                            ErrorCode::ArgType is_32bit,
+                            uint64_t mask,
+                            uint64_t value,
+                            const ErrorCode& passed,
+                            const ErrorCode& failed);
+
+  // Legacy variant of CondMaskedEqual that supports a few comparison
+  // operations, which get converted into masked-equality comparisons.
+  ErrorCode Cond(int argno,
+                 ErrorCode::ArgType is_32bit,
                  ErrorCode::Operation op,
-                 uint64_t value, const ErrorCode& passed,
+                 uint64_t value,
+                 const ErrorCode& passed,
                  const ErrorCode& failed);
 
   // Kill the program and print an error message.
-  ErrorCode Kill(const char *msg);
+  static ErrorCode Kill(const char* msg);
 
   // This is the main public entry point. It finds all system calls that
   // need rewriting, sets up the resources needed by the sandbox, and
   // enters Seccomp mode.
+  // The calling process must specify its current SandboxThreadState, as a way
+  // to tell the sandbox which type of kernel support it should engage.
   // It is possible to stack multiple sandboxes by creating separate "Sandbox"
   // objects and calling "StartSandbox()" on each of them. Please note, that
   // this requires special care, though, as newly stacked sandboxes can never
@@ -169,7 +166,7 @@ class Sandbox {
   // disallowed.
   // Finally, stacking does add more kernel overhead than having a single
   // combined policy. So, it should only be used if there are no alternatives.
-  void StartSandbox();
+  bool StartSandbox(SandboxThreadState thread_state) WARN_UNUSED_RESULT;
 
   // Assembles a BPF filter program from the current policy. After calling this
   // function, you must not call any other sandboxing function.
@@ -179,12 +176,12 @@ class Sandbox {
   // through the verifier, iff the program was built in debug mode.
   // But by setting "force_verification", the caller can request that the
   // verifier is run unconditionally. This is useful for unittests.
-  Program *AssembleFilter(bool force_verification);
+  ProgramAssembleFilter(bool force_verification);
 
   // Returns the fatal ErrorCode that is used to indicate that somebody
   // attempted to pass a 64bit value in a 32bit system call argument.
   // This method is primarily needed for testing purposes.
-  ErrorCode Unexpected64bitArgument();
+  static ErrorCode Unexpected64bitArgument();
 
  private:
   friend class CodeGen;
@@ -193,17 +190,21 @@ class Sandbox {
 
   struct Range {
     Range(uint32_t f, uint32_t t, const ErrorCode& e)
-        : from(f),
-          to(t),
-          err(e) {
-    }
-    uint32_t  from, to;
+        : from(f), to(t), err(e) {}
+    uint32_t from, to;
     ErrorCode err;
   };
   typedef std::vector<Range> Ranges;
   typedef std::map<uint32_t, ErrorCode> ErrMap;
   typedef std::set<ErrorCode, struct ErrorCode::LessThan> Conds;
 
+  // Used by CondExpressionHalf to track which half of the argument it's
+  // emitting instructions for.
+  enum ArgHalf {
+    LowerHalf,
+    UpperHalf,
+  };
+
   // Get a file descriptor pointing to "/proc", if currently available.
   int proc_fd() { return proc_fd_; }
 
@@ -211,7 +212,7 @@ class Sandbox {
   // policy. The caller has to make sure that "this" has not yet been
   // initialized with any other policies.
   bool RunFunctionInPolicy(void (*code_in_sandbox)(),
-                           EvaluateSyscall syscall_evaluator, void *aux);
+                           scoped_ptr<SandboxBPFPolicy> policy);
 
   // Performs a couple of sanity checks to verify that the kernel supports the
   // features that we need for successful sandboxing.
@@ -220,11 +221,42 @@ class Sandbox {
   bool KernelSupportSeccompBPF();
 
   // Verify that the current policy passes some basic sanity checks.
-  void PolicySanityChecks(EvaluateSyscall syscall_evaluator, void *aux);
+  void PolicySanityChecks(SandboxBPFPolicy* policy);
 
   // Assembles and installs a filter based on the policy that has previously
   // been configured with SetSandboxPolicy().
-  void InstallFilter();
+  void InstallFilter(bool must_sync_threads);
+
+  // Compile the configured policy into a complete instruction sequence.
+  // (See MaybeAddEscapeHatch for |has_unsafe_traps|.)
+  Instruction* CompilePolicy(CodeGen* gen, bool* has_unsafe_traps);
+
+  // Return an instruction sequence that checks the
+  // arch_seccomp_data's "arch" field is valid, and then passes
+  // control to |passed| if so.
+  Instruction* CheckArch(CodeGen* gen, Instruction* passed);
+
+  // If the |rest| instruction sequence contains any unsafe traps,
+  // then sets |*has_unsafe_traps| to true and returns an instruction
+  // sequence that allows all system calls from Syscall::Call(), and
+  // otherwise passes control to |rest|.
+  //
+  // If |rest| contains no unsafe traps, then |rest| is returned
+  // directly and |*has_unsafe_traps| is set to false.
+  Instruction* MaybeAddEscapeHatch(CodeGen* gen,
+                                   bool* has_unsafe_traps,
+                                   Instruction* rest);
+
+  // Return an instruction sequence that loads and checks the system
+  // call number, performs a binary search, and then dispatches to an
+  // appropriate instruction sequence compiled from the current
+  // policy.
+  Instruction* DispatchSyscall(CodeGen* gen);
+
+  // Return an instruction sequence that checks the system call number
+  // (expected to be loaded in register A) and if valid, passes
+  // control to |passed| (with register A still valid).
+  Instruction* CheckSyscallNumber(CodeGen* gen, Instruction* passed);
 
   // Verify the correctness of a compiled program by comparing it against the
   // current policy. This function should only ever be called by unit tests and
@@ -235,11 +267,11 @@ class Sandbox {
   // sorted in ascending order of system call numbers. There are no gaps in the
   // ranges. System calls with identical ErrorCodes are coalesced into a single
   // range.
-  void FindRanges(Ranges *ranges);
+  void FindRanges(Rangesranges);
 
   // Returns a BPF program snippet that implements a jump table for the
   // given range of system call numbers. This function runs recursively.
-  Instruction *AssembleJumpTable(CodeGen *gen,
+  Instruction* AssembleJumpTable(CodeGen* gen,
                                  Ranges::const_iterator start,
                                  Ranges::const_iterator stop);
 
@@ -248,24 +280,33 @@ class Sandbox {
   // conditional expression; if so, this function will recursively call
   // CondExpression() and possibly RetExpression() to build a complex set of
   // instructions.
-  Instruction *RetExpression(CodeGen *gen, const ErrorCode& err);
+  Instruction* RetExpression(CodeGen* gen, const ErrorCode& err);
 
   // Returns a BPF program that evaluates the conditional expression in
   // "cond" and returns the appropriate value from the BPF filter program.
   // This function recursively calls RetExpression(); it should only ever be
   // called from RetExpression().
-  Instruction *CondExpression(CodeGen *gen, const ErrorCode& cond);
+  Instruction* CondExpression(CodeGen* gen, const ErrorCode& cond);
+
+  // Returns a BPF program that evaluates half of a conditional expression;
+  // it should only ever be called from CondExpression().
+  Instruction* CondExpressionHalf(CodeGen* gen,
+                                  const ErrorCode& cond,
+                                  ArgHalf half,
+                                  Instruction* passed,
+                                  Instruction* failed);
 
   static SandboxStatus status_;
 
-  bool       quiet_;
-  int        proc_fd_;
-  Evaluators *evaluators_;
-  Conds      *conds_;
+  bool quiet_;
+  int proc_fd_;
+  scoped_ptr<const SandboxBPFPolicy> policy_;
+  Conds* conds_;
+  bool sandbox_has_started_;
 
-  DISALLOW_COPY_AND_ASSIGN(Sandbox);
+  DISALLOW_COPY_AND_ASSIGN(SandboxBPF);
 };
 
-}  // namespace
+}  // namespace sandbox
 
 #endif  // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_H__