LCOV - code coverage report
Current view: top level - src/trap-handler - handler-inside-posix.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 21 23 91.3 %
Date: 2019-01-20 Functions: 2 3 66.7 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project 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             : // PLEASE READ BEFORE CHANGING THIS FILE!
       6             : //
       7             : // This file implements the out of bounds signal handler for
       8             : // WebAssembly. Signal handlers are notoriously difficult to get
       9             : // right, and getting it wrong can lead to security
      10             : // vulnerabilities. In order to minimize this risk, here are some
      11             : // rules to follow.
      12             : //
      13             : // 1. Do not introduce any new external dependencies. This file needs
      14             : //    to be self contained so it is easy to audit everything that a
      15             : //    signal handler might do.
      16             : //
      17             : // 2. Any changes must be reviewed by someone from the crash reporting
      18             : //    or security team. See OWNERS for suggested reviewers.
      19             : //
      20             : // For more information, see https://goo.gl/yMeyUY.
      21             : //
      22             : // This file contains most of the code that actually runs in a signal handler
      23             : // context. Some additional code is used both inside and outside the signal
      24             : // handler. This code can be found in handler-shared.cc.
      25             : 
      26             : #include "src/trap-handler/handler-inside-posix.h"
      27             : 
      28             : #include <signal.h>
      29             : 
      30             : #ifdef V8_OS_LINUX
      31             : #include <ucontext.h>
      32             : #elif V8_OS_MACOSX
      33             : #include <sys/ucontext.h>
      34             : #endif
      35             : 
      36             : #include <stddef.h>
      37             : #include <stdlib.h>
      38             : 
      39             : #include "src/trap-handler/trap-handler-internal.h"
      40             : #include "src/trap-handler/trap-handler.h"
      41             : 
      42             : namespace v8 {
      43             : namespace internal {
      44             : namespace trap_handler {
      45             : 
      46           0 : bool IsKernelGeneratedSignal(siginfo_t* info) {
      47             :   // On macOS, only `info->si_code > 0` is relevant, because macOS leaves
      48             :   // si_code at its default of 0 for signals that don’t originate in hardware.
      49             :   // The other conditions are only relevant for Linux.
      50             :   return info->si_code > 0 && info->si_code != SI_USER &&
      51             :          info->si_code != SI_QUEUE && info->si_code != SI_TIMER &&
      52      155764 :          info->si_code != SI_ASYNCIO && info->si_code != SI_MESGQ;
      53             : }
      54             : 
      55             : class SigUnmaskStack {
      56             :  public:
      57             :   explicit SigUnmaskStack(sigset_t sigs) {
      58             :     // TODO(eholk): consider using linux-syscall-support for calling this
      59             :     // syscall.
      60      155759 :     pthread_sigmask(SIG_UNBLOCK, &sigs, &old_mask_);
      61             :   }
      62             : 
      63      155755 :   ~SigUnmaskStack() { pthread_sigmask(SIG_SETMASK, &old_mask_, nullptr); }
      64             : 
      65             :  private:
      66             :   sigset_t old_mask_;
      67             : 
      68             :   // We'd normally use DISALLOW_COPY_AND_ASSIGN, but we're avoiding a dependency
      69             :   // on base/macros.h
      70             :   SigUnmaskStack(const SigUnmaskStack&) = delete;
      71             :   void operator=(const SigUnmaskStack&) = delete;
      72             : };
      73             : 
      74      155765 : bool TryHandleSignal(int signum, siginfo_t* info, void* context) {
      75             :   // Ensure the faulting thread was actually running Wasm code. This should be
      76             :   // the first check in the trap handler to guarantee that the IsThreadInWasm
      77             :   // flag is only set in wasm code. Otherwise a later signal handler is executed
      78             :   // with the flag set.
      79      155765 :   if (!IsThreadInWasm()) {
      80             :     return false;
      81             :   }
      82             : 
      83             :   // Clear g_thread_in_wasm_code, primarily to protect against nested faults.
      84      155760 :   g_thread_in_wasm_code = false;
      85             : 
      86             :   // Bail out early in case we got called for the wrong kind of signal.
      87             : 
      88      155760 :   if (signum != kOobSignal) {
      89             :     return false;
      90             :   }
      91             : 
      92             :   // Make sure the signal was generated by the kernel and not some other source.
      93      155759 :   if (!IsKernelGeneratedSignal(info)) {
      94             :     return false;
      95             :   }
      96             : 
      97             :   // Begin signal mask scope. We need to be sure to restore the signal mask
      98             :   // before we restore the g_thread_in_wasm_code flag.
      99             :   {
     100             :     // Unmask the signal so that if this signal handler crashes, the crash will
     101             :     // be handled by the crash reporter.  Otherwise, the process might be killed
     102             :     // with the crash going unreported.
     103             :     sigset_t sigs;
     104             :     // Fortunately, sigemptyset and sigaddset are async-signal-safe according to
     105             :     // the POSIX standard.
     106      155759 :     sigemptyset(&sigs);
     107      155759 :     sigaddset(&sigs, SIGSEGV);
     108             :     SigUnmaskStack unmask(sigs);
     109             : 
     110             :     ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
     111             : #if V8_OS_LINUX
     112             :     auto* context_rip = &uc->uc_mcontext.gregs[REG_RIP];
     113             : #elif V8_OS_MACOSX
     114             :     auto* context_rip = &uc->uc_mcontext->__ss.__rip;
     115             : #else
     116             : #error Unsupported platform
     117             : #endif
     118      155759 :     uintptr_t fault_addr = *context_rip;
     119      155759 :     uintptr_t landing_pad = 0;
     120      155759 :     if (TryFindLandingPad(fault_addr, &landing_pad)) {
     121             :       // Tell the caller to return to the landing pad.
     122      155755 :       *context_rip = landing_pad;
     123             :       // We will return to wasm code, so restore the g_thread_in_wasm_code flag.
     124      155755 :       g_thread_in_wasm_code = true;
     125             :       return true;
     126             :     }
     127             :   }  // end signal mask scope
     128             : 
     129             :   // If we get here, it's not a recoverable wasm fault, so we go to the next
     130             :   // handler. Leave the g_thread_in_wasm_code flag unset since we do not return
     131             :   // to wasm code.
     132           4 :   return false;
     133             : }
     134             : 
     135      155758 : void HandleSignal(int signum, siginfo_t* info, void* context) {
     136      155758 :   if (!TryHandleSignal(signum, info, context)) {
     137             :     // Since V8 didn't handle this signal, we want to re-raise the same signal.
     138             :     // For kernel-generated SEGV signals, we do this by restoring the original
     139             :     // SEGV handler and then returning. The fault will happen again and the
     140             :     // usual SEGV handling will happen.
     141             :     //
     142             :     // We handle user-generated signals by calling raise() instead. This is for
     143             :     // completeness. We should never actually see one of these, but just in
     144             :     // case, we do the right thing.
     145           5 :     RemoveTrapHandler();
     146           5 :     if (!IsKernelGeneratedSignal(info)) {
     147           0 :       raise(signum);
     148             :     }
     149             :   }
     150             :   // TryHandleSignal modifies context to change where we return to.
     151      155758 : }
     152             : 
     153             : }  // namespace trap_handler
     154             : }  // namespace internal
     155             : }  // namespace v8

Generated by: LCOV version 1.10