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