Home | History | Annotate | Download | only in seccomp-bpf-helpers
      1 // Copyright (c) 2013 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 // Note: any code in this file MUST be async-signal safe.
      6 
      7 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
      8 
      9 #include <unistd.h>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/posix/eintr_wrapper.h"
     13 #include "build/build_config.h"
     14 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
     15 
     16 #define SECCOMP_MESSAGE_COMMON_CONTENT "seccomp-bpf failure"
     17 #define SECCOMP_MESSAGE_CLONE_CONTENT "clone() failure"
     18 #define SECCOMP_MESSAGE_PRCTL_CONTENT "prctl() failure"
     19 #define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure"
     20 #define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure"
     21 #define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure"
     22 
     23 namespace {
     24 
     25 inline bool IsArchitectureX86_64() {
     26 #if defined(__x86_64__)
     27   return true;
     28 #else
     29   return false;
     30 #endif
     31 }
     32 
     33 // Write |error_message| to stderr. Similar to RawLog(), but a bit more careful
     34 // about async-signal safety. |size| is the size to write and should typically
     35 // not include a terminating \0.
     36 void WriteToStdErr(const char* error_message, size_t size) {
     37   while (size > 0) {
     38     // TODO(jln): query the current policy to check if send() is available and
     39     // use it to perform a non-blocking write.
     40     const int ret = HANDLE_EINTR(write(STDERR_FILENO, error_message, size));
     41     // We can't handle any type of error here.
     42     if (ret <= 0 || static_cast<size_t>(ret) > size) break;
     43     size -= ret;
     44     error_message += ret;
     45   }
     46 }
     47 
     48 // Print a seccomp-bpf failure to handle |sysno| to stderr in an
     49 // async-signal safe way.
     50 void PrintSyscallError(uint32_t sysno) {
     51   if (sysno >= 1024)
     52     sysno = 0;
     53   // TODO(markus): replace with async-signal safe snprintf when available.
     54   const size_t kNumDigits = 4;
     55   char sysno_base10[kNumDigits];
     56   uint32_t rem = sysno;
     57   uint32_t mod = 0;
     58   for (int i = kNumDigits - 1; i >= 0; i--) {
     59     mod = rem % 10;
     60     rem /= 10;
     61     sysno_base10[i] = '0' + mod;
     62   }
     63   static const char kSeccompErrorPrefix[] =
     64       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_COMMON_CONTENT " in syscall ";
     65   static const char kSeccompErrorPostfix[] = "\n";
     66   WriteToStdErr(kSeccompErrorPrefix, sizeof(kSeccompErrorPrefix) - 1);
     67   WriteToStdErr(sysno_base10, sizeof(sysno_base10));
     68   WriteToStdErr(kSeccompErrorPostfix, sizeof(kSeccompErrorPostfix) - 1);
     69 }
     70 
     71 }  // namespace.
     72 
     73 namespace sandbox {
     74 
     75 intptr_t CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux) {
     76   uint32_t syscall = args.nr;
     77   if (syscall >= 1024)
     78     syscall = 0;
     79   PrintSyscallError(syscall);
     80 
     81   // Encode 8-bits of the 1st two arguments too, so we can discern which socket
     82   // type, which fcntl, ... etc., without being likely to hit a mapped
     83   // address.
     84   // Do not encode more bits here without thinking about increasing the
     85   // likelihood of collision with mapped pages.
     86   syscall |= ((args.args[0] & 0xffUL) << 12);
     87   syscall |= ((args.args[1] & 0xffUL) << 20);
     88   // Purposefully dereference the syscall as an address so it'll show up very
     89   // clearly and easily in crash dumps.
     90   volatile char* addr = reinterpret_cast<volatile char*>(syscall);
     91   *addr = '\0';
     92   // In case we hit a mapped address, hit the null page with just the syscall,
     93   // for paranoia.
     94   syscall &= 0xfffUL;
     95   addr = reinterpret_cast<volatile char*>(syscall);
     96   *addr = '\0';
     97   for (;;)
     98     _exit(1);
     99 }
    100 
    101 // TODO(jln): refactor the reporting functions.
    102 
    103 intptr_t SIGSYSCloneFailure(const struct arch_seccomp_data& args, void* aux) {
    104   static const char kSeccompCloneError[] =
    105       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_CLONE_CONTENT "\n";
    106   WriteToStdErr(kSeccompCloneError, sizeof(kSeccompCloneError) - 1);
    107   // "flags" is the first argument in the kernel's clone().
    108   // Mark as volatile to be able to find the value on the stack in a minidump.
    109   volatile uint64_t clone_flags = args.args[0];
    110   volatile char* addr;
    111   if (IsArchitectureX86_64()) {
    112     addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFFFFF);
    113     *addr = '\0';
    114   }
    115   // Hit the NULL page if this fails to fault.
    116   addr = reinterpret_cast<volatile char*>(clone_flags & 0xFFF);
    117   *addr = '\0';
    118   for (;;)
    119     _exit(1);
    120 }
    121 
    122 intptr_t SIGSYSPrctlFailure(const struct arch_seccomp_data& args,
    123                             void* /* aux */) {
    124   static const char kSeccompPrctlError[] =
    125       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_PRCTL_CONTENT "\n";
    126   WriteToStdErr(kSeccompPrctlError, sizeof(kSeccompPrctlError) - 1);
    127   // Mark as volatile to be able to find the value on the stack in a minidump.
    128   volatile uint64_t option = args.args[0];
    129   volatile char* addr =
    130       reinterpret_cast<volatile char*>(option & 0xFFF);
    131   *addr = '\0';
    132   for (;;)
    133     _exit(1);
    134 }
    135 
    136 intptr_t SIGSYSIoctlFailure(const struct arch_seccomp_data& args,
    137                             void* /* aux */) {
    138   static const char kSeccompIoctlError[] =
    139       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_IOCTL_CONTENT "\n";
    140   WriteToStdErr(kSeccompIoctlError, sizeof(kSeccompIoctlError) - 1);
    141   // Make "request" volatile so that we can see it on the stack in a minidump.
    142   volatile uint64_t request = args.args[1];
    143   volatile char* addr = reinterpret_cast<volatile char*>(request & 0xFFFF);
    144   *addr = '\0';
    145   // Hit the NULL page if this fails.
    146   addr = reinterpret_cast<volatile char*>(request & 0xFFF);
    147   *addr = '\0';
    148   for (;;)
    149     _exit(1);
    150 }
    151 
    152 intptr_t SIGSYSKillFailure(const struct arch_seccomp_data& args,
    153                            void* /* aux */) {
    154    static const char kSeccompKillError[] =
    155       __FILE__":**CRASHING**:" SECCOMP_MESSAGE_KILL_CONTENT "\n";
    156   WriteToStdErr(kSeccompKillError, sizeof(kSeccompKillError) - 1);
    157   // Make "request" volatile so that we can see it on the stack in a minidump.
    158   volatile uint64_t pid = args.args[0];
    159   volatile char* addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
    160   *addr = '\0';
    161   // Hit the NULL page if this fails.
    162   addr = reinterpret_cast<volatile char*>(pid & 0xFFF);
    163   *addr = '\0';
    164   for (;;)
    165     _exit(1);
    166 }
    167 
    168 intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
    169                             void* /* aux */) {
    170   static const char kSeccompFutexError[] =
    171       __FILE__ ":**CRASHING**:" SECCOMP_MESSAGE_FUTEX_CONTENT "\n";
    172   WriteToStdErr(kSeccompFutexError, sizeof(kSeccompFutexError) - 1);
    173   volatile int futex_op = args.args[1];
    174   volatile char* addr = reinterpret_cast<volatile char*>(futex_op & 0xFFF);
    175   *addr = '\0';
    176   for (;;)
    177     _exit(1);
    178 }
    179 
    180 const char* GetErrorMessageContentForTests() {
    181   return SECCOMP_MESSAGE_COMMON_CONTENT;
    182 }
    183 
    184 const char* GetCloneErrorMessageContentForTests() {
    185   return SECCOMP_MESSAGE_CLONE_CONTENT;
    186 }
    187 
    188 const char* GetPrctlErrorMessageContentForTests() {
    189   return SECCOMP_MESSAGE_PRCTL_CONTENT;
    190 }
    191 
    192 const char* GetIoctlErrorMessageContentForTests() {
    193   return SECCOMP_MESSAGE_IOCTL_CONTENT;
    194 }
    195 
    196 const char* GetKillErrorMessageContentForTests() {
    197   return SECCOMP_MESSAGE_KILL_CONTENT;
    198 }
    199 
    200 const char* GetFutexErrorMessageContentForTests() {
    201   return SECCOMP_MESSAGE_FUTEX_CONTENT;
    202 }
    203 
    204 }  // namespace sandbox.
    205