Beispiel #1
0
/* serve trap invoked from the untrusted code */
NORETURN void SyscallHook()
{
  struct NaClApp *nap;
  struct ThreadContext *user;
  uintptr_t tramp_ret;
  nacl_reg_t user_ret;
  size_t sysnum;
  uintptr_t sp_user;
  uintptr_t sp_sys;

  /* restore trusted side environment */
  nap = gnap; /* restore NaClApp object */
  user = nacl_user;
  sp_user = GetThreadCtxSp(user);
  sp_sys = 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;
  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;
  SetThreadCtxSp(user, sp_user);

  /* fail if nacl syscall received */
  ZLOGFAIL(sysnum != 0, EINVAL, "nacl syscall #%d received", sysnum);

  /*
   * syscall_args must point to the first argument of a system call.
   * System call arguments are placed on the untrusted user stack.
   */
  nap->sysret = TrapHandler(nap, *(uint32_t*)sp_sys);

  /*
   * 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 user side */
  SwitchToApp(nap, user_ret);
  ZLOGFAIL(1, EFAULT, "the unreachable has been reached");
}
/*
 * HandleStackContext() fetches some of the inputs to the NaCl syscall
 * from the untrusted stack.  It updates NaClThreadContext so that the
 * saved state will be complete in case this state is read via the
 * thread suspension API.
 *
 * This is called while natp->suspend_state is set to
 * NACL_APP_THREAD_UNTRUSTED, which has two consequences:
 *
 *  1) We may read untrusted address space without calling
 *     NaClCopyInTakeLock() first, because this function's execution
 *     will be suspended while any mmap hole is opened up on Windows.
 *
 *  2) We may not claim any locks.  This means we may not call
 *     NaClLog().  (An exception is that LOG_FATAL calls to NaClLog()
 *     should be okay for internal errors.)
 */
static void HandleStackContext(struct NaClAppThread *natp,
                               uintptr_t            *tramp_ret_out,
                               uintptr_t            *sp_user_out) {
  struct NaClApp *nap = natp->nap;
  uintptr_t      sp_user;
  uintptr_t      sp_sys;
  uintptr_t      tramp_ret;
  nacl_reg_t     user_ret;

  /*
   * sp_sys points to the top of the user stack where return addresses
   * and syscall arguments are stored.
   *
   * Note that on x86-64, NaClUserToSysStackAddr() and
   * NaClSysToUserStackAddr() do no range check.  sp_user must be okay
   * for control to have reached here, because nacl_syscall*.S writes
   * to the stack.
   */
  sp_user = NaClGetThreadCtxSp(&natp->user);
  sp_sys = NaClUserToSysStackAddr(nap, sp_user);
  /*
   * Get the trampoline return address.  This just tells us which
   * trampoline was called (and hence the syscall number); we never
   * return to the trampoline.
   */
  tramp_ret = *(uintptr_t *) (sp_sys + NACL_TRAMPRET_FIX);
  tramp_ret = NaClUserToSysStackAddr(nap, tramp_ret);
  /*
   * Get the user return address (where we return to after the system
   * call).  We must ensure the address is properly sandboxed before
   * switching back to untrusted code.
   */
  user_ret = *(uintptr_t *) (sp_sys + NACL_USERRET_FIX);
  user_ret = (nacl_reg_t) NaClSandboxCodeAddr(nap, (uintptr_t) user_ret);
  natp->user.new_prog_ctr = user_ret;

  *tramp_ret_out = tramp_ret;
  *sp_user_out = sp_user;
}
Beispiel #3
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();
}