Example #1
0
static struct Gio *NaClLogGioFromFileIoBuffer(FILE *log_iob) {
  struct GioFile *log_gio;

  log_gio = malloc(sizeof *log_gio);
  if (NULL == log_gio) {
    perror("NaClLogSetFile");
    fprintf(stderr, "No memory for log buffers\n");
    NaClAbort();
  }
  if (!GioFileRefCtor(log_gio, log_iob)) {
    fprintf(stderr, "NaClLog module internal error: GioFileRefCtor failed\n");
    NaClAbort();
  }
  return (struct Gio *) log_gio;
}
Example #2
0
static FILE *NaClLogFileIoBufferFromFile(char const *log_file) {
  int   log_desc;
  FILE  *log_iob;

  log_desc = open(log_file, O_WRONLY | O_APPEND | O_CREAT, 0777);
  if (-1 == log_desc) {
    perror("NaClLogSetFile");
    fprintf(stderr, "Could not create log file\n");
    NaClAbort();
  }

  log_iob = FDOPEN(log_desc, "a");
  if (NULL == log_iob) {
    perror("NaClLogSetFile");
    fprintf(stderr, "Could not fdopen log stream\n");
    NaClAbort();
  }
  return log_iob;
}
Example #3
0
static void HandleSuspendSignal(struct NaClSignalContext *regs) {
  uint32_t tls_idx = NaClTlsGetIdx();
  struct NaClAppThread *natp = nacl_thread[tls_idx];
  struct NaClSignalContext *suspended_registers =
      &natp->suspended_registers->context;

  /* Sanity check. */
  if (natp->suspend_state != (NACL_APP_THREAD_UNTRUSTED |
                              NACL_APP_THREAD_SUSPENDING)) {
    NaClSignalErrorMessage("HandleSuspendSignal: "
                           "Unexpected suspend_state\n");
    NaClAbort();
  }

  if (suspended_registers != NULL) {
    *suspended_registers = *regs;
    /*
     * Ensure that the change to natp->suspend_state does not become
     * visible before the change to natp->suspended_registers.
     */
    NaClWriteMemoryBarrier();
  }

  /*
   * Indicate that we have suspended by setting
   * NACL_APP_THREAD_SUSPENDED.  We should not need an atomic
   * operation for this since the calling thread will not be trying to
   * change suspend_state.
   */
  natp->suspend_state |= NACL_APP_THREAD_SUSPENDED;
  FutexWake(&natp->suspend_state, 1);

  /* Wait until we are asked to resume. */
  while (1) {
    Atomic32 state = natp->suspend_state;
    if ((state & NACL_APP_THREAD_SUSPENDED) != 0) {
      FutexWait(&natp->suspend_state, state);
      continue;  /* Retry */
    }
    break;
  }
  /*
   * Apply register modifications.  We need to use a snapshot of
   * natp->suspended_registers because, since we were asked to resume,
   * we could have been asked to suspend again, and
   * suspended_registers could have been allocated in the new
   * suspension request but not in the original suspension request.
   */
  if (suspended_registers != NULL) {
    *regs = *suspended_registers;
  }
}
Example #4
0
void NaClLogUnlock(void) {
  int run_abort_behavior = 0;
  switch (g_abort_count) {
    case 0:
      NaClXMutexUnlock(&log_mu);
      break;
    case 1:
      /*
       * include an easy-to-recognize output for the fuzzer to recognize
       */
      if (!g_abort_behavior_active) {
        NaClLog_mu(LOG_ERROR, "LOG_FATAL abort exit\n");
        g_abort_behavior_active = 1;
        run_abort_behavior = 1;
        /*
         * run abort behavior only on edge transition when
         * g_abort_behavior_active is first set.
         */
      }
      NaClXMutexUnlock(&log_mu);
      if (run_abort_behavior) {
#ifdef __COVERITY__
        NaClAbort();  /* help coverity figure out that this is the default */
#else
        NaClLogRunAbortBehavior();
#endif
        /* The abort behavior hook may not abort, so abort here in case. */
        NaClAbort();
      }
      break;
    default:
      /*
       * Abort handling code in turn aborted.  Eeep!
       */
      NaClAbort();
      break;
  }
}
Example #5
0
static void HandleUntrustedFault(int signal,
                                 struct NaClSignalContext *regs,
                                 struct NaClAppThread *natp) {
  /* Sanity check. */
  if ((natp->suspend_state & NACL_APP_THREAD_UNTRUSTED) == 0) {
    NaClSignalErrorMessage("HandleUntrustedFault: Unexpected suspend_state\n");
    NaClAbort();
  }

  /* Notify the debug stub by marking this thread as faulted. */
  natp->fault_signal = signal;
  AtomicIncrement(&natp->nap->faulted_thread_count, 1);

  /*
   * We now expect the debug stub to suspend this thread via the
   * thread suspension API.  This will allow the debug stub to get the
   * register state at the point the fault happened.  The debug stub
   * will be able to modify the register state before unblocking the
   * thread using NaClAppThreadUnblockIfFaulted().
   */
  do {
    int new_signal;
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, NACL_THREAD_SUSPEND_SIGNAL);
    if (sigwait(&sigset, &new_signal) != 0) {
      NaClSignalErrorMessage("HandleUntrustedFault: sigwait() failed\n");
      NaClAbort();
    }
    if (new_signal != NACL_THREAD_SUSPEND_SIGNAL) {
      NaClSignalErrorMessage("HandleUntrustedFault: "
                             "sigwait() returned unexpected result\n");
      NaClAbort();
    }
    HandleSuspendSignal(regs);
  } while (natp->fault_signal != 0);
}
void NaClErrorLogHookInit(void (*hook)(void *state,
                                       char *buf,
                                       size_t buf_bytes),
                          void *state) {
  NaClLog(2, "NaClErrorLogHookInit: entered\n");
  if (!NaClErrorGioCtor(&g_NaCl_log_gio, NaClLogGetGio())) {
    fprintf(stderr, "sel_main_chrome: log reporting setup failed\n");
    NaClAbort();
  }

  g_NaCl_log_abort_fn = hook;
  g_NaCl_log_abort_state = state;

  NaClLogSetGio((struct Gio *) &g_NaCl_log_gio);

  NaClLogSetAbortBehavior(NaClReportLogMessages);
}
Example #7
0
/*
 * d'b: make syscall invoked from the untrusted code
 */
NORETURN void NaClSyscallCSegHook()
{
  struct NaClApp            *nap;
  struct NaClThreadContext  *user;
  uintptr_t                 tramp_ret;
  nacl_reg_t                user_ret;
  size_t                    sysnum;
  uintptr_t                 sp_user;
  uintptr_t                 sp_sys;

  /*
   * d'b: nexe just invoked some syscall. stop cpu time counting
   * increase syscalls counter (correction for setup call will be
   * corrected later). small mallocs and other calls which are
   * not really "system" will be accounted anyway!
   */
  nap = gnap; /* restore NaClApp object */
  nap->user_side_flag = 1; /* set "user side call" mark */
  PauseCpuClock(nap);
  AccountingSyscallsInc(nap);
  user = nacl_user; /* restore from global */
  sp_user = NaClGetThreadCtxSp(user);

  sp_sys = NaClUserToSysStackAddr(nap, sp_user);

  /*
   * sp_sys points to the top of user stack where there is a retaddr to
   * trampoline slot
   */
  tramp_ret = *(uintptr_t *)sp_sys;
  tramp_ret = NaClUserToSysStackAddr(nap, tramp_ret);

  sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR))
      >> NACL_SYSCALL_BLOCK_SHIFT;

  /*
   * getting user return address (the address where we need to return after
   * system call) from the user stack. (see stack layout above)
   */
  user_ret = *(uintptr_t *) (sp_sys + NACL_USERRET_FIX);

  /*
   * Fix the user stack, throw away return addresses from the top of the stack.
   * After this fix, the first argument to a system call must be on the top of
   * the user stack (see user stack layout above)
   */
  sp_sys += NACL_SYSARGS_FIX;
  sp_user += NACL_SYSCALLRET_FIX;
  NaClSetThreadCtxSp(user, sp_user);

  /* debug print to log */
  NaClLog(4, "system call number %"NACL_PRIdS"\n", sysnum);

  if (sysnum >= NACL_MAX_SYSCALLS) {
    NaClLog(2, "INVALID system call %"NACL_PRIdS"\n", sysnum);
    nap->sysret = -NACL_ABI_EINVAL;
  } else {
    /*
     * syscall_args is used by Decoder functions in
     * nacl_syscall_handlers.c which is automatically generated file
     * and placed in the
     * scons-out/.../gen/src/service_runtime/
     * directory.  syscall_args must point to the first argument of a
     * system call. System call arguments are placed on the untrusted
     * user stack.
     */
    nap->syscall_args = (uintptr_t *) sp_sys;
    nap->sysret = (*(nap->syscall_table[sysnum].handler))(nap);
  }

  /*
   * before switching back to user module, we need to make sure that the
   * user_ret is properly sandboxed.
   */
  user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t)user_ret);

  /* d'b: give control to the nexe. start cpu time counting */
  ResumeCpuClock(nap);
  nap->user_side_flag = 0; /* remove "user side call" mark */
  NaClSwitchToApp(nap, user_ret);

  /* NOTREACHED */
  fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n");
  NaClAbort();
}
NORETURN void NaClSyscallCSegHook(int32_t tls_idx) {
  struct NaClAppThread      *natp;
  struct NaClApp            *nap;
  uintptr_t                 tramp_ret;
  size_t                    sysnum;
  uintptr_t                 sp_user;
  uint32_t                  sysret;

  /*
   * Mark the thread as running on a trusted stack as soon as possible
   * so that we can report any crashes that occur after this point.
   */
  NaClStackSafetyNowOnTrustedStack();

  natp = nacl_thread[tls_idx];

  HandleStackContext(natp, &tramp_ret, &sp_user);

  /*
   * Before this call, the thread could be suspended, so we should not
   * lock any mutexes before this, otherwise it could cause a
   * deadlock.
   */
  NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_UNTRUSTED,
                               NACL_APP_THREAD_TRUSTED);

  nap = natp->nap;

  NaClLog(4, "Entered NaClSyscallCSegHook\n");
  NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user);

  NaClCopyInTakeLock(nap);
  /*
   * held until syscall args are copied, which occurs in the generated
   * code.
   */

  sysnum = (tramp_ret - (nap->mem_start + NACL_SYSCALL_START_ADDR))
      >> NACL_SYSCALL_BLOCK_SHIFT;

  NaClLog(4, "system call %"NACL_PRIuS"\n", sysnum);

  /*
   * usr_syscall_args is used by Decoder functions in
   * nacl_syscall_handlers.c which is automatically generated file and
   * placed in the
   * scons-out/.../gen/native_client/src/trusted/service_runtime/
   * directory.  usr_syscall_args must point to the first argument of
   * a system call. System call arguments are placed on the untrusted
   * user stack.
   *
   * We save the user address for user syscall arguments fetching and
   * for VM range locking.
   */
  natp->usr_syscall_args = NaClRawUserStackAddrNormalize(sp_user +
                                                         NACL_SYSARGS_FIX);

  if (sysnum >= NACL_MAX_SYSCALLS) {
    NaClLog(2, "INVALID system call %"NACL_PRIdS"\n", sysnum);
    sysret = -NACL_ABI_EINVAL;
    NaClCopyInDropLock(nap);
  } else {
    NaClLog(4, "making system call %"NACL_PRIdS", "
            "handler 0x%08"NACL_PRIxPTR"\n",
            sysnum, (uintptr_t) nap->syscall_table[sysnum].handler);
    sysret = (*(nap->syscall_table[sysnum].handler))(natp);
    /* Implicitly drops lock */
  }
  NaClLog(4,
          ("returning from system call %"NACL_PRIdS", return value %"NACL_PRId32
           " (0x%"NACL_PRIx32")\n"),
          sysnum, sysret, sysret);
  natp->user.sysret = sysret;

  NaClLog(4, "return target 0x%08"NACL_PRIxNACL_REG"\n",
          natp->user.new_prog_ctr);
  NaClLog(4, "user sp %"NACL_PRIxPTR"\n", sp_user);

  /*
   * After this NaClAppThreadSetSuspendState() call, we should not
   * claim any mutexes, otherwise we risk deadlock.  Note that if
   * NACLVERBOSITY is set high enough to enable the NaClLog() calls in
   * NaClSwitchToApp(), these calls could deadlock.
   */
  NaClAppThreadSetSuspendState(natp, NACL_APP_THREAD_TRUSTED,
                               NACL_APP_THREAD_UNTRUSTED);
  NaClStackSafetyNowOnUntrustedStack();

  NaClSwitchToApp(natp);
  /* NOTREACHED */

  fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n");
  NaClAbort();
}