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_TRAP_H__ 6 #define SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__ 7 8 #include <signal.h> 9 #include <stdint.h> 10 11 #include <map> 12 #include <vector> 13 14 #include "base/basictypes.h" 15 16 namespace sandbox { 17 18 class ErrorCode; 19 20 // The Trap class allows a BPF filter program to branch out to user space by 21 // raising a SIGSYS signal. 22 // N.B.: This class does not perform any synchronization operations. If 23 // modifications are made to any of the traps, it is the caller's 24 // responsibility to ensure that this happens in a thread-safe fashion. 25 // Preferably, that means that no other threads should be running at that 26 // time. For the purposes of our sandbox, this assertion should always be 27 // true. Threads are incompatible with the seccomp sandbox anyway. 28 class Trap { 29 public: 30 // TrapFnc is a pointer to a function that handles Seccomp traps in 31 // user-space. The seccomp policy can request that a trap handler gets 32 // installed; it does so by returning a suitable ErrorCode() from the 33 // syscallEvaluator. See the ErrorCode() constructor for how to pass in 34 // the function pointer. 35 // Please note that TrapFnc is executed from signal context and must be 36 // async-signal safe: 37 // http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html 38 // Also note that it follows the calling convention of native system calls. 39 // In other words, it reports an error by returning an exit code in the 40 // range -1..-4096. It should not set errno when reporting errors; on the 41 // other hand, accidentally modifying errno is harmless and the changes will 42 // be undone afterwards. 43 typedef intptr_t (*TrapFnc)(const struct arch_seccomp_data& args, void* aux); 44 45 // Registers a new trap handler and sets up the appropriate SIGSYS handler 46 // as needed. 47 // N.B.: This makes a permanent state change. Traps cannot be unregistered, 48 // as that would break existing BPF filters that are still active. 49 static ErrorCode MakeTrap(TrapFnc fnc, const void* aux, bool safe); 50 51 // Enables support for unsafe traps in the SIGSYS signal handler. This is a 52 // one-way fuse. It works in conjunction with the BPF compiler emitting code 53 // that unconditionally allows system calls, if they have a magic return 54 // address (i.e. SandboxSyscall(-1)). 55 // Once unsafe traps are enabled, the sandbox is essentially compromised. 56 // But this is still a very useful feature for debugging purposes. Use with 57 // care. This feature is availably only if enabled by the user (see above). 58 // Returns "true", if unsafe traps were turned on. 59 static bool EnableUnsafeTrapsInSigSysHandler(); 60 61 // Returns the ErrorCode associate with a particular trap id. 62 static ErrorCode ErrorCodeFromTrapId(uint16_t id); 63 64 private: 65 // The destructor is unimplemented. Don't ever attempt to destruct this 66 // object. It'll break subsequent system calls that trigger a SIGSYS. 67 ~Trap(); 68 69 struct TrapKey { 70 TrapKey(TrapFnc f, const void* a, bool s) : fnc(f), aux(a), safe(s) {} 71 TrapFnc fnc; 72 const void* aux; 73 bool safe; 74 bool operator<(const TrapKey&) const; 75 }; 76 typedef std::map<TrapKey, uint16_t> TrapIds; 77 78 // We only have a very small number of methods. We opt to make them static 79 // and have them internally call GetInstance(). This is a little more 80 // convenient than having each caller obtain short-lived reference to the 81 // singleton. 82 // It also gracefully deals with methods that should check for the singleton, 83 // but avoid instantiating it, if it doesn't exist yet 84 // (e.g. ErrorCodeFromTrapId()). 85 static Trap* GetInstance(); 86 static void SigSysAction(int nr, siginfo_t* info, void* void_context); 87 88 // Make sure that SigSys is not inlined in order to get slightly better crash 89 // dumps. 90 void SigSys(int nr, siginfo_t* info, void* void_context) 91 __attribute__((noinline)); 92 ErrorCode MakeTrapImpl(TrapFnc fnc, const void* aux, bool safe); 93 bool SandboxDebuggingAllowedByUser() const; 94 95 // We have a global singleton that handles all of our SIGSYS traps. This 96 // variable must never be deallocated after it has been set up initially, as 97 // there is no way to reset in-kernel BPF filters that generate SIGSYS 98 // events. 99 static Trap* global_trap_; 100 101 TrapIds trap_ids_; // Maps from TrapKeys to numeric ids 102 ErrorCode* trap_array_; // Array of ErrorCodes indexed by ids 103 size_t trap_array_size_; // Currently used size of array 104 size_t trap_array_capacity_; // Currently allocated capacity of array 105 bool has_unsafe_traps_; // Whether unsafe traps have been enabled 106 107 // Our constructor is private. A shared global instance is created 108 // automatically as needed. 109 // Copying and assigning is unimplemented. It doesn't make sense for a 110 // singleton. 111 DISALLOW_IMPLICIT_CONSTRUCTORS(Trap); 112 }; 113 114 } // namespace sandbox 115 116 #endif // SANDBOX_LINUX_SECCOMP_BPF_TRAP_H__ 117