Ejemplo n.º 1
0
NORETURN void CreateSession(struct NaClApp *nap)
{
  uintptr_t stack_ptr;

  assert(nap != NULL);

  /* set up user stack */
  stack_ptr = nap->mem_start + ((uintptr_t)1U << nap->addr_bits);
  stack_ptr -= STACK_USER_DATA_SIZE;
  memset((void*)stack_ptr, 0, STACK_USER_DATA_SIZE);
  ((uint32_t*)stack_ptr)[4] = 1;
  ((uint32_t*)stack_ptr)[5] = 0xfffffff0;

  /* construct "nacl_user" global */
  ThreadContextCtor(nacl_user, nap, nap->initial_entry_pt, stack_ptr, 0);
  nacl_user->sysret = nap->break_addr;
  nacl_user->prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt);
  nacl_user->new_prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt);

  /* initialize "nacl_sys" global */
  nacl_sys->rbp = GetStackPtr();
  nacl_sys->rsp = GetStackPtr();

  /* pass control to the user side */
  ZLOGS(LOG_DEBUG, "SESSION %d STARTED", nap->manifest->node);
  SwitchToApp(nap, nacl_user->new_prog_ctr);
  ZLOGFAIL(1, EFAULT, "the unreachable has been reached");
}
Ejemplo n.º 2
0
/*
 * d'b: alternative mechanism to pass control to user side
 * note: initializes "nacl_user" global
 */
NORETURN void SwitchToApp(struct NaClApp  *nap, uintptr_t stack_ptr)
{
  /* initialize "nacl_user" global */
  if(!nacl_user) nacl_user = malloc(sizeof(*nacl_user));
  assert(nacl_user != NULL);

  /* construct "nacl_user" global */
  NaClThreadContextCtor(nacl_user, nap, nap->initial_entry_pt,
                        NaClSysToUserStackAddr(nap, stack_ptr), 0);
  assert(NaClSignalStackAllocate(&nap->signal_stack));
  nacl_user->sysret = nap->break_addr;
  nacl_user->prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt);
  nacl_user->new_prog_ctr = NaClUserToSys(nap, nap->initial_entry_pt);

  /* initialize "nacl_sys" global */
  if(!nacl_sys) nacl_sys = malloc(sizeof(*nacl_sys));
  assert(nacl_sys != NULL);
  nacl_sys->rbp = NaClGetStackPtr();
  nacl_sys->rsp = NaClGetStackPtr();

  /* set global nap to current nap object */
  gnap = nap;

  /*
   * todo: put here switch to chose proper function: avx or sse
   */
  NaClSwitchSSE(nacl_user);

  /* unreachable */
}
Ejemplo n.º 3
0
Archivo: trap.c Proyecto: hxr/zerovm
/*
 * validate and set syscallback (both local and global)
 * return 0 if syscallback installed, otherwise -1
 *
 * update: please note, syscallback is same far jump. so it
 * must be tested the same way. we cannot use validator and to
 * prevent potential danger the code below must be *very* safe
 * and must check all possibilities.
 */
static int32_t UpdateSyscallback(struct NaClApp *nap, struct SetupList *hint)
{
  int32_t addr = hint->syscallback;
  int32_t retcode = ERR_CODE;
  syscallback = 0;
  nap->manifest->user_setup->syscallback = 0;

  if(!addr) return OK_CODE; /* user wants to uninstall syscallback */

#define OP_ALIGNEMENT 0x20

  /* check alignement */
  if(addr & (OP_ALIGNEMENT - 1)) return ERR_CODE;

  /* seek syscallback in static text (aware of right border proximity) */
  if(addr >= nap->dynamic_text_start && addr < nap->dynamic_text_end)
    retcode = OK_CODE;

  /* seek placement in dynamic text (aware of right border proximity) */
  if(addr >= NACL_TRAMPOLINE_END && addr < nap->static_text_end)
    retcode = OK_CODE;

  /* set the new syscallback if found in the proper place */
  if(retcode == OK_CODE)
  {
    nap->manifest->user_setup->syscallback = addr;
    syscallback = NaClUserToSys(nap, (intptr_t) addr);
  }

  return retcode;
}
Ejemplo n.º 4
0
int main(int argc, char **argv) {
  struct NaClApp app;
  struct NaClApp *nap = &app;
  struct NaClSyscallTableEntry syscall_table[NACL_MAX_SYSCALLS] = {{0}};
  int index;
  int use_separate_thread = 0;


  for (index = 0; index < NACL_MAX_SYSCALLS; index++) {
    syscall_table[index].handler = NotImplementedDecoder;
  }
  syscall_table[TEST_SYSCALL_INVOKE].handler = MySyscallInvoke;
  syscall_table[TEST_SYSCALL_EXIT].handler = MySyscallExit;

  NaClAllModulesInit();

  CHECK(NaClAppWithSyscallTableCtor(&app, syscall_table));
  CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK);

      struct NaClAppThread *natp;
    uintptr_t stack_ptr = NaClGetInitialStackTop(nap);
    /* Ensure the stack pointer is suitably aligned. */
    stack_ptr &= ~NACL_STACK_ALIGN_MASK;
    stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
    /* TODO(mseaborn): Make this interface more straightforward to use. */
    stack_ptr = NaClSysToUserStackAddr(nap, NaClUserToSys(nap, stack_ptr));

    natp = NaClAppThreadMake(nap, nap->initial_entry_pt, stack_ptr, 0, 0);
    CHECK(natp != NULL);
    NaClAppThreadLauncher(natp);
 
  printf("game over\n");
  return 1;
}
Ejemplo n.º 5
0
/*
 * set syscallback
 * returns a new syscallback when successfully installed or
 * returns an old syscallback if installation failed
 * note: global syscallback uses system address space,
 *       nap->system_manifest->syscallback - user space
 */
static int32_t ZVMSyscallback(struct NaClApp *nap, int32_t addr)
{
  int32_t good_pos = 0;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);

  /* uninstall syscallback if 0 given */
  if(addr == 0)
  {
    syscallback = 0; /* global variable */
    nap->system_manifest->syscallback = 0;
    return 0;
  }

  /* check alignement */
  if(addr & (OP_ALIGNEMENT - 1))
    return nap->system_manifest->syscallback;

  /* check if syscallback points to text */
  good_pos |= addr >= NACL_TRAMPOLINE_END && addr < nap->static_text_end;
  good_pos |= addr >= nap->dynamic_text_start && addr < nap->dynamic_text_end;

  if(good_pos)
  {
    nap->system_manifest->syscallback = addr;
    syscallback = NaClUserToSys(nap, (intptr_t) addr);
  }

  return nap->system_manifest->syscallback;
}
Ejemplo n.º 6
0
/* set pointer to user manifest */
static void SetUserManifestPtr(struct NaClApp *nap, void *mft)
{
  uintptr_t *p;

  p = (void*)NaClUserToSys(nap, FOURGIG - nap->stack_size - USER_PTR_SIZE);
  *p = NaClSysToUser(nap, (uintptr_t)mft);
}
Ejemplo n.º 7
0
/* preallocate memory area of given size. abort if fail */
static void PreallocateUserMemory(struct NaClApp *nap)
{
  uintptr_t i;
  int64_t heap;
  void *p;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);

  /* quit function if max_mem is not specified or invalid */
  ZLOGFAIL(nap->heap_end == 0 || nap->heap_end > FOURGIG,
      ENOMEM, "invalid memory size");

  /* calculate user heap size (must be allocated next to the data_end) */
  p = (void*)NaClRoundAllocPage(nap->data_end);
  heap = nap->heap_end - nap->stack_size;
  heap = NaClRoundAllocPage(heap) - NaClRoundAllocPage(nap->data_end);
  ZLOGFAIL(heap <= LEAST_USER_HEAP_SIZE, ENOMEM, "user heap size is too small");

  /* since 4gb of user space is already allocated just set protection to the heap */
  p = (void*)NaClUserToSys(nap, (uintptr_t)p);
  i = NaCl_mprotect(p, heap, PROT_READ | PROT_WRITE);
  ZLOGFAIL(0 != i, -i, "cannot set protection on user heap");
  nap->heap_end = NaClSysToUser(nap, (uintptr_t)p + heap);

  nap->mem_map[HeapIdx].size += heap;
  nap->mem_map[HeapIdx].end += heap;
}
Ejemplo n.º 8
0
Archivo: trap.c Proyecto: hxr/zerovm
/* ### move to documentation or rewrite
 * supported three functions:
 * ZVMSetup(char *hint, char answer[])
 * TrapRead(int32_t buffer, int32_t size, int64_t offset)
 * TrapWrite(int32_t buffer, int32_t size, int64_t offset)
 *
 * "args" is an array of syscall name and its arguments:
 * FunctionName(arg1,arg2,..) where arg1/2/3 are values/pointers
 * note: since nacl spoils 1st two arguments if they are pointers, arg[1] are not used
 */
int32_t TrapHandler(struct NaClApp *nap, uint32_t args)
{
  uint64_t *sys_args;
  int retcode = 0;

  /* translate address from user space to system. note: cannot set "trap error" */
  if(!nap->manifest) return -1; /* return error if not manifest found */
  sys_args = (uint64_t*)NaClUserToSys(nap, (uintptr_t) args);
  NaClLog(4, "NaClSysNanosleep received in = 0x%lx\n", (intptr_t)sys_args);

  switch(*sys_args)
  {
    case TrapExit:
      retcode = TrapExitHandle(nap, (int32_t) sys_args[2]);
      break;
    case TrapUserSetup:
      retcode = TrapUserSetupHandle(nap, (struct SetupList*) sys_args[2]);
      break;
    case TrapRead:
      retcode = TrapReadHandle(nap,
          (enum ChannelType)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]);
      break;
    case TrapWrite:
      retcode = TrapWriteHandle(nap,
          (enum ChannelType)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]);
      break;
    default:
      retcode = ERR_CODE;
      NaClLog(LOG_ERROR, "function %ld is not supported\n", *sys_args);
      break;
  }

  return retcode;
}
Ejemplo n.º 9
0
int NaClThreadContextCtor(struct NaClThreadContext  *ntcp,
                          struct NaClApp            *nap,
                          nacl_reg_t                prog_ctr,
                          nacl_reg_t                stack_ptr,
                          uint32_t                  tls_idx) {
  ntcp->rax = 0;
  ntcp->rbx = 0;
  ntcp->rcx = 0;
  ntcp->rdx = 0;

  ntcp->rbp = stack_ptr;  /* must be a valid stack addr! */
  ntcp->rsi = 0;
  ntcp->rdi = 0;
  ntcp->rsp = stack_ptr;

  ntcp->r8 = 0;
  ntcp->r9 = 0;
  ntcp->r10 = 0;
  ntcp->r11 = 0;

  ntcp->r12 = 0;
  ntcp->r13 = 0;
  ntcp->r14 = 0;
  ntcp->r15 = nap->mem_start;

  ntcp->prog_ctr = NaClUserToSys(nap, prog_ctr);
  ntcp->new_prog_ctr = 0;
  ntcp->sysret = -NACL_ABI_EINVAL;

  ntcp->tls_base = NULL;
  ntcp->tls_idx = tls_idx;

  return 1;
}
Ejemplo n.º 10
0
static void MakeDynamicCodePagesVisible(struct NaClApp *nap,
                                        uint32_t page_index_min,
                                        uint32_t page_index_max,
                                        uint8_t *writable_addr) {
  void *user_addr;
  uint32_t index;
  size_t size = (page_index_max - page_index_min) * NACL_MAP_PAGESIZE;

  for (index = page_index_min; index < page_index_max; index++) {
    CHECK(!BitmapIsBitSet(nap->dynamic_page_bitmap, index));
    BitmapSetBit(nap->dynamic_page_bitmap, index);
  }
  user_addr = (void *) NaClUserToSys(nap, nap->dynamic_text_start
                                     + page_index_min * NACL_MAP_PAGESIZE);

#if NACL_WINDOWS
  NaClUntrustedThreadsSuspendAll(nap, /* save_registers= */ 0);

  /*
   * The VirtualAlloc() call here has two effects:
   *
   *  1) It commits the page in the shared memory (SHM) object,
   *     allocating swap space and making the page accessible.  This
   *     affects our writable mapping of the shared memory object too.
   *     Before the VirtualAlloc() call, dereferencing writable_addr
   *     would fault.
   *  2) It changes the page permissions of the mapping to
   *     read+execute.  Since this exposes the page in its unsafe,
   *     non-HLT-filled state, this must be done with untrusted
   *     threads suspended.
   */
  {
    uintptr_t offset;
    for (offset = 0; offset < size; offset += NACL_MAP_PAGESIZE) {
      void *user_page_addr = (char *) user_addr + offset;
      if (VirtualAlloc(user_page_addr, NACL_MAP_PAGESIZE,
                       MEM_COMMIT, PAGE_EXECUTE_READ) != user_page_addr) {
        NaClLog(LOG_FATAL, "MakeDynamicCodePagesVisible: "
                "VirtualAlloc() failed -- probably out of swap space\n");
      }
    }
  }
#endif

  /* Sanity check:  Ensure the page is not already in use. */
  CHECK(*writable_addr == 0);

  NaClFillMemoryRegionWithHalt(writable_addr, size);

#if NACL_WINDOWS
  NaClUntrustedThreadsResumeAll(nap);
#else
  if (NaClMprotect(user_addr, size, PROT_READ | PROT_EXEC) != 0) {
    NaClLog(LOG_FATAL, "MakeDynamicCodePageVisible: NaClMprotect() failed\n");
  }
#endif
}
Ejemplo n.º 11
0
/*
 * read specified amount of bytes from given desc/offset to buffer
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMReadHandle(struct NaClApp *nap,
    int ch, char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  char *sys_buffer;

  assert(nap != NULL);
  assert(nap->manifest != NULL);
  assert(nap->manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->manifest->channels->len)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld",
        ch, buffer, size, offset);
    return -EINVAL;
  }
  channel = CH_CH(nap->manifest, ch);
  ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld",
      channel->alias, buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_WRITE) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t)buffer);

  /* ignore user offset for sequential access read */
  if(CH_SEQ_READABLE(channel))
    offset = channel->getpos;
  else
  /* prevent reading beyond the end of the random access channels */
    size = MIN(channel->size - offset, size);

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check for eof */
  if(channel->eof) return 0;

  /* check limits */
  if(channel->counters[GetsLimit] >= channel->limits[GetsLimit])
    return -EDQUOT;
  if(CH_RND_READABLE(channel))
    if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]
      + channel->size) return -EINVAL;

  /* calculate i/o leftovers */
  tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit];
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* read data */
  return ChannelRead(channel, sys_buffer, (size_t)size, (off_t)offset);
}
Ejemplo n.º 12
0
Archivo: trap.c Proyecto: Abioy/zerovm
int32_t TrapHandler(struct NaClApp *nap, uint32_t args)
{
  uint64_t *sargs;
  int retcode = 0;
  int i;

  assert(nap != NULL);
  assert(nap->manifest != NULL);

  /*
   * translate address from user space to system
   * note: cannot set "trap error"
   */
  sargs = (uint64_t*)NaClUserToSys(nap, (uintptr_t)args);
  i = FunctionIndexById(*sargs);
  ZLOGS(LOG_DEBUG, "%s called", function[i]);
  ZTrace("untrusted code");

  switch(*sargs)
  {
    case TrapFork:
      if(Daemon(nap) == 0)
      {
        SyscallZTrace(5, function[5]);
        ZVMExitHandle(nap, 0);
      }
      break;
    case TrapExit:
      ZVMExitHandle(nap, (int32_t)sargs[2]);
      break;
    case TrapRead:
      retcode = ZVMReadHandle(nap,
          (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]);
      break;
    case TrapWrite:
      retcode = ZVMWriteHandle(nap,
          (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]);
      break;
    case TrapJail:
      retcode = ZVMJailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]);
      break;
    case TrapUnjail:
      retcode = ZVMUnjailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]);
      break;
    default:
      retcode = -EPERM;
      ZLOG(LOG_ERROR, "function %ld is not supported", *sargs);
      break;
  }

  /* report, ztrace and return */
  FastReport();
  ZLOGS(LOG_DEBUG, "%s returned %d", function[i], retcode);
  SyscallZTrace(i, function[i], sargs[2], sargs[3], sargs[4], sargs[5], retcode);
  return retcode;
}
Ejemplo n.º 13
0
/*
 * "One Ring" syscall main routine. the nacl syscalls replacement.
 * "args" is an array of syscall name and its arguments
 * note: since nacl patch two 1st arguments if they are pointers, arg[1] are not used
 * todo(d'b): check how nacl decide to patch arguments.
 */
int32_t TrapHandler(struct NaClApp *nap, uint32_t args)
{
  uint64_t *sys_args;
  int retcode = 0;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);

  /*
   * translate address from user space to system
   * note: cannot set "trap error"
   */
  sys_args = (uint64_t*)NaClUserToSys(nap, (uintptr_t) args);
  ZLOGS(LOG_DEBUG, "%s called", FunctionNameById(sys_args[0]));

  switch(*sys_args)
  {
    case TrapExit:
      retcode = ZVMExitHandle(nap, (int32_t) sys_args[2]);
      break;
    case TrapRead:
      retcode = ZVMReadHandle(nap,
          (int)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]);
      break;
    case TrapWrite:
      retcode = ZVMWriteHandle(nap,
          (int)sys_args[2], (char*)sys_args[3], (int32_t)sys_args[4], sys_args[5]);
      break;
    case TrapSyscallback:
      retcode = ZVMSyscallback(nap, (int32_t)sys_args[2]);
      break;
    case TrapChannels:
      retcode = ZVMChannels(nap, (struct ZVMChannel*)sys_args[2]);
      break;
    case TrapChannelName:
      retcode = ZVMChannelName(nap, (struct ZVMChannel*)sys_args[2], (int32_t)sys_args[3]);
      break;
    case TrapHeapEnd:
      retcode = ZVMHeapEnd(nap);
      break;
    case TrapHeapPtr:
      retcode = ZVMHeapPtr(nap);
      break;
    default:
      retcode = -EPERM;
      ZLOG(LOG_ERROR, "function %ld is not supported", *sys_args);
      break;
  }

  ZLOGS(LOG_DEBUG, "%s returned %d", FunctionNameById(sys_args[0]), retcode);
  return retcode;
}
Ejemplo n.º 14
0
/*
 * initializer: channels
 * returns channels number if buffer == NULL, otherwise
 * returns channels number and initializes given buffer with channels data
 */
static int32_t ZVMChannels(struct NaClApp *nap, struct ZVMChannel *buf)
{
  struct ZVMChannel *uchannels;
  struct ChannelDesc *channels;
  int ch;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);

  /* user asked for the channels count */
  if(buf == NULL) return nap->system_manifest->channels_count;

  channels = nap->system_manifest->channels;
  uchannels = (struct ZVMChannel*)NaClUserToSys(nap, (uintptr_t)buf);

  /* populate given array with the channels information */
  for(ch = 0; ch < nap->system_manifest->channels_count; ++ch)
  {
    int i;

    uchannels[ch].name = NULL; /* see ZVMChannelName() */
    uchannels[ch].type = channels[ch].type;

    /* copy limits and counters */
    for(i = 0; i < IOLimitsCount; ++i)
      uchannels[ch].limits[i] = channels[ch].limits[i];

    /* channel size/position */
    switch(uchannels[ch].type)
    {
      case SGetSPut:
        /* size/position is not defined */
        break;
      case SGetRPut:
        uchannels[ch].size = channels[ch].size;
        break;
      case RGetSPut:
        uchannels[ch].size = channels[ch].size;
        break;
      case RGetRPut:
        /* in this case get or put updates both positions synchronously */
        uchannels[ch].size = channels[ch].size;
        break;
      default:
        /* invalid access type */
        break;
    }
  }

  return nap->system_manifest->channels_count;
}
Ejemplo n.º 15
0
/*
 * return channel name length + 1 if given pointer is not NULL
 * and "name" field in the given channel descriptor is NULL
 * otherwise also copy channel alias to "name" field
 */
int32_t ZVMChannelName(struct NaClApp *nap, struct ZVMChannel *chnl, int ch)
{
  struct ZVMChannel *uchannel;
  struct ChannelDesc *channel;
  char *alias;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);

  if(chnl == NULL) return -EINVAL;

  uchannel = (struct ZVMChannel*)NaClUserToSys(nap, (uintptr_t)chnl);
  channel = &nap->system_manifest->channels[ch];

  /* user asked for the name. give her the channel alias */
  if(uchannel->name != NULL)
  {
    alias = (char*)NaClUserToSys(nap, (uintptr_t)uchannel->name);
    strcpy(alias, channel->alias);
  }

  return strlen(channel->alias) + 1;
}
Ejemplo n.º 16
0
/*
 * write specified amount of bytes from buffer to given desc/offset
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMWriteHandle(struct NaClApp *nap,
    int ch, const char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  const char *sys_buffer;

  assert(nap != NULL);
  assert(nap->manifest != NULL);
  assert(nap->manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->manifest->channels->len)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=%p, size=%d, offset=%ld",
        ch, buffer, size, offset);
    return -EINVAL;
  }
  channel = CH_CH(nap->manifest, ch);
  ZLOGS(LOG_INSANE, "channel %s, buffer=%p, size=%d, offset=%ld",
      channel->alias, buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access write */
  if(CH_SEQ_WRITEABLE(channel)) offset = channel->putpos;

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check limits */
  if(channel->counters[PutsLimit] >= channel->limits[PutsLimit])
    return -EDQUOT;
  tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit];
  if(offset >= channel->limits[PutSizeLimit] &&
      !((CH_RW_TYPE(channel) & 1) == 1)) return -EINVAL;

  if(offset >= channel->size + tail) return -EINVAL;
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* write data */
  return ChannelWrite(channel, sys_buffer, (size_t)size, (off_t)offset);
}
Ejemplo n.º 17
0
int main(int argc, char **argv) {
  struct NaClApp app;
  uint32_t mmap_addr;
  char arg_string[32];
  char *args[] = {"prog_name", arg_string};

  NaClAllModulesInit();

  if (argc != 2) {
    NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n");
  }

  NaClAddSyscall(NACL_sys_test_syscall_1, TestSyscall);

  CHECK(NaClAppCtor(&app));
  CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK);
  NaClAppInitialDescriptorHookup(&app);
  CHECK(NaClAppPrepareToLaunch(&app) == LOAD_OK);

  NaClSignalHandlerInit();
  NaClSignalHandlerSet(TrapSignalHandler);

  /*
   * Allocate some space in untrusted address space.  We pass the
   * address to the guest program so that it can write a register
   * snapshot for us to compare against.
   */
  mmap_addr = NaClSysMmapIntern(
      &app, NULL, sizeof(*g_test_shm),
      NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
      NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS, -1, 0);
  g_test_shm = (struct RegsTestShm *) NaClUserToSys(&app, mmap_addr);
  SNPRINTF(arg_string, sizeof(arg_string), "0x%x", (unsigned int) mmap_addr);

  CHECK(NaClCreateMainThread(&app, 2, args, NULL));
  CHECK(NaClWaitForMainThreadToExit(&app) == 0);

  CHECK(!g_in_untrusted_code);
  ASSERT_EQ(g_context_switch_count,
            (kNumberOfCallsToTest + kFastPathSyscallsToTest - 1) * 2);

  /*
   * Avoid calling exit() because it runs process-global destructors
   * which might break code that is running in our unjoined threads.
   */
  NaClExit(0);
  return 0;
}
Ejemplo n.º 18
0
Archivo: trap.c Proyecto: hxr/zerovm
/*
 * read specified amount of bytes from given desc/offset to buffer
 * return amount of read bytes or negative error code if call failed
 */
int32_t TrapReadHandle(struct NaClApp *nap,
    enum ChannelType desc, char *buffer, int32_t size, int64_t offset)
{
  struct PreOpenedFileDesc *fd;
  int64_t tail;
  char *sys_buffer;
  int32_t retcode;

  // ### make it function with editable list of available channels
  /* only allow this call for InputChannel, OutputChannel */
  if(desc != InputChannel && desc != OutputChannel) return -INVALID_DESC;

  /* convert address and check buffer */
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  NaClLog(4, "%s() invoked: desc=%d, buffer=0x%lx, size=%d, offset=%ld\n",
      __func__, desc, (intptr_t)buffer, size, offset);

  /* take fd from nap with given desc */
  if(nap == NULL) return -INTERNAL_ERR;
  fd = &nap->manifest->user_setup->channels[desc];
  if(fd == NULL) return -INVALID_DESC;
  if(fd->mounted != LOADED) return -INVALID_MODE; // ### make it function with editable list of available channels

  /* check arguments sanity */
  if(size < 1) return -INSANE_SIZE;
  if(offset < 0) return -INSANE_OFFSET;

  /* check/update limits/counters */
  if(offset >= fd->fsize) return -OUT_OF_BOUNDS;
  if(fd->cnt_gets >= fd->max_gets) return -OUT_OF_LIMITS;

  tail = fd->max_get_size - fd->cnt_get_size;
  if(size > tail) size = tail;
  if(size < 1) return -OUT_OF_LIMITS;

  /* update counters (even if syscall failed) */
  ++fd->cnt_gets;
  fd->cnt_get_size += size;

  /* read data */
  retcode = pread(fd->handle, sys_buffer, (size_t)size, (off_t)offset);

  return retcode;
}
struct NaClSignalContext *StartGuestWithSharedMemory(
    struct NaClApp *nap) {
  char arg_string[32];
  char *args[] = {"prog_name", arg_string};
  uint32_t mmap_addr;
  struct NaClSignalContext *expected_regs;

  /*
   * Allocate some space in untrusted address space.  We pass the
   * address to the guest program so that we can share data with it.
   */
  mmap_addr = NaClSysMmapIntern(
      nap, NULL, sizeof(*expected_regs),
      NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
      NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS,
      -1, 0);
  SNPRINTF(arg_string, sizeof(arg_string), "0x%x", (unsigned int) mmap_addr);
  expected_regs = (struct NaClSignalContext *) NaClUserToSys(nap, mmap_addr);

  WaitForThreadToExitFully(nap);

  CHECK(NaClCreateMainThread(nap, NACL_ARRAY_SIZE(args), args, NULL));
  return expected_regs;
}
Ejemplo n.º 20
0
/*
 * read specified amount of bytes from given desc/offset to buffer
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMReadHandle(struct NaClApp *nap,
    int ch, char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  char *sys_buffer;
  int32_t retcode = -1;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);
  assert(nap->system_manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->system_manifest->channels_count)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld",
        ch, (intptr_t)buffer, size, offset);
    return -EINVAL;
  }
  channel = &nap->system_manifest->channels[ch];
  ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld",
      channel->alias, (intptr_t)buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access read */
  if(CHANNEL_SEQ_READABLE(channel))
    offset = channel->getpos;
  else
    /* prevent reading beyond the end of the random access channels */
    size = MIN(channel->size - offset, size);

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check for eof */
  if(channel->eof) return 0;

  /* check limits */
  if(channel->counters[GetsLimit] >= channel->limits[GetsLimit])
    return -EDQUOT;
  if(CHANNEL_RND_READABLE(channel))
    if(offset >= channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit]
      + channel->size) return -EINVAL;

  /* calculate i/o leftovers */
  tail = channel->limits[GetSizeLimit] - channel->counters[GetSizeLimit];
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* read data and update position */
  switch(channel->source)
  {
    case ChannelRegular:
      retcode = pread(channel->handle, sys_buffer, (size_t)size, (off_t)offset);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelCharacter:
    case ChannelFIFO:
     retcode = fread(sys_buffer, 1, (size_t)size, (FILE*)channel->socket);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelTCP:
      retcode = FetchMessage(channel, sys_buffer, size);
      if(retcode == -1) retcode = -EIO;
      break;
    default: /* design error */
      ZLOGFAIL(1, EFAULT, "invalid channel source");
      break;
  }

  /* update the channel counter, size, position and tag */
  ++channel->counters[GetsLimit];
  if(retcode > 0)
  {
    channel->counters[GetSizeLimit] += retcode;
    UpdateChannelTag(channel, (const char*)sys_buffer, retcode);

    /*
     * current get cursor. must be updated if channel have seq get
     * but there is nothing wrong to update it even it have random get
     */
    channel->getpos = offset + retcode;

    /* if channel have random put update put cursor. not allowed for cdr */
    if(CHANNEL_RND_WRITEABLE(channel)) channel->putpos = offset + retcode;
  }

  /*
   * set eof if 0 bytes has been read. it is safe because
   * 1. if user asked for a 0 bytes control will not reach this code
   * 2. if user asked more then 0 bytes and got 0 that means end of data
   * 3. if quota exceeded user will get an error before an actual read
   */
  if(retcode == 0) channel->eof = 1;

  return retcode;
}
Ejemplo n.º 21
0
/* serialize system data to user space */
static void SetSystemData(struct NaClApp *nap)
{
  struct SystemManifest *manifest;
  struct ChannelSerialized *channels;
  struct UserManifestSerialized *user_manifest;
  void *ptr; /* pointer to the user manifest area */
  int64_t size;
  int i;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);
  assert(nap->system_manifest->channels != NULL);

  manifest = nap->system_manifest;

  /*
   * 1. calculate channels array size (w/o aliases)
   * 2. calculate user manifest size (w/o aliases)
   * 3. calculate pointer to user manifest
   * 4. calculate pointer to channels array
   */
  size = manifest->channels_count * CHANNEL_STRUCT_SIZE;
  size += USER_MANIFEST_STRUCT_SIZE + USER_PTR_SIZE;
  ptr = (void*)(FOURGIG - nap->stack_size - size);
  user_manifest = (void*)NaClUserToSys(nap, (uintptr_t)ptr);
  channels = (void*)((uintptr_t)&user_manifest->channels + USER_PTR_SIZE);

  /* make the 1st page of user manifest writeable */
  CopyDown((void*)NaClUserToSys(nap, FOURGIG - nap->stack_size), "");
  ptr = user_manifest;

  /* initialize pointer to user manifest */
  SetUserManifestPtr(nap, user_manifest);

  /* serialize channels */
  for(i = 0; i < manifest->channels_count; ++i)
  {
    /* limits */
    int j;
    for(j = 0; j < IOLimitsCount; ++j)
      channels[i].limits[j] = manifest->channels[i].limits[j];

    /* type and size */
    channels[i].type = (int32_t)manifest->channels[i].type;
    channels[i].size = channels[i].type == SGetSPut
        ? 0 : manifest->channels[i].size;

    /* alias */
    ptr = CopyDown(ptr, manifest->channels[i].alias);
    channels[i].name = NaClSysToUser(nap, (uintptr_t)ptr);
  }

  /* update heap_size in the user manifest */
  size = ROUNDDOWN_64K(NaClSysToUser(nap, (uintptr_t)ptr));
  size = MIN(nap->heap_end, size);
  user_manifest->heap_size = size - nap->break_addr;

  /* note that rw data merged with heap! */

  /* update memory map */
  nap->mem_map[HeapIdx].end = NaClUserToSys(nap, size);
  nap->mem_map[HeapIdx].size = user_manifest->heap_size;

  /* serialize the rest of the user manifest records */
  user_manifest->heap_ptr = nap->break_addr;
  user_manifest->stack_size = nap->stack_size;
  user_manifest->channels_count = manifest->channels_count;
  user_manifest->channels = NaClSysToUser(nap, (uintptr_t)channels);

  /* make the user manifest read only */
  ProtectUserManifest(nap, ptr);
}
Ejemplo n.º 22
0
int32_t TrapHandler(struct NaClApp *nap, uint32_t args)
{
  uint64_t *sargs;
  int retcode = 0;

  assert(nap != NULL);
  assert(nap->manifest != NULL);

  /*
   * translate address from user space to system
   * note: cannot set "trap error"
   */
  sargs = (uint64_t*)NaClUserToSys(nap, (uintptr_t)args);
  ZLOGS(LOG_DEBUG, "%s called", FunctionName(*sargs));
  ZTrace("untrusted code");

  switch(*sargs)
  {
    case TrapFork:
      retcode = Daemon(nap);
      if(retcode) break;
      SyscallZTrace(*sargs, 0);
      SyscallZTrace(TrapExit, 0);
      ZVMExitHandle(nap, 0);
      break;
    case TrapExit:
      SyscallZTrace(*sargs, sargs[2]);
      ZVMExitHandle(nap, (int32_t)sargs[2]);
      break;
    case TrapRead:
      retcode = ZVMReadHandle(nap,
          (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]);
      break;
    case TrapWrite:
      retcode = ZVMWriteHandle(nap,
          (int)sargs[2], (char*)sargs[3], (int32_t)sargs[4], sargs[5]);
      break;
    case TrapJail:
      retcode = ZVMJailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]);
      break;
    case TrapUnjail:
      retcode = ZVMUnjailHandle(nap, (uint32_t)sargs[2], (int32_t)sargs[3]);
      break;

#ifdef ZVM_SOCKETS
    case TrapSocket:
      retcode = ZVM_socket((int)sargs[2], (int)sargs[3], (int)sargs[4]);
      break;
    case TrapBind: {
      const struct sockaddr *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_bind((int)sargs[2], addr, (socklen_t)sargs[4]);
      break; }
    case TrapConnect: {
      const struct sockaddr *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_connect((int)sargs[2], addr, (socklen_t)sargs[4]);
      break; }
    case TrapAccept: {
      struct sockaddr *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      socklen_t *len = (void*)NaClUserToSys(nap, (uintptr_t)sargs[4]);
      retcode = ZVM_accept((int)sargs[2], addr, len);
      break; }
    case TrapListen:
      retcode = ZVM_listen((int)sargs[2], (int)sargs[3]);
      break;
    case TrapRecv: {
      void *buf = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_recv((int)sargs[2], buf, (size_t)sargs[4], (int)sargs[5]);
      break; }
    case TrapRecvfrom: {
      void *buf = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      struct sockaddr *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[6]);
      socklen_t *len = (void*)NaClUserToSys(nap, (uintptr_t)sargs[7]);
      retcode = ZVM_recvfrom((int)sargs[2], buf, (size_t)sargs[4], (int)sargs[5], addr, len);
      break; }
    case TrapRecvmsg: {
      struct msghdr *msg = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_recvmsg((int)sargs[2], msg, (int)sargs[4]);
      break; }
    case TrapSend: {
      const void *buf = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_send((int)sargs[2], buf, (size_t)sargs[4], (int)sargs[5]);
      break; }
    case TrapSendto: {
      const void *buf = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      const struct sockaddr *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[6]);
      retcode = ZVM_sendto((int)sargs[2], buf, (size_t)sargs[4], (int)sargs[5], addr, (socklen_t)sargs[7]);
      break; }
    case TrapSendmsg: {
      const struct msghdr *msg = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      retcode = ZVM_sendmsg((int)sargs[2], msg, (int)sargs[4]);
      break; }
    case TrapGetsockopt: {
      void *optval = (void*)NaClUserToSys(nap, (uintptr_t)sargs[5]);
      socklen_t *len = (void*)NaClUserToSys(nap, (uintptr_t)sargs[6]);
      retcode = ZVM_getsockopt((int)sargs[2], (int)sargs[3], (int)sargs[4], optval, len);
      break; }
    case TrapSetsockopt: {
      const void *optval = (void*)NaClUserToSys(nap, (uintptr_t)sargs[5]);
      retcode = ZVM_setsockopt((int)sargs[2], (int)sargs[3], (int)sargs[4], optval, (socklen_t)sargs[6]);
      break; }
    case TrapSelect: {
      fd_set *readfds = (void*)NaClUserToSys(nap, (uintptr_t)sargs[3]);
      fd_set *writefds = (void*)NaClUserToSys(nap, (uintptr_t)sargs[4]);
      fd_set *exceptfds = (void*)NaClUserToSys(nap, (uintptr_t)sargs[5]);
      struct timeval *timeout = (void*)NaClUserToSys(nap, (uintptr_t)sargs[6]);
      retcode = ZVM_select((int)sargs[2], readfds, writefds, exceptfds, timeout);
      break; }
    case TrapPoll: {
      struct pollfd *fds = (void*)NaClUserToSys(nap, (uintptr_t)sargs[2]);
      retcode = ZVM_poll(fds, (nfds_t)sargs[3], (int)sargs[4]);
      break; }
    case TrapGethostbyname: {
      const char *name = (void*)NaClUserToSys(nap, (uintptr_t)sargs[2]);
      retcode = (int)(intptr_t)ZVM_gethostbyname(name);
      break; }
    case TrapGethostbyaddr: {
      const void *addr = (void*)NaClUserToSys(nap, (uintptr_t)sargs[2]);
      retcode = (int)(intptr_t)ZVM_gethostbyaddr(addr, (socklen_t)sargs[3], (int)sargs[4]);
      break; }
    case TrapClose:
      retcode = ZVM_close((int)sargs[2]);
      break;
#endif

    default:
      retcode = -EPERM;
      ZLOG(LOG_ERROR, "function %ld is not supported", *sargs);
      break;
  }

  /* report, ztrace and return */
  FastReport();
  ZLOGS(LOG_DEBUG, "%s returned %d", FunctionName(*sargs), retcode);
  SyscallZTrace(*sargs, retcode, sargs[2], sargs[3], sargs[4], sargs[5], sargs[6], sargs[7]);
  return retcode;
}
Ejemplo n.º 23
0
NaClErrorCode NaClElfImageLoadDynamically(
    struct NaClElfImage *image,
    struct NaClApp *nap,
    struct NaClDesc *ndp,
    struct NaClValidationMetadata *metadata) {
  ssize_t read_ret;
  int segnum;
  for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
    const Elf_Phdr *php = &image->phdrs[segnum];
    Elf_Addr vaddr = php->p_vaddr & ~(NACL_MAP_PAGESIZE - 1);
    Elf_Off offset = php->p_offset & ~(NACL_MAP_PAGESIZE - 1);
    Elf_Off filesz = php->p_offset + php->p_filesz - offset;
    Elf_Off memsz = php->p_offset + php->p_memsz - offset;
    int32_t result;

    /*
     * By checking if filesz is larger than memsz, we no longer run the risk of
     * a malicious ELF object overrunning into the trusted address space when
     * reading data of size "filez" into a buffer of size "memsz".
     */
    if (filesz > memsz) {
      return LOAD_UNLOADABLE;
    }

    /*
     * We check for PT_LOAD directly rather than using the "loadable"
     * array because we are not using NaClElfImageValidateProgramHeaders()
     * to fill out the "loadable" array for this ELF object.  This ELF
     * object does not have to fit such strict constraints (such as
     * having code at 0x20000), and safety checks are applied by
     * NaClTextDyncodeCreate() and NaClSysMmapIntern().
     */
    if (PT_LOAD != php->p_type) {
      continue;
    }

    if (0 != (php->p_flags & PF_X)) {
      /* Load code segment. */
      /*
       * We make a copy of the code.  This is not ideal given that this
       * code path is used only for loading the IRT, and we could assume
       * that the contents of the irt.nexe file will not change underneath
       * us.  We should be able to mmap() the IRT's code segment instead of
       * copying it.
       * TODO(mseaborn): Reduce the amount of copying here.
       */
      char *code_copy = malloc(filesz);
      if (NULL == code_copy) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: malloc failed\n");
        return LOAD_NO_MEMORY;
      }
      read_ret = (*NACL_VTBL(NaClDesc, ndp)->
                  PRead)(ndp, code_copy, filesz, (nacl_off64_t) offset);
      if (NaClSSizeIsNegErrno(&read_ret) ||
          (size_t) read_ret != filesz) {
        free(code_copy);
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to read code segment\n");
        return LOAD_READ_ERROR;
      }
      if (NULL != metadata) {
        metadata->code_offset = offset;
      }
      result = NaClTextDyncodeCreate(nap, (uint32_t) vaddr,
                                     code_copy, (uint32_t) filesz, metadata);
      free(code_copy);
      if (0 != result) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to load code segment\n");
        return LOAD_UNLOADABLE;
      }
    } else {
      /* Load data segment. */
      void *paddr = (void *) NaClUserToSys(nap, vaddr);
      size_t mapping_size = NaClRoundAllocPage(memsz);
      /*
       * Note that we do not used NACL_ABI_MAP_FIXED because we do not
       * want to silently overwrite any existing mappings, such as the
       * user app's data segment or the stack.  We detect overmapping
       * when mmap chooses not to use the preferred address we supply.
       * (Ideally mmap would provide a MAP_EXCL option for this
       * instead.)
       */
      result = NaClSysMmapIntern(
          nap, (void *) (uintptr_t) vaddr, mapping_size,
          NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
          NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
          -1, 0);
      if ((int32_t) vaddr != result) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to map data segment\n");
        return LOAD_UNLOADABLE;
      }
      read_ret = (*NACL_VTBL(NaClDesc, ndp)->
                  PRead)(ndp, paddr, filesz, (nacl_off64_t) offset);
      if (NaClSSizeIsNegErrno(&read_ret) ||
          (size_t) read_ret != filesz) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to read data segment\n");
        return LOAD_READ_ERROR;
      }
      /*
       * Note that we do not need to zero the BSS (the region from
       * p_filesz to p_memsz) because it should already be zero
       * filled.  This would not be the case if we were mapping the
       * data segment from the file.
       */

      if (0 == (php->p_flags & PF_W)) {
        /* Handle read-only data segment. */
        int rc = NaClMprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
        if (0 != rc) {
          NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                  "failed to mprotect read-only data segment\n");
          return LOAD_MPROTECT_FAIL;
        }

        NaClVmmapAddWithOverwrite(&nap->mem_map,
                                  vaddr >> NACL_PAGESHIFT,
                                  mapping_size >> NACL_PAGESHIFT,
                                  NACL_ABI_PROT_READ,
                                  NACL_ABI_MAP_PRIVATE,
                                  NULL,
                                  0,
                                  0);
      }
    }
  }
Ejemplo n.º 24
0
NaClErrorCode NaClMakeDynamicTextShared(struct NaClApp *nap) {
  enum NaClErrorCode          retval = LOAD_INTERNAL;
  uintptr_t                   dynamic_text_size;
  struct NaClDescImcShm       *shm = NULL;
  uintptr_t                   shm_vaddr_base;
  int                         mmap_protections;
  uintptr_t                   mmap_ret;

  uintptr_t                   shm_upper_bound;
  uintptr_t                   text_sysaddr;

  shm_vaddr_base = NaClEndOfStaticText(nap);
  NaClLog(4,
          "NaClMakeDynamicTextShared: shm_vaddr_base = %08"NACL_PRIxPTR"\n",
          shm_vaddr_base);
  shm_vaddr_base = NaClRoundAllocPage(shm_vaddr_base);
  NaClLog(4,
          "NaClMakeDynamicTextShared: shm_vaddr_base = %08"NACL_PRIxPTR"\n",
          shm_vaddr_base);

  /*
   * Default is that there is no usable dynamic code area.
   */
  nap->dynamic_text_start = shm_vaddr_base;
  nap->dynamic_text_end = shm_vaddr_base;
  if (!nap->use_shm_for_dynamic_text) {
    NaClLog(4,
            "NaClMakeDynamicTextShared:"
            "  rodata / data segments not allocation aligned\n");
    NaClLog(4,
            " not using shm for text\n");
    return LOAD_OK;
  }

  /*
   * Allocate a shm region the size of which is nap->rodata_start -
   * end-of-text.  This implies that the "core" text will not be
   * backed by shm.
   */
  shm_upper_bound = nap->rodata_start;
  if (0 == shm_upper_bound) {
    shm_upper_bound = NaClTruncAllocPage(nap->data_start);
  }
  if (0 == shm_upper_bound) {
    shm_upper_bound = shm_vaddr_base;
  }

  NaClLog(4, "shm_upper_bound = %08"NACL_PRIxPTR"\n", shm_upper_bound);

  dynamic_text_size = shm_upper_bound - shm_vaddr_base;
  NaClLog(4,
          "NaClMakeDynamicTextShared: dynamic_text_size = %"NACL_PRIxPTR"\n",
          dynamic_text_size);

  if (0 == dynamic_text_size) {
    NaClLog(4, "Empty JITtable region\n");
    return LOAD_OK;
  }

  shm = (struct NaClDescImcShm *) malloc(sizeof *shm);
  if (NULL == shm) {
    NaClLog(4, "NaClMakeDynamicTextShared: shm object allocation failed\n");
    retval = LOAD_NO_MEMORY;
    goto cleanup;
  }
  if (!NaClDescImcShmAllocCtor(shm, dynamic_text_size, /* executable= */ 1)) {
    /* cleanup invariant is if ptr is non-NULL, it's fully ctor'd */
    free(shm);
    shm = NULL;
    NaClLog(4, "NaClMakeDynamicTextShared: shm alloc ctor for text failed\n");
    retval = LOAD_NO_MEMORY_FOR_DYNAMIC_TEXT;
    goto cleanup;
  }

  text_sysaddr = NaClUserToSys(nap, shm_vaddr_base);

  /* Existing memory is anonymous paging file backed. */
  NaClPageFree((void *) text_sysaddr, dynamic_text_size);

  /*
   * Unix allows us to map pages with PROT_NONE initially and later
   * increase the mapping permissions with mprotect().
   *
   * Windows does not allow this, however: the initial permissions are
   * an upper bound on what the permissions may later be changed to
   * with VirtualProtect() or VirtualAlloc().  Given this, using
   * PROT_NONE at this point does not even make sense.  On Windows,
   * the pages start off as uncommitted, which makes them inaccessible
   * regardless of the page permissions they are mapped with.
   *
   * Write permissions are included here for nacl64-gdb to set
   * breakpoints.
   */
#if NACL_WINDOWS
  mmap_protections =
    NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC | NACL_ABI_PROT_WRITE;
#else
  mmap_protections = NACL_ABI_PROT_NONE;
#endif
  NaClLog(4,
          "NaClMakeDynamicTextShared: Map(,,0x%"NACL_PRIxPTR",size = 0x%x,"
          " prot=0x%x, flags=0x%x, offset=0)\n",
          text_sysaddr,
          (int) dynamic_text_size,
          mmap_protections,
          NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED);
  mmap_ret = (*((struct NaClDescVtbl const *) shm->base.base.vtbl)->
              Map)((struct NaClDesc *) shm,
                   NaClDescEffectorTrustedMem(),
                   (void *) text_sysaddr,
                   dynamic_text_size,
                   mmap_protections,
                   NACL_ABI_MAP_SHARED | NACL_ABI_MAP_FIXED,
                   0);
  if (text_sysaddr != mmap_ret) {
    NaClLog(LOG_FATAL, "Could not map in shm for dynamic text region\n");
  }

  nap->dynamic_page_bitmap =
    BitmapAllocate((uint32_t) (dynamic_text_size / NACL_MAP_PAGESIZE));
  if (NULL == nap->dynamic_page_bitmap) {
    NaClLog(LOG_FATAL, "NaClMakeDynamicTextShared: BitmapAllocate() failed\n");
  }

  nap->dynamic_text_start = shm_vaddr_base;
  nap->dynamic_text_end = shm_upper_bound;
  nap->text_shm = &shm->base;
  retval = LOAD_OK;

 cleanup:
  if (LOAD_OK != retval) {
    NaClDescSafeUnref((struct NaClDesc *) shm);
    free(shm);
  }

  return retval;
}
Ejemplo n.º 25
0
static void TrapSignalHandler(int signal,
                              const struct NaClSignalContext *context_ptr,
                              int is_untrusted) {
  uint32_t prog_ctr;
  char buf[100];
  int len;
  struct NaClSignalContext *expected_regs = &g_test_shm->expected_regs;
  struct NaClSignalContext context = *context_ptr;

  if (signal != SIGTRAP) {
    SignalSafeLogStringLiteral("Error: Received unexpected signal\n");
    _exit(1);
  }

  /* Get the prog_ctr value relative to untrusted address space. */
  prog_ctr = (uint32_t) context.prog_ctr;
  /*
   * The trampoline code is not untrusted code because it is fixed by
   * the TCB.  We don't want thread suspension to report prog_ctr as
   * being inside the trampoline code because we are not providing any
   * DWARF unwind info for the trampoline code.  We want the CALL
   * instruction that jumps to a syscall trampoline to appear to be
   * atomic from the point of view of thread suspension: prog_ctr
   * should be reported as either at the CALL or after the CALL.
   *
   * TODO(mseaborn): Move this range check into the non-test part of
   * the thread suspension code.
   */
  if (prog_ctr >= NACL_TRAMPOLINE_START && prog_ctr < NACL_TRAMPOLINE_END) {
    is_untrusted = 0;
  }
  if (g_in_untrusted_code != is_untrusted) {
    g_context_switch_count++;
    g_in_untrusted_code = is_untrusted;
  }

  if (!*(uint32_t *) NaClUserToSys(g_natp->nap,
                                   (uintptr_t) g_test_shm->regs_should_match))
    return;

  len = snprintf(buf, sizeof(buf), "prog_ctr=0x%"NACL_PRIxNACL_REG": ",
                 context.prog_ctr);
  SignalSafeWrite(buf, len);

  if (is_untrusted) {
    SignalSafeLogStringLiteral("Untrusted context\n");
    RegsUnsetNonCalleeSavedRegisters(&context);
    /*
     * Don't compare prog_ctr if we are executing untrusted code.
     * Untrusted code executes a small loop for calling the syscall,
     * so there are multiple values that prog_ctr can have here.
     */
    context.prog_ctr = expected_regs->prog_ctr;
    RegsAssertEqual(&context, expected_regs);
  } else if ((g_natp->suspend_state & NACL_APP_THREAD_TRUSTED) != 0) {
    SignalSafeLogStringLiteral("Trusted (syscall) context\n");
    NaClThreadContextToSignalContext(&g_natp->user, &context);
    RegsAssertEqual(&context, expected_regs);
  } else {
    enum NaClUnwindCase unwind_case = 0;
    const char *str;

    SignalSafeLogStringLiteral("Inside a context switch: ");

    NaClGetRegistersForContextSwitch(g_natp, &context, &unwind_case);

    str = NaClUnwindCaseToString(unwind_case);
    CHECK(str != NULL);
    SignalSafeWrite(str, strlen(str));
    SignalSafeLogStringLiteral("\n");

    RegsAssertEqual(&context, expected_regs);
  }
}
Ejemplo n.º 26
0
NaClErrorCode NaClElfImageLoadDynamically(struct NaClElfImage *image,
                                          struct NaClApp      *nap,
                                          struct Gio          *gfile) {
  int segnum;
  for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
    const Elf_Phdr *php = &image->phdrs[segnum];
    int32_t result;

    /*
     * We check for PT_LOAD directly rather than using the "loadable"
     * array because we are not using NaClElfImageValidateProgramHeaders()
     * to fill out the "loadable" array for this ELF object.  This ELF
     * object does not have to fit such strict constraints (such as
     * having code at 0x20000), and safety checks are applied by
     * NaClTextDyncodeCreate() and NaClCommonSysMmapIntern().
     */
    if (PT_LOAD != php->p_type) {
      continue;
    }

    /*
     * Ideally, Gio would have a Pread() method which we would use
     * instead of Seek().  In practice, though, there is no
     * Seek()/Read() race condition here because both
     * GioMemoryFileSnapshot and NaClGioShm use a seek position that
     * is local and not shared between processes.
     */
    if ((*gfile->vtbl->Seek)(gfile, (off_t) php->p_offset,
                             SEEK_SET) == (off_t) -1) {
      NaClLog(1, "NaClElfImageLoadDynamically: seek failed\n");
      return LOAD_READ_ERROR;
    }

    if (0 != (php->p_flags & PF_X)) {
      /* Load code segment. */
      /*
       * We make a copy of the code.  This is not ideal given that
       * GioMemoryFileSnapshot and NaClGioShm already have a copy of
       * the file in memory or mmapped.
       * TODO(mseaborn): Reduce the amount of copying here.
       */
      char *code_copy = malloc(php->p_filesz);
      if (NULL == code_copy) {
        NaClLog(1, "NaClElfImageLoadDynamically: malloc failed\n");
        return LOAD_NO_MEMORY;
      }
      if ((Elf_Word) (*gfile->vtbl->Read)(gfile, code_copy, php->p_filesz)
          != php->p_filesz) {
        free(code_copy);
        NaClLog(1, "NaClElfImageLoadDynamically: "
                "failed to read code segment\n");
        return LOAD_READ_ERROR;
      }
      result = NaClTextDyncodeCreate(nap, (uint32_t) php->p_vaddr,
                                     code_copy, (uint32_t) php->p_filesz);
      free(code_copy);
      if (0 != result) {
        NaClLog(1, "NaClElfImageLoadDynamically: "
                "failed to load code segment\n");
        return LOAD_UNLOADABLE;
      }
    } else {
      /* Load data segment. */
      void *paddr = (void *) NaClUserToSys(nap, php->p_vaddr);
      size_t mapping_size = NaClRoundAllocPage(php->p_memsz);
      /*
       * Note that we do not used NACL_ABI_MAP_FIXED because we do not
       * want to silently overwrite any existing mappings, such as the
       * user app's data segment or the stack.  We detect overmapping
       * when mmap chooses not to use the preferred address we supply.
       * (Ideally mmap would provide a MAP_EXCL option for this
       * instead.)
       */
      result = NaClCommonSysMmapIntern(
          nap, (void *) php->p_vaddr, mapping_size,
          NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
          NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
          -1, 0);
      if ((int32_t) php->p_vaddr != result) {
        NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n");
        return LOAD_UNLOADABLE;
      }
      if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz)
          != php->p_filesz) {
        NaClLog(1, "NaClElfImageLoadDynamically: "
                "failed to read data segment\n");
        return LOAD_READ_ERROR;
      }
      /*
       * Note that we do not need to zero the BSS (the region from
       * p_filesz to p_memsz) because it should already be zero
       * filled.  This would not be the case if we were mapping the
       * data segment from the file.
       */

      if (0 == (php->p_flags & PF_W)) {
        /* Handle read-only data segment. */
        int rc = NaCl_mprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
        if (0 != rc) {
          NaClLog(1, "NaClElfImageLoadDynamically: "
                  "failed to mprotect read-only data segment\n");
          return LOAD_MPROTECT_FAIL;
        }

        NaClVmmapUpdate(&nap->mem_map,
                        php->p_vaddr >> NACL_PAGESHIFT,
                        mapping_size >> NACL_PAGESHIFT,
                        PROT_READ,
                        NULL,
                        0  /* remove: false */);
      }
    }
  }
Ejemplo n.º 27
0
/*
 * Apply memory protection to memory regions.
 */
void NaClMemoryProtection(struct NaClApp *nap)
{
  uintptr_t start_addr;
  size_t    region_size;
  int       err;

  /*
   * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
   * This enables NULL pointer checking, and provides additional protection
   * against addr16/data16 prefixed operations being used for attacks.
   *
   * NaClMprotectGuards also sets up guard pages outside of the
   * virtual address space of the NaClApp -- for the ARM and x86-64
   * where data sandboxing only sandbox memory writes and not reads,
   * we need to ensure that certain addressing modes that might
   * otherwise allow the NaCl app to write outside its address space
   * (given how we using masking / base registers to implement data
   * write sandboxing) won't affect the trusted data structures.
   */

  ZLOGS(LOG_DEBUG, "Protecting guard pages for 0x%08x", nap->mem_start);
  NaClMprotectGuards(nap);

  start_addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
  /*
   * The next pages up to NACL_TRAMPOLINE_END are the trampolines.
   * Immediately following that is the loaded text section.
   * These are collectively marked as PROT_READ | PROT_EXEC.
   */
  region_size = NaClRoundPage(nap->static_text_end - NACL_SYSCALL_START_ADDR);
  ZLOGS(LOG_DEBUG, "Trampoline/text region start 0x%08x, size 0x%08x, end 0x%08x",
          start_addr, region_size, start_addr + region_size);

  err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ | PROT_EXEC);
  ZLOGFAIL(0 != err, err, FAILED_MSG);

  SET_MEM_MAP_IDX(nap->mem_map[TextIdx], "Text",
      start_addr, region_size, PROT_READ | PROT_EXEC);

  /*
   * Page protections for this region have already been set up by
   * nacl_text.c.
   *
   * todo(d'b): since text.c exists no more, protection should be set here
   *
   * We record the mapping for consistency with other fixed
   * mappings, but the record is not actually used.  Overmapping is
   * prevented by a separate range check, which is done by
   * NaClSysCommonAddrRangeContainsExecutablePages_mu().
   */
  /*
   * zerovm does not support dynamic text. the code below will check its
   * existence, log information and fail if needed.
   * todo(d'b): after the dynamic text support will be added or completely
   * removed the block below should be rewritten or removed
   */
  start_addr = NaClUserToSys(nap, nap->dynamic_text_start);
  region_size = nap->dynamic_text_end - nap->dynamic_text_start;
  ZLOGS(LOG_DEBUG, "shm txt region start 0x%08x, size 0x%08x, end 0x%08x",
      start_addr, region_size, start_addr + region_size);
  ZLOGFAIL(0 != region_size, EFAULT, "zerovm does not support nexe with dynamic text!");

  if(0 != nap->rodata_start)
  {
    uintptr_t rodata_end;

    /*
     * TODO(mseaborn): Could reduce the number of cases by ensuring
     * that nap->data_start is always non-zero, even if
     * nap->rodata_start == nap->data_start == nap->break_addr.
     */
    if(0 != nap->data_start)
      rodata_end = nap->data_start;
    else rodata_end = nap->break_addr;

    start_addr = NaClUserToSys(nap, nap->rodata_start);
    region_size = NaClRoundPage(NaClRoundAllocPage(rodata_end)
        - NaClSysToUser(nap, start_addr));
    ZLOGS(LOG_DEBUG, "RO data region start 0x%08x, size 0x%08x, end 0x%08x",
        start_addr, region_size, start_addr + region_size);

    err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ);
    ZLOGFAIL(0 != err, err, FAILED_MSG);

    SET_MEM_MAP_IDX(nap->mem_map[RODataIdx], "ROData",
        start_addr, region_size, PROT_READ);
  }

  /*
   * data_end is max virtual addr seen, so start_addr <= data_end
   * must hold.
   */
  if(0 != nap->data_start)
  {
    start_addr = NaClUserToSys(nap, nap->data_start);
    region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end)
        - NaClSysToUser(nap, start_addr));
    ZLOGS(LOG_DEBUG, "RW data region start 0x%08x, size 0x%08x, end 0x%08x",
        start_addr, region_size, start_addr + region_size);

    err = NaCl_mprotect((void *)start_addr, region_size, PROT_READ | PROT_WRITE);
    ZLOGFAIL(0 != err, err, FAILED_MSG);

    SET_MEM_MAP_IDX(nap->mem_map[HeapIdx], "Heap",
        start_addr, region_size, PROT_READ | PROT_WRITE);
  }

  /* stack is read/write but not execute */
  region_size = nap->stack_size;
  start_addr = NaClUserToSys(nap,
      NaClTruncAllocPage(((uintptr_t) 1U << nap->addr_bits) - nap->stack_size));
  ZLOGS(LOG_DEBUG, "RW stack region start 0x%08x, size 0x%08lx, end 0x%08x",
          start_addr, region_size, start_addr + region_size);

  err = NaCl_mprotect((void *)start_addr, NaClRoundAllocPage(nap->stack_size),
      PROT_READ | PROT_WRITE);
  ZLOGFAIL(0 != err, err, FAILED_MSG);

  SET_MEM_MAP_IDX(nap->mem_map[StackIdx], "Stack",
      start_addr, NaClRoundAllocPage(nap->stack_size), PROT_READ | PROT_WRITE);
}
Ejemplo n.º 28
0
Archivo: trap.c Proyecto: hxr/zerovm
/*
 * user request to change limits for system resources. for now we only can decrease bounds
 * return: function update given SetupList object (hint) and if there were
 * unsuccessful attempt to change policy return -1, otherwirse return 0
 */
static int32_t TrapUserSetupHandle(struct NaClApp *nap, struct SetupList *h)
{
  struct PreOpenedFileDesc *policy_channel;
  struct PreOpenedFileDesc *hint_channel;
  struct SetupList *policy = nap->manifest->user_setup;
  struct SetupList *hint = (struct SetupList*)NaClUserToSys(nap, (intptr_t) h);
  int32_t retcode = OK_CODE;
  enum ChannelType ch;

  /*
   * check/count this call. decrease number of syscalls
   * since this call is not really "system"
   */
  --nap->manifest->user_setup->cnt_syscalls;
  if(policy->max_setup_calls < ++policy->cnt_setup_calls)
    return -OUT_OF_LIMITS;

  /* check i/o limits */
  for(ch = InputChannel; ch < CHANNELS_COUNT; ++ch)
  {
    /* pick current channel settings */
    policy_channel = &policy->channels[ch];
    hint_channel = &hint->channels[ch];
    hint_channel->self_size = policy_channel->self_size; /* set self size */

#define STRNCPY_NULL(a, b, n) if ((a) && (b)) strncpy((a), (b), (n));
#define TRY_UPDATE(pretender, current)\
    do {\
      if(policy->cnt_setup_calls == 1) { pretender = current; break; }\
      if((pretender) < (current)) current = pretender;\
      else { pretender = current; retcode = ERR_CODE; }\
    } while(0)

    /* check/update i/o limits. 1st time - set fields in hint */
    TRY_UPDATE(hint_channel->max_size, policy_channel->max_size);
    TRY_UPDATE(hint_channel->max_get_size, policy_channel->max_get_size);
    TRY_UPDATE(hint_channel->max_gets, policy_channel->max_gets);
    TRY_UPDATE(hint_channel->max_put_size, policy_channel->max_put_size);
    TRY_UPDATE(hint_channel->max_puts, policy_channel->max_puts);

    /* set i/o fields n/a to change */
    hint_channel->bsize = policy_channel->bsize;
    hint_channel->buffer = policy_channel->buffer;
    hint_channel->fsize = policy_channel->fsize;
    hint_channel->type = policy_channel->type;
  }

  /* check/update system limits. 1st time - set fields in hint */
  TRY_UPDATE(hint->max_cpu, policy->max_cpu);
  TRY_UPDATE(hint->max_mem, policy->max_mem); /* ### call unmap here? */
  TRY_UPDATE(hint->max_syscalls, policy->max_syscalls);
  TRY_UPDATE(hint->max_setup_calls, policy->max_setup_calls);

  /* set system fields n/a to change */
  hint->self_size = policy->self_size; /* set self size */
  hint->heap_ptr = policy->heap_ptr; /* set self size */
  STRNCPY_NULL(hint->content_type, policy->content_type, CONTENT_TYPE_LEN);
  STRNCPY_NULL(hint->timestamp, policy->timestamp, TIMESTAMP_LEN);
  STRNCPY_NULL(hint->user_etag, policy->user_etag, USER_TAG_LEN);
  STRNCPY_NULL(hint->x_object_meta_tag, policy->x_object_meta_tag, X_OBJECT_META_TAG_LEN);

  /* update syscallback */
  if(UpdateSyscallback(nap, hint) == ERR_CODE) retcode = ERR_CODE;

#undef STRNCPY_NULL
#undef TRY_UPDATE
  return retcode;
}
/*
 * preconditions:
 * argc > 0, argc and argv table is consistent
 * envv may be NULL (this happens on MacOS/Cocoa
 * if envv is non-NULL it is 'consistent', null terminated etc.
 */
int NaClCreateMainThread(struct NaClApp     *nap,
                         int                argc,
                         char               **argv,
                         char const *const  *envv) {
  /*
   * Compute size of string tables for argv and envv
   */
  int                   retval;
  int                   envc;
  size_t                size;
  size_t                ptr_tbl_size;
  int                   i;
  char                  *p;
  char                  *strp;
  size_t                *argv_len;
  size_t                *envv_len;
  struct NaClAppThread  *natp;
  uintptr_t             stack_ptr;

  /*
   * Set an exception handler so Windows won't show a message box if
   * an exception occurs
   */
  WINDOWS_EXCEPTION_TRY;

  retval = 0;  /* fail */
  CHECK(argc > 0);
  CHECK(NULL != argv);

  envc = 0;
  if (NULL != envv) {
    char const *const *pp;
    for (pp = envv; NULL != *pp; ++pp) {
      ++envc;
    }
  }
  envv_len = 0;
  argv_len = malloc(argc * sizeof argv_len[0]);
  envv_len = malloc(envc * sizeof envv_len[0]);
  if (NULL == argv_len) {
    goto cleanup;
  }
  if (NULL == envv_len && 0 != envc) {
    goto cleanup;
  }

  /*
   * Store information for remote query when debugging.
   */
  NaClDebugSetAppInfo(nap);
  NaClDebugSetAppEnvironment(argc, (char const * const *) argv,
                             envc, (char const * const *) envv);
  NaClDebugStart();

  size = 0;

  /*
   * The following two loops cannot overflow.  The reason for this is
   * that they are counting the number of bytes used to hold the
   * NUL-terminated strings that comprise the argv and envv tables.
   * If the entire address space consisted of just those strings, then
   * the size variable would overflow; however, since there's the code
   * space required to hold the code below (and we are not targetting
   * Harvard architecture machines), at least one page holds code, not
   * data.  We are assuming that the caller is non-adversarial and the
   * code does not look like string data....
   */
  for (i = 0; i < argc; ++i) {
    argv_len[i] = strlen(argv[i]) + 1;
    size += argv_len[i];
  }
  for (i = 0; i < envc; ++i) {
    envv_len[i] = strlen(envv[i]) + 1;
    size += envv_len[i];
  }

  /*
   * NaCl modules are ILP32, so the argv, envv pointers, as well as
   * the terminating NULL pointers at the end of the argv/envv tables,
   * are 32-bit values.  We also have the empty auxv to take into
   * account, so that's 6 additional 32-bit values on top of the
   * argv/envv contents.  Note that on nacl64, argc is popped, and
   * is an 8-byte value!
   *
   * The argv and envv pointer tables came from trusted code and is
   * part of memory.  Thus, by the same argument above, adding in
   * (argc+envc+4)*sizeof(void *) cannot possibly overflow the size
   * variable since it is a size_t object.  However, the two more
   * pointers for auxv and the space for argv could cause an overflow.
   * The fact that we used stack to get here etc means that
   * ptr_tb_size could not have overflowed.
   *
   * NB: the underlying OS would have limited the amount of space used
   * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and
   * hence the overflow check is for obvious auditability rather than
   * for correctness.
   */
  ptr_tbl_size = (argc + envc + 6) * sizeof(uint32_t) + sizeof(int);

  if (SIZE_T_MAX - size < ptr_tbl_size) {
    NaClLog(LOG_WARNING,
            "NaClCreateMainThread: ptr_tb_size cause size of"
            " argv / environment copy to overflow!?!\n");
    retval = 0;
    goto cleanup;
  }
  size += ptr_tbl_size;

  size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK;

  if (size > nap->stack_size) {
    retval = 0;
    goto cleanup;
  }

  /* write strings and char * arrays to stack */
  stack_ptr = (nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) - size);

  NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr);

  VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK),
         ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr));

  p = (char *) stack_ptr;
  strp = p + ptr_tbl_size;

#define BLAT(t, v) do { \
    *(t *) p = (t) v; p += sizeof(t);           \
  } while (0);

  BLAT(nacl_reg_t, argc);

  for (i = 0; i < argc; ++i) {
    BLAT(uint32_t, NaClSysToUser(nap, (uintptr_t) strp));
    NaClLog(2, "copying arg %d  %p -> %p\n",
            i, argv[i], strp);
    strcpy(strp, argv[i]);
    strp += argv_len[i];
  }
  BLAT(uint32_t, 0);

  for (i = 0; i < envc; ++i) {
    BLAT(uint32_t, NaClSysToUser(nap, (uintptr_t) strp));
    NaClLog(2, "copying env %d  %p -> %p\n",
            i, envv[i], strp);
    strcpy(strp, envv[i]);
    strp += envv_len[i];
  }
  BLAT(uint32_t, 0);
  /* Push an empty auxv for glibc support */
  BLAT(uint32_t, 0);
  BLAT(uint32_t, 0);
#undef BLAT

  /* now actually spawn the thread */
  natp = malloc(sizeof *natp);
  if (!natp) {
    goto cleanup;
  }

  /* We are ready to distinguish crashes in trusted and untrusted code. */
  NaClSignalRegisterApp(nap);

  nap->running = 1;

  NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr);
  NaClLog(2, "  user stack ptr : %016"NACL_PRIxPTR"\n",
          NaClSysToUserStackAddr(nap, stack_ptr));

  /* e_entry is user addr */
  if (!NaClAppThreadAllocSegCtor(natp,
                                 nap,
                                 1,
                                 nap->entry_pt,
                                 NaClSysToUserStackAddr(nap, stack_ptr),
                                 NaClUserToSys(nap, nap->break_addr),
                                 1)) {
    retval = 0;
    goto cleanup;
  }

  /*
   * NB: Hereafter locking is required to access nap.
   */
  retval = 1;
cleanup:
  free(argv_len);
  free(envv_len);

  WINDOWS_EXCEPTION_CATCH;
  return retval;
}
Ejemplo n.º 30
0
/*
 * write specified amount of bytes from buffer to given desc/offset
 * return amount of read bytes or negative error code if call failed
 */
static int32_t ZVMWriteHandle(struct NaClApp *nap,
    int ch, const char *buffer, int32_t size, int64_t offset)
{
  struct ChannelDesc *channel;
  int64_t tail;
  const char *sys_buffer;
  int32_t retcode = -1;

  assert(nap != NULL);
  assert(nap->system_manifest != NULL);
  assert(nap->system_manifest->channels != NULL);

  /* check the channel number */
  if(ch < 0 || ch >= nap->system_manifest->channels_count)
  {
    ZLOGS(LOG_DEBUG, "channel_id=%d, buffer=0x%lx, size=%d, offset=%ld",
        ch, (intptr_t)buffer, size, offset);
    return -EINVAL;
  }
  channel = &nap->system_manifest->channels[ch];
  ZLOGS(LOG_DEBUG, "channel %s, buffer=0x%lx, size=%d, offset=%ld",
      channel->alias, (intptr_t)buffer, size, offset);

  /* check buffer and convert address */
  if(CheckRAMAccess(nap, (uintptr_t)buffer, size, PROT_READ) == -1) return -EINVAL;
  sys_buffer = (char*)NaClUserToSys(nap, (uintptr_t) buffer);

  /* ignore user offset for sequential access write */
  if(CHANNEL_SEQ_WRITEABLE(channel)) offset = channel->putpos;

  /* check arguments sanity */
  if(size == 0) return 0; /* success. user has read 0 bytes */
  if(size < 0) return -EFAULT;
  if(offset < 0) return -EINVAL;

  /* check limits */
  if(channel->counters[PutsLimit] >= channel->limits[PutsLimit])
    return -EDQUOT;
  tail = channel->limits[PutSizeLimit] - channel->counters[PutSizeLimit];
  if(offset >= channel->limits[PutSizeLimit] &&
      !CHANNEL_READABLE(channel)) return -EINVAL;
  if(offset >= channel->size + tail) return -EINVAL;
  if(size > tail) size = tail;
  if(size < 1) return -EDQUOT;

  /* write data and update position */
  switch(channel->source)
  {
    case ChannelRegular:
      retcode = pwrite(channel->handle, sys_buffer, (size_t)size, (off_t)offset);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelCharacter:
    case ChannelFIFO:
      retcode = fwrite(sys_buffer, 1, (size_t)size, (FILE*)channel->socket);
      if(retcode == -1) retcode = -errno;
      break;
    case ChannelTCP:
      retcode = SendMessage(channel, sys_buffer, size);
      if(retcode == -1) retcode = -EIO;
      break;
    default: /* design error */
      ZLOGFAIL(1, EFAULT, "invalid channel source");
      break;
  }

  /* update the channel counter, size, position and tag */
  ++channel->counters[PutsLimit];
  if(retcode > 0)
  {
    channel->counters[PutSizeLimit] += retcode;
    UpdateChannelTag(channel, (const char*)sys_buffer, retcode);

    channel->putpos = offset + retcode;
    channel->size = (channel->type == SGetRPut) || (channel->type == RGetRPut) ?
        MAX(channel->size, channel->putpos) : channel->putpos;
    channel->getpos = channel->putpos;
  }

  return retcode;
}