Home | History | Annotate | Download | only in seccomp-bpf
      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 <errno.h>
      6 #include <signal.h>
      7 #include <string.h>
      8 #include <sys/prctl.h>
      9 #include <sys/syscall.h>
     10 
     11 #ifndef SECCOMP_BPF_STANDALONE
     12 #include "base/logging.h"
     13 #include "base/posix/eintr_wrapper.h"
     14 #endif
     15 
     16 #include "sandbox/linux/seccomp-bpf/codegen.h"
     17 #include "sandbox/linux/seccomp-bpf/die.h"
     18 #include "sandbox/linux/seccomp-bpf/syscall.h"
     19 #include "sandbox/linux/seccomp-bpf/trap.h"
     20 
     21 // Android's signal.h doesn't define ucontext etc.
     22 #if defined(OS_ANDROID)
     23 #include "sandbox/linux/services/android_ucontext.h"
     24 #endif
     25 
     26 #include <limits>
     27 
     28 
     29 namespace {
     30 
     31 const int kCapacityIncrement = 20;
     32 
     33 // Unsafe traps can only be turned on, if the user explicitly allowed them
     34 // by setting the CHROME_SANDBOX_DEBUGGING environment variable.
     35 const char kSandboxDebuggingEnv[] = "CHROME_SANDBOX_DEBUGGING";
     36 
     37 // We need to tell whether we are performing a "normal" callback, or
     38 // whether we were called recursively from within a UnsafeTrap() callback.
     39 // This is a little tricky to do, because we need to somehow get access to
     40 // per-thread data from within a signal context. Normal TLS storage is not
     41 // safely accessible at this time. We could roll our own, but that involves
     42 // a lot of complexity. Instead, we co-opt one bit in the signal mask.
     43 // If BUS is blocked, we assume that we have been called recursively.
     44 // There is a possibility for collision with other code that needs to do
     45 // this, but in practice the risks are low.
     46 // If SIGBUS turns out to be a problem, we could instead co-opt one of the
     47 // realtime signals. There are plenty of them. Unfortunately, there is no
     48 // way to mark a signal as allocated. So, the potential for collision is
     49 // possibly even worse.
     50 bool GetIsInSigHandler(const ucontext_t *ctx) {
     51   // Note: on Android, sigismember does not take a pointer to const.
     52   return sigismember(const_cast<sigset_t*>(&ctx->uc_sigmask), SIGBUS);
     53 }
     54 
     55 void SetIsInSigHandler() {
     56   sigset_t mask;
     57   if (sigemptyset(&mask) ||
     58       sigaddset(&mask, SIGBUS) ||
     59       sigprocmask(SIG_BLOCK, &mask, NULL)) {
     60     SANDBOX_DIE("Failed to block SIGBUS");
     61   }
     62 }
     63 
     64 }  // namespace
     65 
     66 namespace playground2 {
     67 
     68 Trap::Trap()
     69     : trap_array_(NULL),
     70       trap_array_size_(0),
     71       trap_array_capacity_(0),
     72       has_unsafe_traps_(false) {
     73   // Set new SIGSYS handler
     74   struct sigaction sa = { };
     75   sa.sa_sigaction = SigSysAction;
     76   sa.sa_flags = SA_SIGINFO | SA_NODEFER;
     77   if (sigaction(SIGSYS, &sa, NULL) < 0) {
     78     SANDBOX_DIE("Failed to configure SIGSYS handler");
     79   }
     80 
     81   // Unmask SIGSYS
     82   sigset_t mask;
     83   if (sigemptyset(&mask) ||
     84       sigaddset(&mask, SIGSYS) ||
     85       sigprocmask(SIG_UNBLOCK, &mask, NULL)) {
     86     SANDBOX_DIE("Failed to configure SIGSYS handler");
     87   }
     88 }
     89 
     90 Trap *Trap::GetInstance() {
     91   // Note: This class is not thread safe. It is the caller's responsibility
     92   // to avoid race conditions. Normally, this is a non-issue as the sandbox
     93   // can only be initialized if there are no other threads present.
     94   // Also, this is not a normal singleton. Once created, the global trap
     95   // object must never be destroyed again.
     96   if (!global_trap_) {
     97     global_trap_ = new Trap();
     98     if (!global_trap_) {
     99       SANDBOX_DIE("Failed to allocate global trap handler");
    100     }
    101   }
    102   return global_trap_;
    103 }
    104 
    105 void Trap::SigSysAction(int nr, siginfo_t *info, void *void_context) {
    106   if (!global_trap_) {
    107     SANDBOX_DIE("This can't happen. Found no global singleton instance "
    108                 "for Trap() handling.");
    109   }
    110   global_trap_->SigSys(nr, info, void_context);
    111 }
    112 
    113 void Trap::SigSys(int nr, siginfo_t *info, void *void_context) {
    114   // Various sanity checks to make sure we actually received a signal
    115   // triggered by a BPF filter. If something else triggered SIGSYS
    116   // (e.g. kill()), there is really nothing we can do with this signal.
    117   if (nr != SIGSYS || info->si_code != SYS_SECCOMP || !void_context ||
    118       info->si_errno <= 0 ||
    119       static_cast<size_t>(info->si_errno) > trap_array_size_) {
    120     // SANDBOX_DIE() can call LOG(FATAL). This is not normally async-signal
    121     // safe and can lead to bugs. We should eventually implement a different
    122     // logging and reporting mechanism that is safe to be called from
    123     // the sigSys() handler.
    124     // TODO: If we feel confident that our code otherwise works correctly, we
    125     //       could actually make an argument that spurious SIGSYS should
    126     //       just get silently ignored. TBD
    127     SANDBOX_DIE("Unexpected SIGSYS received.");
    128   }
    129 
    130   // Signal handlers should always preserve "errno". Otherwise, we could
    131   // trigger really subtle bugs.
    132   const int old_errno   = errno;
    133 
    134   // Obtain the signal context. This, most notably, gives us access to
    135   // all CPU registers at the time of the signal.
    136   ucontext_t *ctx = reinterpret_cast<ucontext_t *>(void_context);
    137 
    138   // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
    139   // most versions of glibc don't include this information in siginfo_t. So,
    140   // we need to explicitly copy it into a arch_sigsys structure.
    141   struct arch_sigsys sigsys;
    142   memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
    143 
    144   // Some more sanity checks.
    145   if (sigsys.ip != reinterpret_cast<void *>(SECCOMP_IP(ctx)) ||
    146       sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) ||
    147       sigsys.arch != SECCOMP_ARCH) {
    148     SANDBOX_DIE("Sanity checks are failing after receiving SIGSYS.");
    149   }
    150 
    151   intptr_t rc;
    152   if (has_unsafe_traps_ && GetIsInSigHandler(ctx)) {
    153     errno = old_errno;
    154     if (sigsys.nr == __NR_clone) {
    155       SANDBOX_DIE("Cannot call clone() from an UnsafeTrap() handler.");
    156     }
    157     rc = SandboxSyscall(sigsys.nr,
    158                         SECCOMP_PARM1(ctx), SECCOMP_PARM2(ctx),
    159                         SECCOMP_PARM3(ctx), SECCOMP_PARM4(ctx),
    160                         SECCOMP_PARM5(ctx), SECCOMP_PARM6(ctx));
    161   } else {
    162     const ErrorCode& err = trap_array_[info->si_errno - 1];
    163     if (!err.safe_) {
    164       SetIsInSigHandler();
    165     }
    166 
    167     // Copy the seccomp-specific data into a arch_seccomp_data structure. This
    168     // is what we are showing to TrapFnc callbacks that the system call
    169     // evaluator registered with the sandbox.
    170     struct arch_seccomp_data data = {
    171       sigsys.nr,
    172       SECCOMP_ARCH,
    173       reinterpret_cast<uint64_t>(sigsys.ip),
    174       {
    175         static_cast<uint64_t>(SECCOMP_PARM1(ctx)),
    176         static_cast<uint64_t>(SECCOMP_PARM2(ctx)),
    177         static_cast<uint64_t>(SECCOMP_PARM3(ctx)),
    178         static_cast<uint64_t>(SECCOMP_PARM4(ctx)),
    179         static_cast<uint64_t>(SECCOMP_PARM5(ctx)),
    180         static_cast<uint64_t>(SECCOMP_PARM6(ctx))
    181       }
    182     };
    183 
    184     // Now call the TrapFnc callback associated with this particular instance
    185     // of SECCOMP_RET_TRAP.
    186     rc = err.fnc_(data, err.aux_);
    187   }
    188 
    189   // Update the CPU register that stores the return code of the system call
    190   // that we just handled, and restore "errno" to the value that it had
    191   // before entering the signal handler.
    192   SECCOMP_RESULT(ctx) = static_cast<greg_t>(rc);
    193   errno               = old_errno;
    194 
    195   return;
    196 }
    197 
    198 bool Trap::TrapKey::operator<(const TrapKey& o) const {
    199   if (fnc != o.fnc) {
    200     return fnc < o.fnc;
    201   } else if (aux != o.aux) {
    202     return aux < o.aux;
    203   } else {
    204     return safe < o.safe;
    205   }
    206 }
    207 
    208 ErrorCode Trap::MakeTrap(TrapFnc fnc, const void *aux, bool safe) {
    209   return GetInstance()->MakeTrapImpl(fnc, aux, safe);
    210 }
    211 
    212 ErrorCode Trap::MakeTrapImpl(TrapFnc fnc, const void *aux, bool safe) {
    213   if (!safe && !SandboxDebuggingAllowedByUser()) {
    214     // Unless the user set the CHROME_SANDBOX_DEBUGGING environment variable,
    215     // we never return an ErrorCode that is marked as "unsafe". This also
    216     // means, the BPF compiler will never emit code that allow unsafe system
    217     // calls to by-pass the filter (because they use the magic return address
    218     // from SandboxSyscall(-1)).
    219 
    220     // This SANDBOX_DIE() can optionally be removed. It won't break security,
    221     // but it might make error messages from the BPF compiler a little harder
    222     // to understand. Removing the SANDBOX_DIE() allows callers to easyly check
    223     // whether unsafe traps are supported (by checking whether the returned
    224     // ErrorCode is ET_INVALID).
    225     SANDBOX_DIE("Cannot use unsafe traps unless CHROME_SANDBOX_DEBUGGING "
    226                 "is enabled");
    227 
    228     return ErrorCode();
    229   }
    230 
    231   // Each unique pair of TrapFnc and auxiliary data make up a distinct instance
    232   // of a SECCOMP_RET_TRAP.
    233   TrapKey key(fnc, aux, safe);
    234   TrapIds::const_iterator iter = trap_ids_.find(key);
    235 
    236   // We return unique identifiers together with SECCOMP_RET_TRAP. This allows
    237   // us to associate trap with the appropriate handler. The kernel allows us
    238   // identifiers in the range from 0 to SECCOMP_RET_DATA (0xFFFF). We want to
    239   // avoid 0, as it could be confused for a trap without any specific id.
    240   // The nice thing about sequentially numbered identifiers is that we can also
    241   // trivially look them up from our signal handler without making any system
    242   // calls that might be async-signal-unsafe.
    243   // In order to do so, we store all of our traps in a C-style trap_array_.
    244   uint16_t id;
    245   if (iter != trap_ids_.end()) {
    246     // We have seen this pair before. Return the same id that we assigned
    247     // earlier.
    248     id = iter->second;
    249   } else {
    250     // This is a new pair. Remember it and assign a new id.
    251     if (trap_array_size_ >= SECCOMP_RET_DATA /* 0xFFFF */ ||
    252         trap_array_size_ >= std::numeric_limits<typeof(id)>::max()) {
    253       // In practice, this is pretty much impossible to trigger, as there
    254       // are other kernel limitations that restrict overall BPF program sizes.
    255       SANDBOX_DIE("Too many SECCOMP_RET_TRAP callback instances");
    256     }
    257     id = trap_array_size_ + 1;
    258 
    259     // Our callers ensure that there are no other threads accessing trap_array_
    260     // concurrently (typically this is done by ensuring that we are single-
    261     // threaded while the sandbox is being set up). But we nonetheless are
    262     // modifying a life data structure that could be accessed any time a
    263     // system call is made; as system calls could be triggering SIGSYS.
    264     // So, we have to be extra careful that we update trap_array_ atomically.
    265     // In particular, this means we shouldn't be using realloc() to resize it.
    266     // Instead, we allocate a new array, copy the values, and then switch the
    267     // pointer. We only really care about the pointer being updated atomically
    268     // and the data that is pointed to being valid, as these are the only
    269     // values accessed from the signal handler. It is OK if trap_array_size_
    270     // is inconsistent with the pointer, as it is monotonously increasing.
    271     // Also, we only care about compiler barriers, as the signal handler is
    272     // triggered synchronously from a system call. We don't have to protect
    273     // against issues with the memory model or with completely asynchronous
    274     // events.
    275     if (trap_array_size_ >= trap_array_capacity_) {
    276       trap_array_capacity_     += kCapacityIncrement;
    277       ErrorCode *old_trap_array = trap_array_;
    278       ErrorCode *new_trap_array = new ErrorCode[trap_array_capacity_];
    279 
    280       // Language specs are unclear on whether the compiler is allowed to move
    281       // the "delete[]" above our preceding assignments and/or memory moves,
    282       // iff the compiler believes that "delete[]" doesn't have any other
    283       // global side-effects.
    284       // We insert optimization barriers to prevent this from happening.
    285       // The first barrier is probably not needed, but better be explicit in
    286       // what we want to tell the compiler.
    287       // The clang developer mailing list couldn't answer whether this is a
    288       // legitimate worry; but they at least thought that the barrier is
    289       // sufficient to prevent the (so far hypothetical) problem of re-ordering
    290       // of instructions by the compiler.
    291       memcpy(new_trap_array, trap_array_, trap_array_size_*sizeof(ErrorCode));
    292       asm volatile("" : "=r"(new_trap_array) : "0"(new_trap_array) : "memory");
    293       trap_array_ = new_trap_array;
    294       asm volatile("" : "=r"(trap_array_) : "0"(trap_array_) : "memory");
    295 
    296       delete[] old_trap_array;
    297     }
    298     trap_ids_[key] = id;
    299     trap_array_[trap_array_size_] = ErrorCode(fnc, aux, safe, id);
    300     return trap_array_[trap_array_size_++];
    301   }
    302 
    303   return ErrorCode(fnc, aux, safe, id);
    304 }
    305 
    306 bool Trap::SandboxDebuggingAllowedByUser() const {
    307   const char *debug_flag = getenv(kSandboxDebuggingEnv);
    308   return debug_flag && *debug_flag;
    309 }
    310 
    311 
    312 bool Trap::EnableUnsafeTrapsInSigSysHandler() {
    313   Trap *trap = GetInstance();
    314   if (!trap->has_unsafe_traps_) {
    315     // Unsafe traps are a one-way fuse. Once enabled, they can never be turned
    316     // off again.
    317     // We only allow enabling unsafe traps, if the user explicitly set an
    318     // appropriate environment variable. This prevents bugs that accidentally
    319     // disable all sandboxing for all users.
    320     if (trap->SandboxDebuggingAllowedByUser()) {
    321       // We only ever print this message once, when we enable unsafe traps the
    322       // first time.
    323       SANDBOX_INFO("WARNING! Disabling sandbox for debugging purposes");
    324       trap->has_unsafe_traps_ = true;
    325     } else {
    326       SANDBOX_INFO("Cannot disable sandbox and use unsafe traps unless "
    327                    "CHROME_SANDBOX_DEBUGGING is turned on first");
    328     }
    329   }
    330   // Returns the, possibly updated, value of has_unsafe_traps_.
    331   return trap->has_unsafe_traps_;
    332 }
    333 
    334 ErrorCode Trap::ErrorCodeFromTrapId(uint16_t id) {
    335   if (global_trap_ && id > 0 && id <= global_trap_->trap_array_size_) {
    336     return global_trap_->trap_array_[id - 1];
    337   } else {
    338     return ErrorCode();
    339   }
    340 }
    341 
    342 Trap *Trap::global_trap_;
    343 
    344 }  // namespace playground2
    345