Ejemplo n.º 1
0
int NaClHostDescFdatasync(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFdatasync", d);
  /* fdatasync does not exist for osx. */
#if NACL_OSX
  if (-1 == fsync(d->d)) {
#else
  if (-1 == fdatasync(d->d)) {
#endif
    return -NaClXlateErrno(errno);
  }
  return 0;
}

int NaClHostDescFtruncate(struct NaClHostDesc *d, nacl_off64_t length) {
  NaClHostDescCheckValidity("NaClHostDescFtruncate", d);
#if NACL_LINUX
  if (-1 == ftruncate64(d->d, length)) {
#elif NACL_OSX
  if (-1 == ftruncate(d->d, length)) {
#else
# error Unsupported platform
#endif
    return -NaClXlateErrno(errno);
  }
  return 0;
}
Ejemplo n.º 2
0
int NaClClockGetTime(nacl_clockid_t            clk_id,
                     struct nacl_abi_timespec  *tp) {
  int             rv = -NACL_ABI_EINVAL;
  struct timespec host_time;

  if (!g_NaClClock_is_initialized) {
    NaClLog(LOG_FATAL,
            "NaClClockGetTime invoked without successful NaClClockInit\n");
  }
  switch (clk_id) {
    case NACL_CLOCK_REALTIME:
      if (0 != clock_gettime(CLOCK_REALTIME, &host_time)) {
        rv = -NaClXlateErrno(errno);
      } else {
        rv = 0;
      }
      break;
    case NACL_CLOCK_MONOTONIC:
      if (0 != clock_gettime(CLOCK_MONOTONIC, &host_time)) {
        rv = -NaClXlateErrno(errno);
      } else {
        rv = 0;
      }
      break;
    case NACL_CLOCK_PROCESS_CPUTIME_ID:
    case NACL_CLOCK_THREAD_CPUTIME_ID:
      rv = -NACL_ABI_EINVAL;
      break;
  }
  if (0 == rv) {
    tp->tv_sec = host_time.tv_sec;
    tp->tv_nsec = host_time.tv_nsec;
  }
  return rv;
}
Ejemplo n.º 3
0
int NaClHostDirOpen(struct NaClHostDir  *d,
                    char                *path) {
  int         fd;
  struct stat stbuf;
  int         rv;

  NaClLog(3, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) d, path);
  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDirOpen: 'this' is NULL\n");
  }

  NaClLog(3, "NaClHostDirOpen: invoking open(%s)\n", path);
  fd = open(path, O_RDONLY);
  NaClLog(3, "NaClHostDirOpen: got DIR* %d\n", fd);
  if (-1 == fd) {
    NaClLog(LOG_ERROR,
            "NaClHostDirOpen: open returned -1, errno %d\n", errno);
    return -NaClXlateErrno(errno);
  }
  /* check that it is really a directory */
  if (-1 == fstat(fd, &stbuf)) {
    NaClLog(LOG_ERROR,
            "NaClHostDirOpen: fstat failed?!?  errno %d\n", errno);
    (void) close(fd);
    return -NaClXlateErrno(errno);
  }
  if (!S_ISDIR(stbuf.st_mode)) {
    (void) close(fd);
    return -NACL_ABI_ENOTDIR;
  }
  rv = NaClHostDirCtor(d, fd);
  return rv;
}
Ejemplo n.º 4
0
int NaClHostDescOpen(struct NaClHostDesc  *d,
                     char const           *path,
                     int                  flags,
                     int                  mode) {
  int         host_desc;
  struct stat stbuf;

  NaClLog(3, "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0x%x, 0x%x)\n",
          (uintptr_t) d, path, flags, mode);
  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
  }
  /*
   * Sanitize access flags.
   */
  if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
    return -NACL_ABI_EINVAL;
  }

  switch (flags & NACL_ABI_O_ACCMODE) {
    case NACL_ABI_O_RDONLY:
    case NACL_ABI_O_WRONLY:
    case NACL_ABI_O_RDWR:
      break;
    default:
      NaClLog(LOG_ERROR,
              "NaClHostDescOpen: bad access flags 0x%x.\n",
              flags);
      return -NACL_ABI_EINVAL;
  }

  flags = NaClMapOpenFlags(flags);
  mode = NaClMapOpenPerm(mode);

  NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
          path, flags, mode);
  host_desc = open(path, flags, mode);
  NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc);
  if (-1 == host_desc) {
    NaClLog(LOG_ERROR,
            "NaClHostDescOpen: open returned -1, errno %d\n", errno);
    return -NaClXlateErrno(errno);
  }
  if (-1 == fstat(host_desc, &stbuf)) {
    NaClLog(LOG_ERROR,
            "NaClHostDescOpen: fstat failed?!?  errno %d\n", errno);
    (void) close(host_desc);
    return -NaClXlateErrno(errno);
  }
  if (!S_ISREG(stbuf.st_mode)) {
    NaClLog(LOG_INFO,
            "NaClHostDescOpen: file type 0x%x, not regular\n", stbuf.st_mode);
    (void) close(host_desc);
    /* cannot access anything other than a real file */
    return -NACL_ABI_EPERM;
  }
//  return NaClHostDescCtor(d, host_desc, NULL); /* d'b ### */
  return NaClHostDescCtor(d, host_desc);
}
Ejemplo n.º 5
0
int NaClClockGetRes(nacl_clockid_t            clk_id,
                    struct nacl_abi_timespec  *res) {
  int             rv = -NACL_ABI_EINVAL;
  struct timespec host_res;
  clockid_t       host_clk_id;

  if (!g_NaClClock_is_initialized) {
    NaClLog(LOG_FATAL,
            "NaClClockGetRes invoked without successful NaClClockInit\n");
  }
  switch (clk_id) {
    case NACL_CLOCK_REALTIME:
      host_clk_id = CLOCK_REALTIME;
      rv = 0;
      break;
    case NACL_CLOCK_MONOTONIC:
      host_clk_id = CLOCK_MONOTONIC;
      rv = 0;
      break;
    case NACL_CLOCK_PROCESS_CPUTIME_ID:
    case NACL_CLOCK_THREAD_CPUTIME_ID:
      rv = -NACL_ABI_EINVAL;
      break;
  }
  if (0 == rv) {
    if (0 != clock_getres(host_clk_id, &host_res)) {
      rv = -NaClXlateErrno(errno);
    }
  }
  if (0 == rv) {
    res->tv_sec = host_res.tv_sec;
    res->tv_nsec = host_res.tv_nsec;
  }
  return rv;
}
Ejemplo n.º 6
0
int NaClHostDescFchdir(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFchdir", d);
  if (-1 == fchdir(d->d)) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
Ejemplo n.º 7
0
/*
 * NaClDescXferableDataDescSendMsg implements imc_sendmsg For
 * data-only descriptors.  We assume that whatever protocol exists at
 * the NaClSendDatagram level is still not thread safe, but that the
 * lack of thread safety will not have a significant impact on
 * security.  This is still somewhat brittle: the low-level Windows
 * IMC code can be convinced to do the wrong thing still via sender
 * races, but the receiver, because it expects zero handles, will have
 * called ReceiveDatagram in such a way that any "received handles"
 * are closed.  This implies that arbitrary Windows handles can be
 * made to be closed, including those not accessible by NaCl modules,
 * but fortunately this should only result in a denial of service as
 * the error caused by the use of an invalid handle is detected by the
 * service runtime and cause an abort.
 *
 * Note that it is still an application error to send or receive data
 * with a transferable data-only descriptor from two threads (or two
 * modules) simultaneously.
 */
static ssize_t
NaClDescXferableDataDescSendMsg(struct NaClDesc                *vself,
                                struct NaClMessageHeader const *dgram,
                                int                            flags) {
  struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
                                           vself);
  int result;

  if (0 != dgram->handle_count) {
    /*
     * A transferable descriptor cannot be used to transfer other
     * descriptors.
     */
    NaClLog(2,
            ("NaClDescXferableDataDescSendMsg: tranferable and"
             " non-zero handle_count\n"));
    return -NACL_ABI_EINVAL;
  }

  result = NaClSendDatagram(self->base.h, dgram, flags);

  if (-1 == result) {
    return -NaClXlateErrno(errno);
  }
  return result;
}
Ejemplo n.º 8
0
int NaClHostDescFsync(struct NaClHostDesc *d) {
  NaClHostDescCheckValidity("NaClHostDescFsync", d);
  if (-1 == fsync(d->d)) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
Ejemplo n.º 9
0
nacl_off64_t NaClHostDescSeek(struct NaClHostDesc  *d,
                              nacl_off64_t         offset,
                              int                  whence) {
  nacl_off64_t retval;

  NaClHostDescCheckValidity("NaClHostDescSeek", d);
#if NACL_LINUX
  return ((-1 == (retval = lseek64(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#elif NACL_OSX
  return ((-1 == (retval = lseek(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#else
# error "What Unix-like OS is this?"
#endif
}
Ejemplo n.º 10
0
int NaClHostDescFchmod(struct NaClHostDesc *d, nacl_abi_mode_t mode) {
  NaClHostDescCheckValidity("NaClHostDescFchmod", d);
  if (-1 == fchmod(d->d, NaClMapMode(mode))) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
Ejemplo n.º 11
0
ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
                          void const          *buf,
                          size_t              len) {
  /*
   * See NaClHostDescPWrite for details for why need_lock is required.
   */
  int need_lock;
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescWrite", d);
  if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    NaClLog(3, "NaClHostDescWrite: RDONLY file\n");
    return -NACL_ABI_EBADF;
  }

  need_lock = NACL_LINUX && (0 != (d->flags & NACL_ABI_O_APPEND));
  /*
   * Grab O_APPEND attribute lock, in case pwrite occurs in another
   * thread.
   */
  if (need_lock) {
    NaClHostDescExclusiveLock(d->d);
  }
  retval = write(d->d, buf, len);
  if (need_lock) {
    NaClHostDescExclusiveUnlock(d->d);
  }
  if (-1 == retval) {
    retval = -NaClXlateErrno(errno);
  }
  return retval;
}
/*
 * NaClDescXferableDataDescLowLevelSendMsg implements imc_sendmsg For
 * data-only descriptors.  We assume that whatever protocol exists at
 * the NaClSendDatagram level is still not thread safe, but that the
 * lack of thread safety will not have a significant impact on
 * security.  This is still somewhat brittle: the low-level Windows
 * IMC code can be convinced to do the wrong thing still via sender
 * races, but the receiver, because it expects zero handles, will have
 * called ReceiveDatagram in such a way that any "received handles"
 * are closed.  This implies that arbitrary Windows handles can be
 * made to be closed, including those not accessible by NaCl modules,
 * but fortunately this should only result in a denial of service as
 * the error caused by the use of an invalid handle is detected by the
 * service runtime and cause an abort.
 *
 * Note that it is still an application error to send or receive data
 * with a transferable data-only descriptor from two threads (or two
 * modules) simultaneously.
 */
static ssize_t
NaClDescXferableDataDescLowLevelSendMsg(struct NaClDesc                *vself,
                                        struct NaClMessageHeader const *dgram,
                                        int                            flags) {
  struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
                                           vself);
  int result;

  if (0 != dgram->handle_count) {
    /*
     * A transferable descriptor cannot be used to transfer other
     * descriptors.
     */
    NaClLog(2,
            ("NaClDescXferableDataDescLowLevelSendMsg: tranferable and"
             " non-zero handle_count\n"));
    return -NACL_ABI_EINVAL;
  }

  result = NaClSendDatagram(self->base.h, dgram, flags);

  if (-1 == result) {
#if NACL_WINDOWS
    return -NaClXlateSystemError(GetLastError());
#elif NACL_LINUX || NACL_OSX
    return -NaClXlateErrno(errno);
#else
# error "Unknown target platform: cannot translate error code(s) from SendMsg"
#endif
  }
  return result;
}
Ejemplo n.º 13
0
int NaClHostDescIsatty(struct NaClHostDesc *d) {
  int retval;

  NaClHostDescCheckValidity("NaClHostDescIsatty", d);
  retval = isatty(d->d);
  /* When isatty fails it returns zero and sets errno. */
  return (0 == retval) ? -NaClXlateErrno(errno) : retval;
}
Ejemplo n.º 14
0
/*
 * This is not a host descriptor function, but is closely related to
 * fstat and should behave similarly.
 */
int NaClHostDescStat(char const *path, nacl_host_stat_t *nhsp) {

  if (NACL_HOST_STAT64(path, nhsp) == -1) {
    return -NaClXlateErrno(errno);
  }

  return 0;
}
Ejemplo n.º 15
0
/*
 * See NaClHostDescStat below.
 */
int NaClHostDescFstat(struct NaClHostDesc  *d,
                      nacl_host_stat_t     *nhsp) {
  NaClHostDescCheckValidity("NaClHostDescFstat", d);
  if (NACL_HOST_FSTAT64(d->d, nhsp) == -1) {
    return -NaClXlateErrno(errno);
  }

  return 0;
}
Ejemplo n.º 16
0
nacl_off64_t NaClHostDescSeek(struct NaClHostDesc  *d,
                              nacl_off64_t         offset,
                              int                  whence) {
  nacl_off64_t retval;

  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDescSeek: 'this' is NULL\n");
  }
#if NACL_LINUX
  return ((-1 == (retval = lseek64(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#elif NACL_OSX
  return ((-1 == (retval = lseek(d->d, offset, whence)))
          ? -NaClXlateErrno(errno) : retval);
#else
# error "What Unix-like OS is this?"
#endif
}
Ejemplo n.º 17
0
ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
                         void                 *buf,
                         size_t               len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescRead", d);
  return ((-1 == (retval = read(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
Ejemplo n.º 18
0
ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
                          void const          *buf,
                          size_t              len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescWrite", d);
  return ((-1 == (retval = write(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
Ejemplo n.º 19
0
int NaClHostDescClose(struct NaClHostDesc *d) {
  int retval;

  NaClHostDescCheckValidity("NaClHostDescClose", d);
  retval = close(d->d);
  if (-1 != retval) {
    d->d = -1;
  }
  return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
}
Ejemplo n.º 20
0
static ssize_t NaClStreamDirents(struct NaClHostDir *d,
                                 void               *buf,
                                 size_t             len) {
  ssize_t retval;
  size_t  xferred = 0;
  ssize_t entry_size;

  NaClXMutexLock(&d->mu);
  while (len > 0) {
    NaClLog(4, "NaClStreamDirents: loop, xferred = %"NACL_PRIuS"\n", xferred);
    entry_size = NaClCopyDirent(d, buf, len);
    if (0 == entry_size) {
      CHECK(d->cur_byte == d->nbytes);
      retval = getdents(d->fd,
                        (struct dirent *) d->dirent_buf,
                        sizeof d->dirent_buf);
      if (-1 == retval) {
        if (xferred > 0) {
          /* next time through, we'll pick up the error again */
          goto cleanup;
        } else {
          xferred = -NaClXlateErrno(errno);
          goto cleanup;
        }
      } else if (0 == retval) {
        goto cleanup;
      }
      d->cur_byte = 0;
      d->nbytes = retval;
    } else if (entry_size < 0) {
      /*
       * The only error return from NaClCopyDirent is NACL_ABI_EINVAL
       * due to destinaton buffer too small for the current entry.  If
       * we had copied some entries before, we were successful;
       * otherwise report that the buffer is too small for the next
       * directory entry.
       */
      if (xferred > 0) {
        goto cleanup;
      } else {
        xferred = entry_size;
        goto cleanup;
      }
    }
    /* entry_size > 0, maybe copy another */
    buf = (void *) ((char *) buf + entry_size);
    CHECK(len >= (size_t) entry_size);
    len -= entry_size;
    xferred += entry_size;
  }
  /* perfect fit! */
 cleanup:
  NaClXMutexUnlock(&d->mu);
  return xferred;
}
Ejemplo n.º 21
0
int NaClHostDirClose(struct NaClHostDir *d) {
  int retval;

  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDirClose: 'this' is NULL\n");
  }
  NaClLog(3, "NaClHostDirClose(%d)\n", d->fd);
  retval = close(d->fd);
  d->fd = -1;
  return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
}
Ejemplo n.º 22
0
ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
                          void const          *buf,
                          size_t              len) {
  ssize_t retval;

  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDescWrite: 'this' is NULL\n");
  }
  return ((-1 == (retval = write(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
Ejemplo n.º 23
0
int NaClHostDescUnmapUnsafe(void    *start_addr,
                            size_t  len) {
  int       retval;
  uintptr_t addr;

  addr = (uintptr_t) start_addr;

  return ((-1 == (retval = munmap(start_addr, len)))
          ? -NaClXlateErrno(errno)
          : retval);
}
Ejemplo n.º 24
0
int NaClHostDescClose(struct NaClHostDesc *d) {
  int retval;

  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDescClose: 'this' is NULL\n");
  }
  retval = close(d->d);
  if (-1 != retval) {
    d->d = -1;
  }
  return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
}
Ejemplo n.º 25
0
int NaClHostDirClose(struct NaClHostDir *d) {
  int retval;

  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDirClose: 'this' is NULL\n");
  }
  NaClLog(3, "NaClHostDirClose(0x%08"NACL_PRIxPTR")\n", (uintptr_t) d->dirp);
  retval = closedir(d->dirp);
  if (-1 != retval) {
    d->dirp = NULL;
  }
  return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
}
Ejemplo n.º 26
0
ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
                         void                 *buf,
                         size_t               len) {
  ssize_t retval;

  NaClHostDescCheckValidity("NaClHostDescRead", d);
  if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    NaClLog(3, "NaClHostDescRead: WRONLY file\n");
    return -NACL_ABI_EBADF;
  }
  return ((-1 == (retval = read(d->d, buf, len)))
          ? -NaClXlateErrno(errno) : retval);
}
Ejemplo n.º 27
0
int NaClHostDescUtimes(const char *filename,
                       const struct nacl_abi_timeval *times) {
  struct timeval host_times[2];
  if (times != NULL) {
    host_times[0].tv_sec = times[0].nacl_abi_tv_sec;
    host_times[0].tv_usec = times[0].nacl_abi_tv_usec;
    host_times[1].tv_sec = times[1].nacl_abi_tv_sec;
    host_times[1].tv_usec = times[1].nacl_abi_tv_usec;
  }
  if (-1 == utimes(filename, (times != NULL ? host_times : NULL))) {
    return -NaClXlateErrno(errno);
  }
  return 0;
}
Ejemplo n.º 28
0
/*
 * In the level of NaClDescImcDescSendMsg, we do not know what
 * protocol is implemented by NaClSendDatagram (and indeed, in the
 * Windows implementation, the access rights transfer involves a more
 * complex protocol to get the peer process id).  Because the
 * underlying low-level IMC implementation does not provide thread
 * safety, this is the source of race conditions: two simultaneous
 * imc_sendmsg syscalls to the same descriptor could get their various
 * protcol bits interleaved, so the receiver will get garbled data
 * that cause the wrong underlying host OS descriptor to be made
 * available to the NaCl module.
 *
 * In order to address this issue, we (1) make descriptors that can
 * transfer other descriptors non-transferable, and (2) we use locking
 * so that only one thread can be performing (the low level bits of)
 * imc_msgsend at a time.  The non-transferability of such descriptors
 * addresses the multi-module scenario, as opposed to the
 * multi-threaded scenario, where a sender race cause receiver
 * confusion.
 */
static ssize_t NaClDescImcDescSendMsg(struct NaClDesc                *vself,
                                      struct NaClMessageHeader const *dgram,
                               int                            flags) {
  struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
                                  vself);
  int result;

  NaClXMutexLock(&self->sendmsg_mu);
  result = NaClSendDatagram(self->base.h, dgram, flags);
  NaClXMutexUnlock(&self->sendmsg_mu);

  if (-1 == result) {
    return -NaClXlateErrno(errno);
  }
  return result;
}
Ejemplo n.º 29
0
int NaClHostDescUnmap(void    *start_addr,
                      size_t  len) {
  int       retval;
  uintptr_t addr;

  addr = (uintptr_t) start_addr;

  return ((-1 == (retval = (uintptr_t) mmap(start_addr,
                                            len,
                                            PROT_NONE,
                                            (MAP_PRIVATE
                                             | MAP_ANONYMOUS | MAP_FIXED),
                                            -1,
                                            (nacl_off64_t) 0)))
          ? -NaClXlateErrno(errno) : retval);
}
Ejemplo n.º 30
0
int NaClHostDescOpen(struct NaClHostDesc  *d,
                     char const           *path,
                     int                  flags,
                     int                  mode) {
  int host_desc;
  int posix_flags;

  NaClLog(3, "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0x%x, 0x%x)\n",
          (uintptr_t) d, path, flags, mode);
  if (NULL == d) {
    NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
  }
  /*
   * Sanitize access flags.
   */
  if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
    return -NACL_ABI_EINVAL;
  }

  switch (flags & NACL_ABI_O_ACCMODE) {
    case NACL_ABI_O_RDONLY:
    case NACL_ABI_O_WRONLY:
    case NACL_ABI_O_RDWR:
      break;
    default:
      NaClLog(LOG_ERROR,
              "NaClHostDescOpen: bad access flags 0x%x.\n",
              flags);
      return -NACL_ABI_EINVAL;
  }

  posix_flags = NaClMapOpenFlags(flags);
#if NACL_LINUX
  posix_flags |= O_LARGEFILE;
#endif
  mode = NaClMapOpenPerm(mode);

  NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
          path, posix_flags, mode);
  host_desc = open(path, posix_flags, mode);
  NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc);
  if (-1 == host_desc) {
    NaClLog(2, "NaClHostDescOpen: open returned -1, errno %d\n", errno);
    return -NaClXlateErrno(errno);
  }
  return NaClHostDescCtor(d, host_desc, flags);
}