static void NaClKernelServiceCreateProcessRpc( struct NaClSrpcRpc *rpc, struct NaClSrpcArg **in_args, struct NaClSrpcArg **out_args, struct NaClSrpcClosure *done_cls) { struct NaClKernelService *nksp = (struct NaClKernelService *) rpc->channel->server_instance_data; int status; struct NaClDesc *sock_addr = NULL; struct NaClDesc *app_addr = NULL; UNREFERENCED_PARAMETER(in_args); NaClLog(4, "NaClKernelServiceCreateProcessRpc: creating process\n"); status = (*NACL_VTBL(NaClKernelService, nksp)->CreateProcess)( nksp, &sock_addr, &app_addr); out_args[0]->u.ival = status; out_args[1]->u.hval = (0 == status) ? sock_addr : (struct NaClDesc *) NaClDescInvalidMake(); out_args[2]->u.hval = (0 == status) ? app_addr : (struct NaClDesc *) NaClDescInvalidMake(); NaClLog(4, ("NaClKernelServiceCreateProcessRpc: status %d, sock_addr" " 0x08%"NACL_PRIxPTR", app_addr 0x%08"NACL_PRIxPTR"\n"), status, (uintptr_t) sock_addr, (uintptr_t) app_addr); rpc->result = NACL_SRPC_RESULT_OK; (*done_cls->Run)(done_cls); if (0 == status) { NaClDescUnref(sock_addr); NaClDescUnref(app_addr); } }
static void NaClReverseServiceCreateProcessRpc( struct NaClSrpcRpc *rpc, struct NaClSrpcArg **in_args, struct NaClSrpcArg **out_args, struct NaClSrpcClosure *done_cls) { struct NaClReverseService *nrsp = (struct NaClReverseService *) rpc->channel->server_instance_data; struct NaClDesc *sock_addr; struct NaClDesc *app_addr; int status; UNREFERENCED_PARAMETER(in_args); NaClLog(4, "Entered NaClReverseServiceCreateProcessRpc: 0x%08"NACL_PRIxPTR"\n", (uintptr_t) nrsp); status = (*NACL_VTBL(NaClReverseInterface, nrsp->iface)-> CreateProcess)(nrsp->iface, &sock_addr, &app_addr); out_args[0]->u.ival = status; out_args[1]->u.hval = (0 == status) ? sock_addr : (struct NaClDesc *) NaClDescInvalidMake(); out_args[2]->u.hval = (0 == status) ? app_addr : (struct NaClDesc *) NaClDescInvalidMake(); NaClLog(4, "Leaving NaClReverseServiceCreateProcessRpc\n"); rpc->result = NACL_SRPC_RESULT_OK; (*done_cls->Run)(done_cls); }
static void NaClNameServiceNameLookupRpc( struct NaClSrpcRpc *rpc, struct NaClSrpcArg **in_args, struct NaClSrpcArg **out_args, struct NaClSrpcClosure *done_cls) { struct NaClNameService *nnsp = (struct NaClNameService *) rpc->channel->server_instance_data; char *name = in_args[0]->arrays.str; int flags = in_args[1]->u.ival; int status; struct NaClDesc *desc; NaClLog(3, "NaClNameServiceNameLookupRpc: looking up %s\n", name); NaClLog(3, "NaClNameServiceNameLookupRpc: flags %d (0x%x)\n", flags, flags); status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)( nnsp, name, flags, &desc); out_args[0]->u.ival = status; out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status) ? desc : (struct NaClDesc *) NaClDescInvalidMake(); NaClLog(3, "NaClNameServiceNameLookupRpc: status %d\n", status); NaClLog(3, "NaClNameServiceNameLookupRpc: desc 0x%"NACL_PRIxPTR"\n", (uintptr_t) desc); rpc->result = NACL_SRPC_RESULT_OK; (*done_cls->Run)(done_cls); }
static void CreateProcessFunctor(void *functor_state, struct NaClDesc *sock_addr, struct NaClDesc *app_addr, int32_t pid) { struct CreateProcessFunctorState *state = (struct CreateProcessFunctorState *) functor_state; if (NULL == sock_addr) { sock_addr = (struct NaClDesc *) NaClDescInvalidMake(); } if (NULL == app_addr) { app_addr = (struct NaClDesc *) NaClDescInvalidMake(); } *state->out_sock_addr = sock_addr; *state->out_app_addr = app_addr; *state->out_pid = pid; (*state->cls->Run)(state->cls); }
int NaClDescInvalidInternalize(struct NaClDesc **baseptr, struct NaClDescXferState *xfer) { UNREFERENCED_PARAMETER(xfer); *baseptr = (struct NaClDesc *) NaClDescInvalidMake(); return 0; }
/* * Look up by string name, resulting in a handle (if name is in the * preimage), a object proxy handle, and an error code. */ static void NaClReverseServiceManifestLookupRpc( struct NaClSrpcRpc *rpc, struct NaClSrpcArg **in_args, struct NaClSrpcArg **out_args, struct NaClSrpcClosure *done_cls) { struct NaClReverseService *nrsp = (struct NaClReverseService *) rpc->channel->server_instance_data; char *url_key = in_args[0]->arrays.str; int flags = in_args[0]->u.ival; struct NaClFileInfo info; struct NaClHostDesc *host_desc; struct NaClDescIoDesc *io_desc = NULL; struct NaClDesc *nacl_desc = NULL; memset(&info, 0, sizeof(info)); NaClLog(4, "Entered ManifestLookupRpc: 0x%08"NACL_PRIxPTR", %s, %d\n", (uintptr_t) nrsp, url_key, flags); NaClLog(4, "ManifestLookupRpc: invoking OpenManifestEntry\n"); if (!(*NACL_VTBL(NaClReverseInterface, nrsp->iface)-> OpenManifestEntry)(nrsp->iface, url_key, &info) || -1 == info.desc) { NaClLog(1, "ManifestLookupRpc: OpenManifestEntry failed.\n"); out_args[0]->u.ival = NACL_ABI_ENOENT; /* failed */ out_args[1]->u.hval = (struct NaClDesc *) NaClDescInvalidMake(); out_args[2]->u.lval = 0; out_args[3]->u.lval = 0; out_args[4]->u.count = 0; goto done; } NaClLog(4, "ManifestLookupRpc: OpenManifestEntry returned desc %d.\n", info.desc); host_desc = (struct NaClHostDesc *) malloc(sizeof *host_desc); CHECK(host_desc != NULL); CHECK(NaClHostDescPosixTake(host_desc, info.desc, NACL_ABI_O_RDONLY) == 0); io_desc = NaClDescIoDescMake(host_desc); CHECK(io_desc != NULL); nacl_desc = (struct NaClDesc *) io_desc; out_args[0]->u.ival = 0; /* OK */ out_args[1]->u.hval = nacl_desc; out_args[2]->u.lval = (int64_t) info.file_token.lo; out_args[3]->u.lval = (int64_t) info.file_token.hi; out_args[4]->u.count = 10; strncpy(out_args[4]->arrays.carr, "123456789", 10); /* * TODO(phosek): the array should be an object reference (issue 3035). */ done: rpc->result = NACL_SRPC_RESULT_OK; (*done_cls->Run)(done_cls); NaClDescSafeUnref((struct NaClDesc *) io_desc); }
static void NaClNameServiceNameLookupOldRpc( struct NaClSrpcRpc *rpc, struct NaClSrpcArg **in_args, struct NaClSrpcArg **out_args, struct NaClSrpcClosure *done_cls) { struct NaClNameService *nnsp = (struct NaClNameService *) rpc->channel->server_instance_data; char *name = in_args[0]->arrays.str; int status; struct NaClDesc *desc; NaClLog(LOG_WARNING, "NaClNameServiceNameLookupOldRpc: DEPRECATED interface used.\n"); NaClLog(3, "NaClNameServiceNameLookupOldRpc: looking up %s\n", name); status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)( nnsp, name, NACL_ABI_O_RDONLY, &desc); out_args[0]->u.ival = status; out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status) ? desc : (struct NaClDesc *) NaClDescInvalidMake(); rpc->result = NACL_SRPC_RESULT_OK; (*done_cls->Run)(done_cls); }
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; }
/* * This function converts addresses from user addresses to system * addresses, copying into kernel space as needed to avoid TOCvTOU * races, then invokes the descriptor's SendMsg() method. */ int32_t NaClSysImcSendmsg(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; /* copy of user-space data for validation */ 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]; /* kernel-side representatin of descriptors */ struct NaClDesc *kern_desc[NACL_ABI_IMC_USER_DESC_MAX]; struct NaClImcTypedMsgHdr kern_msg_hdr; struct NaClDesc *ndp; size_t i; NaClLog(3, ("Entered NaClSysImcSendmsg(0x%08"NACL_PRIxPTR", %d," " 0x%08"NACL_PRIx32", 0x%x)\n"), (uintptr_t) natp, d, nanimhp, flags); 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 contents */ /* * Some of these checks duplicate checks that will be done in the * nrd xfer library, but it is better to check before doing the * address translation of memory/descriptor vectors if those vectors * might be too long. Plus, we need to copy and validate vectors * for TOCvTOU race protection, and we must prevent overflows. The * nrd xfer library's checks should never fire when called from the * service runtime, but the nrd xfer library might be called from * other code. */ if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) { NaClLog(4, "gather/scatter array too large\n"); retval = -NACL_ABI_EINVAL; goto cleanup_leave; } if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) { NaClLog(4, "handle vector too long\n"); retval = -NACL_ABI_EINVAL; goto cleanup_leave; } if (kern_nanimh.iov_length > 0) { 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; } 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) { retval = -NACL_ABI_EFAULT; goto cleanup_leave; } kern_iov[i].base = (void *) sysaddr; kern_iov[i].length = kern_naiov[i].length; } } ndp = NaClAppGetDesc(nap, d); if (NULL == ndp) { retval = -NACL_ABI_EBADF; goto cleanup_leave; } /* * make things easier for cleaup exit processing */ memset(kern_desc, 0, sizeof kern_desc); retval = -NACL_ABI_EINVAL; kern_msg_hdr.iov = kern_iov; kern_msg_hdr.iov_length = kern_nanimh.iov_length; if (0 == kern_nanimh.desc_length) { kern_msg_hdr.ndescv = 0; kern_msg_hdr.ndesc_length = 0; } else { if (!NaClCopyInFromUser(nap, usr_desc, kern_nanimh.descv, kern_nanimh.desc_length * sizeof usr_desc[0])) { retval = -NACL_ABI_EFAULT; goto cleanup; } for (i = 0; i < kern_nanimh.desc_length; ++i) { if (kKnownInvalidDescNumber == usr_desc[i]) { kern_desc[i] = (struct NaClDesc *) NaClDescInvalidMake(); } else { /* NaCl modules are ILP32, so this works on ILP32 and LP64 systems */ kern_desc[i] = NaClAppGetDesc(nap, usr_desc[i]); } if (NULL == kern_desc[i]) { retval = -NACL_ABI_EBADF; goto cleanup; } } kern_msg_hdr.ndescv = kern_desc; kern_msg_hdr.ndesc_length = kern_nanimh.desc_length; } kern_msg_hdr.flags = kern_nanimh.flags; /* 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)->SendMsg(ndp, &kern_msg_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); } if (NaClSSizeIsNegErrno(&ssize_retval)) { /* * NaClWouldBlock uses TSD (for both the errno-based and * GetLastError()-based implementations), so this is threadsafe. */ if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) { retval = -NACL_ABI_EAGAIN; } else if (-NACL_ABI_EMSGSIZE == ssize_retval) { /* * Allow the caller to handle the case when imc_sendmsg fails because * the message is too large for the system to send in one piece. */ retval = -NACL_ABI_EMSGSIZE; } else { /* * TODO(bsy): the else case is some mysterious internal error. * Should we destroy the ndp or otherwise mark it as bad? Was * the failure atomic? Did it send some partial data? Linux * implementation appears okay. */ retval = -NACL_ABI_EIO; } } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) { retval = -NACL_ABI_EOVERFLOW; } else { /* cast is safe due to range checks above */ retval = (int32_t)ssize_retval; } cleanup: for (i = 0; i < kern_nanimh.desc_length; ++i) { if (NULL != kern_desc[i]) { NaClDescUnref(kern_desc[i]); kern_desc[i] = NULL; } } NaClDescUnref(ndp); cleanup_leave: NaClLog(3, "NaClSysImcSendmsg: returning %d\n", retval); return retval; }