/* Currently supported flags (see sched.h): o CLONE_VM o CLONE_FS o CLONE_SIGHAND o CLONE_PTRACE o CLONE_VFORK o CLONE_PARENT o CLONE_THREAD o CLONE_NEWNS o CLONE_SYSVSEM o CLONE_SETTLS o CLONE_PARENT_SETTID o CLONE_CHILD_CLEARTID o CLONE_DETACHED o CLONE_UNTRACED * CLONE_CHILD_SETTID o CLONE_NEWUTS o CLONE_NEWIPC o CLONE_NEWUSER o CLONE_NEWPID o CLONE_NEWNET o CLONE_IO */ static pid_t fork_process(struct syscall_context *context, unsigned long flags, void *ptid, void *ctid) { wchar_t filename[MAX_PATH]; GetModuleFileNameW(NULL, filename, sizeof(filename) / sizeof(filename[0])); tls_beforefork(); PROCESS_INFORMATION info; STARTUPINFOW si = { 0 }; si.cb = sizeof(si); if (!CreateProcessW(filename, L"/?/fork", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, &info)) { log_warning("fork(): CreateProcessW() failed.\n"); return -1; } if (!mm_fork(info.hProcess)) goto fail; if (!vfs_fork(info.hProcess)) goto fail; /* Set up fork_info in child process */ void *stack_base = process_get_stack_base(); VirtualAllocEx(info.hProcess, FORK_INFO_BASE, BLOCK_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(info.hProcess, &fork->context, context, sizeof(struct syscall_context), NULL); WriteProcessMemory(info.hProcess, &fork->stack_base, &stack_base, sizeof(stack_base), NULL); if (flags & CLONE_CHILD_SETTID) WriteProcessMemory(info.hProcess, &fork->ctid, &ctid, sizeof(void*), NULL); /* Copy stack */ VirtualAllocEx(info.hProcess, stack_base, STACK_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(info.hProcess, context->esp, context->esp, (char *)stack_base + STACK_SIZE - context->esp, NULL); ResumeThread(info.hThread); CloseHandle(info.hThread); /* Process handled will be used for wait() */ log_info("Child pid: %d\n", info.dwProcessId); process_add_child(info.dwProcessId, info.hProcess); return info.dwProcessId; fail: TerminateProcess(info.hProcess, 0); CloseHandle(info.hThread); CloseHandle(info.hProcess); return -1; }
gfarm_error_t gfm_server_process_alloc_child(struct peer *peer, int from_client, int skip) { gfarm_int32_t e; struct user *user; gfarm_int32_t parent_keytype, keytype; size_t parent_keylen, keylen; char parent_sharedkey[GFM_PROTO_PROCESS_KEY_LEN_SHAREDSECRET]; char sharedkey[GFM_PROTO_PROCESS_KEY_LEN_SHAREDSECRET]; struct process *parent_process, *process; gfarm_pid_t parent_pid, pid; e = gfm_server_get_request(peer, "process_alloc_child", "iblib", &parent_keytype, sizeof(parent_sharedkey), &parent_keylen, parent_sharedkey, &parent_pid, &keytype, sizeof(sharedkey), &keylen, sharedkey); if (e != GFARM_ERR_NO_ERROR) return (e); if (skip) return (GFARM_ERR_NO_ERROR); giant_lock(); if (peer_get_process(peer) != NULL) { e = GFARM_ERR_ALREADY_EXISTS; } else if (!from_client || (user = peer_get_user(peer)) == NULL) { e = GFARM_ERR_OPERATION_NOT_PERMITTED; } else if (parent_keytype != GFM_PROTO_PROCESS_KEY_TYPE_SHAREDSECRET || parent_keylen != GFM_PROTO_PROCESS_KEY_LEN_SHAREDSECRET) { e = GFARM_ERR_INVALID_ARGUMENT; } else if ((e = process_does_match(parent_pid, parent_keytype, parent_keylen, parent_sharedkey, &parent_process)) != GFARM_ERR_NO_ERROR) { /* error */ } else if ((e = process_alloc(user, keytype, keylen, sharedkey, &process, &pid)) == GFARM_ERR_NO_ERROR) { peer_set_process(peer, process); process_add_child(parent_process, process); } giant_unlock(); return (gfm_server_put_reply(peer, "process_alloc_child", e, "l", pid)); }