int ipc_cld_join_callback (IPC_CALLBACK_ARGS) { BEGIN_PROFILE_INTERVAL(); debug("ipc callback from %u: IPC_CLD_JOIN\n", msg->src); add_ipc_port(port, msg->src, IPC_PORT_DIRCLD, NULL); SAVE_PROFILE_INTERVAL(ipc_cld_join_callback); return 0; }
int ipc_cld_exit_callback (IPC_CALLBACK_ARGS) { BEGIN_PROFILE_INTERVAL(); struct shim_ipc_cld_exit * msgin = (struct shim_ipc_cld_exit *) &msg->msg; debug("ipc callback from %u: IPC_CLD_EXIT(%u, %d)\n", msg->src, msgin->tid, msgin->exitcode); int ret = ipc_thread_exit(msg->src, msgin->tid, msgin->exitcode); SAVE_PROFILE_INTERVAL(ipc_cld_exit_callback); return ret; }
int ipc_cld_exit_send (IDTYPE tid, unsigned int exitcode) { BEGIN_PROFILE_INTERVAL(); int ret = 0; struct shim_ipc_msg * msg = create_ipc_msg_on_stack(IPC_CLD_EXIT, sizeof(struct shim_ipc_cld_exit), 0); struct shim_ipc_cld_exit * msgin = (struct shim_ipc_cld_exit *) &msg->msg; msgin->tid = tid; msgin->exitcode = exitcode; debug("ipc broadcast: IPC_CLD_EXIT(%u, %d)\n", tid, exitcode); ret = broadcast_ipc(msg, NULL, 0, IPC_PORT_DIRPRT|IPC_PORT_DIRCLD); SAVE_PROFILE_INTERVAL(ipc_cld_exit_send); return ret; }
static int migrate_execve (struct shim_cp_store * cpstore, struct shim_process * process, struct shim_thread * thread, va_list ap) { struct shim_handle_map * handle_map = NULL; int ret; const char ** envp = va_arg (ap, const char **); size_t envsize = va_arg (ap, size_t); BEGIN_PROFILE_INTERVAL(); if ((ret = dup_handle_map(&handle_map, thread->handle_map)) < 0) return ret; set_handle_map(thread, handle_map); if ((ret = close_cloexec_handle(handle_map)) < 0) return ret; SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec); /* Now we start to migrate bookkeeping for exec. The data we need to migrate are: 1. cur_threadrent thread 2. cur_threadrent filesystem 3. handle mapping 4. each handle */ BEGIN_MIGRATION_DEF(execve, struct shim_process * proc, struct shim_thread * thread, const char ** envp, size_t envsize) { store->use_gipc = true; DEFINE_MIGRATE(process, proc, sizeof(struct shim_process), false); DEFINE_MIGRATE(all_mounts, NULL, 0, false); DEFINE_MIGRATE(running_thread, thread, sizeof(struct shim_thread), false); DEFINE_MIGRATE(handle_map, thread->handle_map, sizeof (struct shim_handle_map), true); DEFINE_MIGRATE(migratable, NULL, 0, false); DEFINE_MIGRATE(environ, envp, envsize, true); }
int add_sysv_msg (struct shim_msg_handle * msgq, long type, int size, const void * data, struct sysv_client * src) { BEGIN_PROFILE_INTERVAL(); struct shim_handle * hdl = MSG_TO_HANDLE(msgq); int ret = 0; lock(hdl->lock); if (msgq->deleted) { ret = -EIDRM; goto out_locked; } if (!msgq->owned) { unlock(hdl->lock); ret = ipc_sysv_msgsnd_send(src->port, src->vmid, msgq->msqid, type, data, size, src->seq); goto out; } struct msg_type * mtype = __add_msg_type(type, &msgq->types, &msgq->ntypes, &msgq->maxtypes); if ((ret = __store_msg_qobjs(msgq, mtype, size, data)) < 0) goto out_locked; if (msgq->owned) __balance_sysv_score(&msg_policy, hdl, msgq->scores, MAX_SYSV_CLIENTS, src, MSG_SND_SCORE); DkEventSet(msgq->event); ret = 0; out_locked: unlock(hdl->lock); out: SAVE_PROFILE_INTERVAL(add_sysv_msg); return ret; }
int ipc_cld_join_send (IDTYPE dest) { BEGIN_PROFILE_INTERVAL(); struct shim_ipc_port * port = dest ? lookup_ipc_port(dest, IPC_PORT_DIRPRT) : get_parent_port(&dest); if (!port) return -ESRCH; struct shim_ipc_msg * msg = create_ipc_msg_on_stack(IPC_CLD_JOIN, 0, dest); debug("ipc send to %u: IPC_CLD_JOIN\n", dest); int ret = send_ipc_message(msg, port); add_ipc_port(port, dest, IPC_PORT_DIRPRT, NULL); put_ipc_port(port); SAVE_PROFILE_INTERVAL(ipc_cld_join_send); return ret; }
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv, const char ** envp) { BEGIN_PROFILE_INTERVAL(); struct shim_thread * cur_thread = get_cur_thread(); int ret; if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0) return ret; SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec); void * tcb = malloc(sizeof(__libc_tcb_t)); if (!tcb) return -ENOMEM; populate_tls(tcb, false); __disable_preempt(&((__libc_tcb_t *) tcb)->shim_tcb); // Temporarily disable preemption // during execve(). debug("set tcb to %p\n", tcb); put_handle(cur_thread->exec); get_handle(hdl); cur_thread->exec = hdl; old_stack_top = cur_thread->stack_top; old_stack = cur_thread->stack; old_stack_red = cur_thread->stack_red; cur_thread->stack_top = NULL; cur_thread->stack = NULL; cur_thread->stack_red = NULL; initial_envp = NULL; new_argc = 0; for (const char ** a = argv ; *a ; a++, new_argc++); new_argcp = &new_argc; if ((ret = init_stack(argv, envp, &new_argcp, &new_argp, REQUIRED_ELF_AUXV, &new_auxp)) < 0) return ret; SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec); SWITCH_STACK(new_argp); cur_thread = get_cur_thread(); UPDATE_PROFILE_INTERVAL(); DkVirtualMemoryFree(old_stack, old_stack_top - old_stack); DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red); if (bkeep_munmap(old_stack, old_stack_top - old_stack, 0) < 0 || bkeep_munmap(old_stack_red, old_stack - old_stack_red, 0) < 0) BUG(); remove_loaded_libraries(); clean_link_map_list(); SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec); reset_brk(); size_t count = DEFAULT_VMA_COUNT; struct shim_vma_val * vmas = malloc(sizeof(struct shim_vma_val) * count); if (!vmas) return -ENOMEM; retry_dump_vmas: ret = dump_all_vmas(vmas, count); if (ret == -EOVERFLOW) { struct shim_vma_val * new_vmas = malloc(sizeof(struct shim_vma_val) * count * 2); if (!new_vmas) { free(vmas); return -ENOMEM; } free(vmas); vmas = new_vmas; count *= 2; goto retry_dump_vmas; } if (ret < 0) { free(vmas); return ret; } count = ret; for (struct shim_vma_val * vma = vmas ; vma < vmas + count ; vma++) { /* Don't free the current stack */ if (vma->addr == cur_thread->stack) continue; /* Free all the mapped VMAs */ if (!(vma->flags & VMA_UNMAPPED)) DkVirtualMemoryFree(vma->addr, vma->length); /* Remove the VMAs */ bkeep_munmap(vma->addr, vma->length, vma->flags); } free_vma_val_array(vmas, count); SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec); if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0) shim_terminate(ret); init_brk_from_executable(cur_thread->exec); load_elf_interp(cur_thread->exec); SAVE_PROFILE_INTERVAL(load_new_executable_for_exec); cur_thread->robust_list = NULL; #ifdef PROFILE if (ENTER_TIME) SAVE_PROFILE_INTERVAL_SINCE(syscall_execve, ENTER_TIME); #endif debug("execve: start execution\n"); execute_elf_object(cur_thread->exec, new_argcp, new_argp, REQUIRED_ELF_AUXV, new_auxp); return 0; }
int shim_do_execve_rtld (struct shim_handle * hdl, const char ** argv, const char ** envp) { BEGIN_PROFILE_INTERVAL(); struct shim_thread * cur_thread = get_cur_thread(); int ret; if ((ret = close_cloexec_handle(cur_thread->handle_map)) < 0) return ret; SAVE_PROFILE_INTERVAL(close_CLOEXEC_files_for_exec); void * tcb = malloc(sizeof(__libc_tcb_t)); if (!tcb) return -ENOMEM; populate_tls(tcb); put_handle(cur_thread->exec); get_handle(hdl); cur_thread->exec = hdl; old_stack_top = cur_thread->stack_top; old_stack = cur_thread->stack; old_stack_red = cur_thread->stack_red; cur_thread->stack_top = NULL; cur_thread->stack = NULL; cur_thread->stack_red = NULL; initial_envp = NULL; new_argc = 0; for (const char ** a = argv ; *a ; a++, new_argc++); if ((ret = init_stack(argv, envp, &new_argp, REQUIRED_ELF_AUXV, &new_auxp)) < 0) return ret; SAVE_PROFILE_INTERVAL(alloc_new_stack_for_exec); switch_stack(new_argp); cur_thread = get_cur_thread(); UPDATE_PROFILE_INTERVAL(); DkVirtualMemoryFree(old_stack, old_stack_top - old_stack); DkVirtualMemoryFree(old_stack_red, old_stack - old_stack_red); int flags = VMA_INTERNAL; bkeep_munmap(old_stack, old_stack_top - old_stack, &flags); bkeep_munmap(old_stack_red, old_stack - old_stack_red, &flags); remove_loaded_libraries(); clean_link_map_list(); SAVE_PROFILE_INTERVAL(unmap_loaded_binaries_for_exec); init_brk(); unmap_all_vmas(); SAVE_PROFILE_INTERVAL(unmap_all_vmas_for_exec); if ((ret = load_elf_object(cur_thread->exec, NULL, 0)) < 0) shim_terminate(); load_elf_interp(cur_thread->exec); SAVE_PROFILE_INTERVAL(load_new_executable_for_exec); debug("execve: start execution\n"); execute_elf_object(cur_thread->exec, new_argc, new_argp, REQUIRED_ELF_AUXV, new_auxp); return 0; }
int get_sysv_msg (struct shim_msg_handle * msgq, long type, int size, void * data, int flags, struct sysv_client * src) { BEGIN_PROFILE_INTERVAL(); int ret = 0; struct shim_handle * hdl = MSG_TO_HANDLE(msgq); struct msg_item * msg = NULL; struct msg_type * alltypes = NULL, * mtype = NULL; lock(hdl->lock); if (msgq->deleted) { ret = -EIDRM; goto out_locked; } if (msgq->owned) { __balance_sysv_score(&msg_policy, hdl, msgq->scores, MAX_SYSV_CLIENTS, src, MSG_RCV_SCORE); if (!msgq->owned && src) { struct shim_ipc_info * owner = msgq->owner; assert(owner); ret = ipc_sysv_movres_send(src, owner->vmid, qstrgetstr(&owner->uri), msgq->lease, msgq->msqid, SYSV_MSGQ); goto out_locked; } } if (!msgq->owned) { IDTYPE msqid = msgq->msqid; if (src) { struct shim_ipc_info * owner = msgq->owner; ret = owner ? ipc_sysv_movres_send(src, owner->vmid, qstrgetstr(&owner->uri), msgq->lease, msgq->msqid, SYSV_MSGQ) : -ECONNREFUSED; goto out_locked; } unowned: unlock(hdl->lock); ret = ipc_sysv_msgrcv_send(msqid, type, flags, data, size); if (ret != -EAGAIN && ret != -ECONNREFUSED) goto out; lock(hdl->lock); if (!msgq->owned) goto out_locked; } while (1) { if (alltypes != msgq->types || !mtype || mtype->type != type) { alltypes = msgq->types; mtype = __find_msg_type(type, alltypes, msgq->ntypes); } if (mtype && mtype->msgs) { msg = mtype->msgs; if (msg->size > size && !(flags & MSG_NOERROR)) { ret = -E2BIG; goto out; } break; } if (flags & IPC_NOWAIT || src) break; unlock(hdl->lock); while (!DkObjectsWaitAny(1, &msgq->event, NO_TIMEOUT)); lock(hdl->lock); if (!msgq->owned) goto unowned; } if (!msg) { ret = (!(flags & IPC_NOWAIT) && src) ? __add_msg_req(msgq, mtype, size, flags, src) : -ENOMSG; goto out_locked; } if ((ret = __load_msg_qobjs(msgq, mtype, msg, data)) < 0) goto out_locked;; ret = msg->size; out_locked: unlock(hdl->lock); out: SAVE_PROFILE_INTERVAL(get_sysv_msg); return ret; }