Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
static void run(struct binfmt *binary, int argc, char *argv[], int env_size, char *envp[])
{
	/* Generate initial stack */
	char *stack_base = process_get_stack_base();
	char *stack = stack_base + STACK_SIZE;
	/* 16 random bytes for AT_RANDOM */
	/* TODO: Fill in real content */
	char *random_bytes = ALLOC(16);

	struct elf_header *executable = binary->executable;
	struct elf_header *interpreter = binary->interpreter;

	/* auxiliary vector */
	PTR(NULL);
	AUX_VEC(AT_FLAGS, 0);
	AUX_VEC(AT_SECURE, 0);
	AUX_VEC(AT_RANDOM, random_bytes);
	AUX_VEC(AT_PAGESZ, PAGE_SIZE);
	AUX_VEC(AT_PHDR, executable->load_base + executable->eh.e_phoff);
	AUX_VEC(AT_PHENT, executable->eh.e_phentsize);
	AUX_VEC(AT_PHNUM, executable->eh.e_phnum);
	if (executable->eh.e_type == ET_DYN)
		AUX_VEC(AT_ENTRY, executable->load_base + executable->eh.e_entry);
	else
		AUX_VEC(AT_ENTRY, executable->eh.e_entry);
	AUX_VEC(AT_BASE, (binary->has_interpreter ? (void*)(interpreter->load_base - interpreter->low) : NULL));

	/* environment variables */
	PTR(NULL);
	for (int i = env_size - 1; i >= 0; i--)
		PTR(envp[i]);

	/* argv */
	PTR(NULL);
	for (int i = argc - 1; i >= 0; i--)
		PTR(argv[i]);
	/* Insert additional arguments from special binfmt */
	if (binary->argv1)
	{
		PTR(binary->argv1);
		argc++;
	}
	if (binary->argv0)
	{
		PTR(binary->argv0);
		argc++;
	}

	/* argc */
	PTR(argc);

	/* Call executable entrypoint */
	size_t entrypoint;
	struct elf_header *start = binary->has_interpreter? interpreter: executable;
	if (start->eh.e_type == ET_DYN)
		entrypoint = start->load_base + start->eh.e_entry;
	else
		entrypoint = start->eh.e_entry;
	log_info("Entrypoint: %p", entrypoint);

	/* TODO: The current way isn't bullet-proof
	 * Basically our 'kernel' routines uses the application's stack
	 * When doing an execve we are overwritting the upper part of the stack while relying on the bottom part!!!
	 * To get proper behaviour, we first have to save and restore esp on kernel/app switches, which is left to be done
	 */
	dbt_run(entrypoint, (size_t)stack);
}