Example #1
0
int32_t NaClSysFstat(struct NaClAppThread *natp,
                     int                  d,
                     uint32_t             nasp) {
  struct NaClApp        *nap = natp->nap;
  int32_t               retval = -NACL_ABI_EINVAL;
  struct NaClDesc       *ndp;
  struct nacl_abi_stat  result;

  NaClLog(3,
          ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
           ", %d, 0x%08"NACL_PRIx32")\n"),
          (uintptr_t) natp, d, nasp);

  ndp = NaClAppGetDesc(nap, d);
  if (NULL == ndp) {
    NaClLog(4, "bad desc\n");
    retval = -NACL_ABI_EBADF;
    goto cleanup;
  }

  retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
            Fstat)(ndp, &result);
  if (0 == retval) {
    if (!NaClFileAccessEnabled()) {
      result.nacl_abi_st_ino = NACL_FAKE_INODE_NUM;
    }
    if (!NaClCopyOutToUser(nap, nasp, &result, sizeof result)) {
      retval = -NACL_ABI_EFAULT;
    }
  }

  NaClDescUnref(ndp);
cleanup:
  return retval;
}
Example #2
0
int32_t NaClSysGetcwd(struct NaClAppThread *natp,
                      uint32_t             buffer,
                      int                  len) {
  struct NaClApp *nap = natp->nap;
  int32_t        retval = -NACL_ABI_EINVAL;
  char           path[NACL_CONFIG_PATH_MAX];

  if (!NaClAclBypassChecks) {
    retval = -NACL_ABI_EACCES;
    goto cleanup;
  }

  if (len >= NACL_CONFIG_PATH_MAX)
    len = NACL_CONFIG_PATH_MAX - 1;

  retval = NaClHostDescGetcwd(path, len);
  if (retval != 0)
    goto cleanup;

  if (!NaClCopyOutToUser(nap, buffer, &path, strlen(path) + 1))
    retval = -NACL_ABI_EFAULT;

cleanup:
  return retval;
}
Example #3
0
int32_t NaClSysLstat(struct NaClAppThread  *natp,
                     uint32_t              pathname,
                     uint32_t              nasp) {
  struct NaClApp      *nap = natp->nap;
  int32_t             retval = -NACL_ABI_EINVAL;
  char                path[NACL_CONFIG_PATH_MAX];
  nacl_host_stat_t    stbuf;

  NaClLog(3,
          ("Entered NaClSysLstat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIx32","
           " 0x%08"NACL_PRIx32")\n"), (uintptr_t) natp, pathname, nasp);

  if (!NaClAclBypassChecks) {
    return -NACL_ABI_EACCES;
  }

  retval = CopyPathFromUser(nap, path, sizeof path, pathname);
  if (0 != retval)
    return retval;

  /*
   * Perform a host stat.
   */
  retval = NaClHostDescLstat(path, &stbuf);
  if (0 == retval) {
    struct nacl_abi_stat abi_stbuf;

    retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf);
    if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) {
      return -NACL_ABI_EFAULT;
    }
  }
  return retval;
}
Example #4
0
int32_t NaClSysImcMakeBoundSock(struct NaClAppThread *natp,
                                uint32_t             descs_addr) {
    /*
     * Create a bound socket descriptor and a socket address descriptor.
     */
    struct NaClApp              *nap = natp->nap;
    int32_t                     retval = -NACL_ABI_EINVAL;
    struct NaClDesc             *pair[2];
    int32_t                     usr_pair[2];

    /* This syscall is not used in Chromium so is disabled by default. */
    if (!NaClAclBypassChecks) {
        return -NACL_ABI_EACCES;
    }

    NaClLog(3,
            ("Entered NaClSysImcMakeBoundSock(0x%08"NACL_PRIxPTR","
             " 0x%08"NACL_PRIx32")\n"),
            (uintptr_t) natp, descs_addr);

    retval = NaClCommonDescMakeBoundSock(pair);
    if (0 != retval) {
        goto cleanup;
    }

    usr_pair[0] = NaClAppSetDescAvail(nap, pair[0]);
    usr_pair[1] = NaClAppSetDescAvail(nap, pair[1]);
    if (!NaClCopyOutToUser(nap, descs_addr, usr_pair, sizeof usr_pair)) {
        /*
         * NB: The descriptors were briefly observable to untrusted code
         * in this window, even though the syscall had not returned yet,
         * and another thread which guesses their numbers could actually
         * use them, so the NaClDescSafeUnref inside NaClAppSetDesc below
         * might not actually deallocate right away.  To avoid this, we
         * could grab the descriptor lock and hold it until after the
         * copyout is done, but that imposes an ordering between the
         * descriptor lock and the VM lock which can cause problems
         * elsewhere.
         */
        NaClAppSetDesc(nap, usr_pair[0], NULL);
        NaClAppSetDesc(nap, usr_pair[1], NULL);
        retval = -NACL_ABI_EFAULT;
        goto cleanup;
    }

    retval = 0;

cleanup:
    return retval;
}
Example #5
0
/*
 * This implements 64-bit offsets, so we use |offp| as an in/out
 * address so we can have a 64 bit return value.
 */
int32_t NaClSysLseek(struct NaClAppThread *natp,
                     int                  d,
                     uint32_t             offp,
                     int                  whence) {
  struct NaClApp  *nap = natp->nap;
  nacl_abi_off_t  offset;
  nacl_off64_t    retval64;
  int32_t         retval = -NACL_ABI_EINVAL;
  struct NaClDesc *ndp;

  NaClLog(3,
          ("Entered NaClSysLseek(0x%08"NACL_PRIxPTR", %d,"
           " 0x%08"NACL_PRIx32", %d)\n"),
          (uintptr_t) natp, d, offp, whence);

  ndp = NaClAppGetDesc(nap, d);
  if (NULL == ndp) {
    retval = -NACL_ABI_EBADF;
    goto cleanup;
  }

  if (!NaClCopyInFromUser(nap, &offset, offp, sizeof offset)) {
    retval = -NACL_ABI_EFAULT;
    goto cleanup_unref;
  }
  NaClLog(4, "offset 0x%08"NACL_PRIx64"\n", (uint64_t) offset);

  retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
              Seek)(ndp, (nacl_off64_t) offset, whence);
  if (NaClOff64IsNegErrno(&retval64)) {
    retval = (int32_t) retval64;
  } else {
    if (NaClCopyOutToUser(nap, offp, &retval64, sizeof retval64)) {
      retval = 0;
    } else {
      NaClLog(LOG_FATAL,
              "NaClSysLseek: in/out ptr became invalid at copyout?\n");
    }
  }
cleanup_unref:
  NaClDescUnref(ndp);
cleanup:
  return retval;
}
Example #6
0
int32_t NaClSysReadlink(struct NaClAppThread *natp,
                        uint32_t             path,
                        uint32_t             buffer,
                        uint32_t             buffer_size) {
  struct NaClApp *nap = natp->nap;
  char           pathname[NACL_CONFIG_PATH_MAX];
  char           realpath[NACL_CONFIG_PATH_MAX];
  int32_t        retval = -NACL_ABI_EINVAL;
  uint32_t       result_size;

  if (!NaClAclBypassChecks)
    return -NACL_ABI_EACCES;

  retval = CopyPathFromUser(nap, pathname, sizeof pathname, path);
  if (0 != retval)
    return retval;

  retval = NaClHostDescReadlink(pathname, realpath, sizeof(realpath));
  if (retval < 0)
    return retval;
  result_size = retval;
  CHECK(result_size <= sizeof(realpath));  /* Sanity check */

  if (result_size == sizeof(realpath)) {
    /*
     * The result either got truncated or it fit exactly.  Treat it as
     * truncation.
     *
     * We can't distinguish an exact fit from truncation without doing
     * another readlink() call.  If result_size == buffer_size, we could
     * return success here, but there's little point, because untrusted
     * code can't distinguish the two either and we don't currently allow
     * using a larger buffer.
     */
    return -NACL_ABI_ENAMETOOLONG;
  }

  if (result_size > buffer_size)
    result_size = buffer_size;
  if (!NaClCopyOutToUser(nap, buffer, realpath, result_size))
    return -NACL_ABI_EFAULT;

  return result_size;
}
int32_t NaClSysExceptionHandler(struct NaClAppThread *natp,
                                uint32_t             handler_addr,
                                uint32_t             old_handler) {
  struct NaClApp *nap = natp->nap;
  int32_t rv = -NACL_ABI_EINVAL;

  if (!nap->enable_exception_handling) {
    rv = -NACL_ABI_ENOSYS;
    goto no_lock_exit;
  }
  if (!NaClIsValidJumpTarget(nap, handler_addr)) {
    rv = -NACL_ABI_EFAULT;
    goto no_lock_exit;
  }
  NaClXMutexLock(&nap->exception_mu);

  /*
   * This needs to be done while holding the lock so that we don't
   * start two Windows debug exception handlers.
   */
  if (handler_addr != 0) {
    if (!NaClDebugExceptionHandlerEnsureAttached(nap)) {
      rv = -NACL_ABI_ENOSYS;
      goto unlock_exit;
    }
  }

  if (0 != old_handler &&
      !NaClCopyOutToUser(nap, (uintptr_t) old_handler,
                         &nap->exception_handler,
                         sizeof nap->exception_handler)) {
    rv = -NACL_ABI_EFAULT;
    goto unlock_exit;
  }
  nap->exception_handler = handler_addr;
  rv = 0;
 unlock_exit:
  NaClXMutexUnlock(&nap->exception_mu);
 no_lock_exit:
  return rv;
}
int32_t NaClSysStat(struct NaClAppThread  *natp,
                    const char            *pathname,
                    struct nacl_abi_stat  *buf) {
  struct NaClApp      *nap = natp->nap;
  int32_t             retval = -NACL_ABI_EINVAL;
  char                path[NACL_CONFIG_PATH_MAX];
  nacl_host_stat_t    stbuf;

  NaClLog(3,
          ("Entered NaClSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
           " 0x%08"NACL_PRIxPTR")\n"),
          (uintptr_t) natp, (uintptr_t) pathname, (uintptr_t) buf);

  retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname);
  if (0 != retval)
    goto cleanup;

  retval = NaClStatAclCheck(nap, path);
  if (0 != retval)
    goto cleanup;

  /*
   * Perform a host stat.
   */
  retval = NaClHostDescStat(path, &stbuf);
  if (0 == retval) {
    struct nacl_abi_stat abi_stbuf;

    retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf,
                                              &stbuf);
    if (!NaClCopyOutToUser(nap, (uintptr_t) buf,
                           &abi_stbuf, sizeof abi_stbuf)) {
      retval = -NACL_ABI_EFAULT;
    }
  }
cleanup:
  return retval;
}
Example #9
0
int32_t NaClSysImcSocketPair(struct NaClAppThread *natp,
                             uint32_t             descs_out) {
    struct NaClApp          *nap = natp->nap;
    int32_t                 usr_pair[2];
    struct NaClDesc         *pair[2];
    int32_t                 retval;

    NaClLog(3,
            ("Entered NaClSysImcSocketPair(0x%08"NACL_PRIxPTR
             " 0x%08"NACL_PRIx32")\n"),
            (uintptr_t) natp, descs_out);

    /* This syscall is not used in Chromium so is disabled by default. */
    if (!NaClAclBypassChecks) {
        return -NACL_ABI_EACCES;
    }

    retval = NaClCommonDescSocketPair(pair);
    if (0 != retval) {
        goto cleanup;
    }

    usr_pair[0] = NaClAppSetDescAvail(nap, pair[0]);
    usr_pair[1] = NaClAppSetDescAvail(nap, pair[1]);

    if (!NaClCopyOutToUser(nap, (uintptr_t) descs_out, usr_pair,
                           sizeof usr_pair)) {
        NaClAppSetDesc(nap, usr_pair[0], NULL);
        NaClAppSetDesc(nap, usr_pair[1], NULL);
        retval = -NACL_ABI_EFAULT;
        goto cleanup;
    }
    retval = 0;

cleanup:
    return retval;
}
Example #10
0
int32_t NaClSysImcRecvmsg(struct NaClAppThread *natp,
                          int                  d,
                          uint32_t             nanimhp,
                          int                  flags) {
    struct NaClApp                        *nap = natp->nap;
    int32_t                               retval = -NACL_ABI_EINVAL;
    ssize_t                               ssize_retval;
    uintptr_t                             sysaddr;
    size_t                                i;
    struct NaClDesc                       *ndp;
    struct NaClAbiNaClImcMsgHdr           kern_nanimh;
    struct NaClAbiNaClImcMsgIoVec         kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
    struct NaClImcMsgIoVec                kern_iov[NACL_ABI_IMC_IOVEC_MAX];
    int32_t                               usr_desc[NACL_ABI_IMC_USER_DESC_MAX];
    struct NaClImcTypedMsgHdr             recv_hdr;
    struct NaClDesc                       *new_desc[NACL_ABI_IMC_DESC_MAX];
    nacl_abi_size_t                       num_user_desc;
    struct NaClDesc                       *invalid_desc = NULL;

    NaClLog(3,
            ("Entered NaClSysImcRecvMsg(0x%08"NACL_PRIxPTR", %d,"
             " 0x%08"NACL_PRIx32")\n"),
            (uintptr_t) natp, d, nanimhp);

    /*
     * First, we validate user-supplied message headers before
     * allocating a receive buffer.
     */
    if (!NaClCopyInFromUser(nap, &kern_nanimh, nanimhp, sizeof kern_nanimh)) {
        NaClLog(4, "NaClImcMsgHdr not in user address space\n");
        retval = -NACL_ABI_EFAULT;
        goto cleanup_leave;
    }
    /* copy before validating */

    if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
        NaClLog(4, "gather/scatter array too large: %"NACL_PRIdNACL_SIZE"\n",
                kern_nanimh.iov_length);
        retval = -NACL_ABI_EINVAL;
        goto cleanup_leave;
    }
    if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
        NaClLog(4, "handle vector too long: %"NACL_PRIdNACL_SIZE"\n",
                kern_nanimh.desc_length);
        retval = -NACL_ABI_EINVAL;
        goto cleanup_leave;
    }

    if (kern_nanimh.iov_length > 0) {
        /*
         * Copy IOV array into kernel space.  Validate this snapshot and do
         * user->kernel address conversions on this snapshot.
         */
        if (!NaClCopyInFromUser(nap, kern_naiov, (uintptr_t) kern_nanimh.iov,
                                (kern_nanimh.iov_length * sizeof kern_naiov[0]))) {
            NaClLog(4, "gather/scatter array not in user address space\n");
            retval = -NACL_ABI_EFAULT;
            goto cleanup_leave;
        }
        /*
         * Convert every IOV base from user to system address, validate
         * range of bytes are really in user address space.
         */

        for (i = 0; i < kern_nanimh.iov_length; ++i) {
            sysaddr = NaClUserToSysAddrRange(nap,
                                             (uintptr_t) kern_naiov[i].base,
                                             kern_naiov[i].length);
            if (kNaClBadAddress == sysaddr) {
                NaClLog(4, "iov number %"NACL_PRIuS" not entirely in user space\n", i);
                retval = -NACL_ABI_EFAULT;
                goto cleanup_leave;
            }
            kern_iov[i].base = (void *) sysaddr;
            kern_iov[i].length = kern_naiov[i].length;
        }
    }

    if (kern_nanimh.desc_length > 0) {
        sysaddr = NaClUserToSysAddrRange(nap,
                                         (uintptr_t) kern_nanimh.descv,
                                         kern_nanimh.desc_length * sizeof(int32_t));
        if (kNaClBadAddress == sysaddr) {
            retval = -NACL_ABI_EFAULT;
            goto cleanup_leave;
        }
    }

    ndp = NaClAppGetDesc(nap, d);
    if (NULL == ndp) {
        NaClLog(4, "receiving descriptor invalid\n");
        retval = -NACL_ABI_EBADF;
        goto cleanup_leave;
    }

    recv_hdr.iov = kern_iov;
    recv_hdr.iov_length = kern_nanimh.iov_length;

    recv_hdr.ndescv = new_desc;
    recv_hdr.ndesc_length = NACL_ARRAY_SIZE(new_desc);
    memset(new_desc, 0, sizeof new_desc);

    recv_hdr.flags = 0;  /* just to make it obvious; IMC will clear it for us */

    /* lock user memory ranges in kern_naiov */
    for (i = 0; i < kern_nanimh.iov_length; ++i) {
        NaClVmIoWillStart(nap,
                          kern_naiov[i].base,
                          kern_naiov[i].base + kern_naiov[i].length - 1);
    }
    ssize_retval = NACL_VTBL(NaClDesc, ndp)->RecvMsg(ndp, &recv_hdr, flags);
    /* unlock user memory ranges in kern_naiov */
    for (i = 0; i < kern_nanimh.iov_length; ++i) {
        NaClVmIoHasEnded(nap,
                         kern_naiov[i].base,
                         kern_naiov[i].base + kern_naiov[i].length - 1);
    }
    /*
     * retval is number of user payload bytes received and excludes the
     * header bytes.
     */
    NaClLog(3, "NaClSysImcRecvMsg: RecvMsg() returned %"NACL_PRIdS"\n",
            ssize_retval);
    if (NaClSSizeIsNegErrno(&ssize_retval)) {
        /* negative error numbers all have valid 32-bit representations,
         * so this cast is safe. */
        retval = (int32_t) ssize_retval;
        goto cleanup;
    } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
        retval = -NACL_ABI_EOVERFLOW;
        goto cleanup;
    } else {
        /* cast is safe due to range check above */
        retval = (int32_t) ssize_retval;
    }

    /*
     * NB: recv_hdr.flags may contain NACL_ABI_MESSAGE_TRUNCATED and/or
     * NACL_ABI_HANDLES_TRUNCATED.
     */

    kern_nanimh.flags = recv_hdr.flags;

    /*
     * Now internalize the NaClHandles as NaClDesc objects.
     */
    num_user_desc = recv_hdr.ndesc_length;

    if (kern_nanimh.desc_length < num_user_desc) {
        kern_nanimh.flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
        for (i = kern_nanimh.desc_length; i < num_user_desc; ++i) {
            NaClDescUnref(new_desc[i]);
            new_desc[i] = NULL;
        }
        num_user_desc = kern_nanimh.desc_length;
    }

    invalid_desc = (struct NaClDesc *) NaClDescInvalidMake();
    /* prepare to write out to user space the descriptor numbers */
    for (i = 0; i < num_user_desc; ++i) {
        if (invalid_desc == new_desc[i]) {
            usr_desc[i] = kKnownInvalidDescNumber;
            NaClDescUnref(new_desc[i]);
        } else {
            usr_desc[i] = NaClAppSetDescAvail(nap, new_desc[i]);
        }
        new_desc[i] = NULL;
    }
    if (0 != num_user_desc &&
            !NaClCopyOutToUser(nap, (uintptr_t) kern_nanimh.descv, usr_desc,
                               num_user_desc * sizeof usr_desc[0])) {
        NaClLog(LOG_FATAL,
                ("NaClSysImcRecvMsg: in/out ptr (descv %"NACL_PRIxPTR
                 ") became invalid at copyout?\n"),
                (uintptr_t) kern_nanimh.descv);
    }

    kern_nanimh.desc_length = num_user_desc;
    if (!NaClCopyOutToUser(nap, nanimhp, &kern_nanimh, sizeof kern_nanimh)) {
        NaClLog(LOG_FATAL,
                "NaClSysImcRecvMsg: in/out ptr (iov) became"
                " invalid at copyout?\n");
    }
    /* copy out updated desc count, flags */
cleanup:
    if (retval < 0) {
        for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
            if (NULL != new_desc[i]) {
                NaClDescUnref(new_desc[i]);
                new_desc[i] = NULL;
            }
        }
    }
    NaClDescUnref(ndp);
    NaClDescSafeUnref(invalid_desc);
    NaClLog(3, "NaClSysImcRecvMsg: returning %d\n", retval);
cleanup_leave:
    return retval;
}