/* initialize ethread */ void ethread_init(struct ethread *thread, struct eprocess *process, struct task_struct *tsk) { ktrace("\n"); /* attach to the containing process */ ref_object((PVOID)process); write_lock(&process->ep_lock); thread->threads_process = process; write_unlock(&process->ep_lock); /* FIXME create a thread object and hook in to the Linux task */ thread->et_task = tsk; atomic_set(&thread->et_count, 0); /* FIXME */ thread->et_ops = (struct ethread_operations *)ðread_ops; INIT_LIST_HEAD(&thread->lpc_reply_chain); INIT_LIST_HEAD(&thread->irp_list); INIT_LIST_HEAD(&thread->active_timer_list_head); thread->active_timer_list_lock = SPIN_LOCK_UNLOCKED; thread->thread_lock = SPIN_LOCK_UNLOCKED; /* FIXME: semaphore_init */ thread->cid.unique_process = process->unique_processid; thread->win32_start_address = 0; /* context->Eax, default is 0 */ lock_process(process); list_add_tail(&thread->thread_list_entry, &process->thread_list_head); unlock_process(process); add_ethread(thread->et_task, thread); if (atomic_read(&thread->et_count) == 1) /* FIXME: add this to win32_thread.c */ ref_object(thread); kthread_init(&thread->tcb, process); } /* end ethread_init */
PACCESS_TOKEN ref_impersonation_token(IN struct ethread *Thread, OUT PBOOLEAN CopyOnOpen, OUT PBOOLEAN EffectiveOnly, OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) { if (Thread->active_impersonation_info == FALSE) return NULL; *ImpersonationLevel = Thread->impersonation_info->impersonation_level; *CopyOnOpen = Thread->impersonation_info->copy_on_open; *EffectiveOnly = Thread->impersonation_info->effective_only; ref_object(Thread->impersonation_info->token); return Thread->impersonation_info->token; }
NTSTATUS open_process_token(HANDLE ProcessHandle, PACCESS_TOKEN *Token) { struct eprocess *process; NTSTATUS status; status = ref_object_by_handle(ProcessHandle, PROCESS_QUERY_INFORMATION, /* TODO */ process_object_type, get_pre_mode(), (PVOID *)&process, NULL); if (NT_SUCCESS(status)) { ref_object(&process->token); *Token = process->token.object; deref_object(process); } return status; }
/*-------------------------------------------------------------------------*/ svalue_t * v_tls_init_connection (svalue_t *sp, int num_arg) /* EFUN tls_init_connection() * * int tls_init_connection(object ob) * int tls_init_connection(object ob, string fun, string|object fob, mixed extra...) * int tls_init_connection(object ob, closure fun, mixed extra...) * * tls_init_connection() tries to start a TLS secured connection to the * interactive object <ob> (or this_object() if <ob> is not given). * Result: * errorcode < 0: unsuccessful, use tls_error() to get an useful * description of the error * number > 0: the secure connection is still being set up in the * background * number == 0: the secure connection is active. * * If the callback <fun>/<fun>:<fob> is specified, it will be called once * the fate of the secure connection has been determined. The first argument * will be the return code from the handshake (errorcode < 0 on failure, * or 0 on success), followed by the interactive object <ob> and any <extra> * arguments. */ { svalue_t * argp = sp - num_arg + 1; long ret; object_t * obj; interactive_t *ip; if (!tls_available()) errorf("tls_init_connection(): TLS layer hasn't been initialized.\n"); if (num_arg > 0) { obj = argp->u.ob; put_number(argp, 0); /* remove obj reference from the stack */ } else { obj = ref_object(current_object, "tls_init_connection"); } if (!O_SET_INTERACTIVE(ip, obj)) { free_object(obj, "tls_init_connection"); errorf("Bad arg 1 to tls_init_connection(): " "object not interactive.\n"); } free_object(obj, "tls_init_connection"); /* ip has another reference to obj, so this is safe to do */ if (ip->tls_status != TLS_INACTIVE) errorf("tls_init_connection(): Interactive already has a secure " "connection.\n"); /* Extract the callback information from the stack */ if (num_arg > 1) { /* Extract the callback information from the stack */ int error_index; callback_t * cb; inter_sp = sp; memsafe(cb = xalloc(sizeof *cb) , sizeof *cb , "callback structure"); assign_eval_cost(); error_index = setup_efun_callback(cb, argp+1, num_arg-1); if (error_index >= 0) { /* The callback values have already been removed. */ xfree(cb); inter_sp = sp = argp; vefun_bad_arg(error_index+2, argp); /* NOTREACHED */ return argp; } /* Callback creation successful */ ip->tls_cb = cb; } inter_sp = sp = argp - 1; /* Flush the connection */ { object_t * save_c_g = command_giver; command_giver = obj; add_message(message_flush); command_giver = save_c_g; } ret = tls_init_connection(ip); if (ret >= 0) { ip->tls_status = TLS_HANDSHAKING; ret = tls_continue_handshake(ip); /* Adjust the return value of tls_continue_handshake() */ if (ret >= 0) ret = !ret; } push_number(sp, ret); return sp; } /* f_tls_init_connection() */
/* * open a section object, maybe creating if non-existent */ NTSTATUS SERVICECALL NtCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG Protect, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL ) { HANDLE hSection; size_t size = 0; struct win32_file *wfile = NULL; struct win32_section *section; struct ethread *thread; POBJECT_ATTRIBUTES obj_attr = NULL; LARGE_INTEGER max_size; NTSTATUS Status; MODE previous_mode; ktrace("()\n"); if (!(thread = get_current_ethread())) return STATUS_UNSUCCESSFUL; /* FIXME */ previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; if (ObjectAttributes) { if (previous_mode == UserMode) { if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) return STATUS_NO_MEMORY; } else obj_attr = ObjectAttributes; } if (obj_attr && obj_attr->RootDirectory) obj_attr->RootDirectory = base_dir_handle; if (MaximumSize) { if (previous_mode == UserMode) { Status = STATUS_NO_MEMORY; if (copy_from_user(&max_size, MaximumSize, sizeof(max_size))) goto cleanup_object_attr; MaximumSize = &max_size; } Status = STATUS_INVALID_PARAMETER; if (MaximumSize->u.HighPart) goto cleanup_object_attr; size = MaximumSize->u.LowPart; } /* gain access to the file */ if (FileHandle) { Status = ref_object_by_handle( FileHandle, DesiredAccess, file_object_type, KernelMode, (PVOID *)&wfile, NULL ); if (!NT_SUCCESS(Status)) goto cleanup_object_attr; } /* create a section object */ Status = create_object( KernelMode, section_object_type, obj_attr, KernelMode, NULL, sizeof(struct win32_section), 0, 0, (PVOID *)§ion ); if (Status) goto cleanup_wfile; Status = insert_object( (PVOID)section, NULL, 0, 0, NULL, &hSection ); if (Status == STATUS_OBJECT_NAME_EXISTS) { deref_object(section); goto section_exists; } deref_object(section); if (Status) goto cleanup_wfile; /* setup section */ if (wfile) ref_object(wfile); section->ws_wfile = wfile; /* attach file */ section->ws_len = size; section->ws_flags = 0; section->ws_alloctype = AllocationAttributes; if (AllocationAttributes & _SEC_IMAGE) { if (!wfile || image_section_setup(section) < 0) { Status = STATUS_NO_SUCH_FILE; goto cleanup_handle; } } else { if ((Protect & PAGE_PROT_MASK) != Protect || !(Protect & PAGE_PROT_MASK)) { Status = STATUS_INVALID_PAGE_PROTECTION; kdebug("FIXME: some protect not implemention! Protect %x\n", Protect); goto cleanup_handle; } section->ws_protect = prot_to_linux(Protect); /* anonymous map, map len is need */ if (!wfile && !section->ws_len) { Status = STATUS_NOT_MAPPED_VIEW; goto cleanup_handle; } if (!wfile && (!obj_attr->ObjectName || !obj_attr->ObjectName->Length)) { Status = STATUS_OBJECT_NAME_INVALID; goto cleanup_handle; } if (!wfile && (AllocationAttributes & _SEC_RESERVE)) section->ws_flags |= MAP_RESERVE; if ((Protect & _PAGE_WRITECOPY) || (Protect & _PAGE_EXECUTE_WRITECOPY)) /* copy on write */ section->ws_flags |= MAP_PRIVATE; else /* shared map */ section->ws_flags |= MAP_SHARED; /* get the file size, when paramter len is 0 */ if (!section->ws_len && wfile) section->ws_len = wfile->wf_file->f_dentry->d_inode->i_size; section->ws_pagelen = PAGE_ALIGN(section->ws_len); /* TODO if (section->ws_len < wfile->wf_file->f_dentry->d_inode->i_size) grow_file(wfile); */ if (data_section_setup(section) < 0) { Status = STATUS_NOT_MAPPED_VIEW; goto cleanup_handle; } } Status = STATUS_SUCCESS; section_exists: if (previous_mode == UserMode) { if (copy_to_user(SectionHandle, &hSection, sizeof(hSection))) { Status = STATUS_INVALID_ADDRESS; goto cleanup_handle; } } else *SectionHandle = hSection; goto cleanup_wfile; cleanup_handle: NtClose(hSection); cleanup_wfile: if (wfile) deref_object((PVOID)wfile); cleanup_object_attr: if (obj_attr && previous_mode == UserMode) kfree(obj_attr); return Status; } /* end NtCreateSection() */
/* * map a view of the section to the process's address space */ NTSTATUS SERVICECALL NtMapViewOfSection( IN HANDLE SectionHandle, IN HANDLE ProcessHandle, IN OUT PVOID *BaseAddress, IN ULONG ZeroBits, IN ULONG CommitSize, IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, IN OUT PSIZE_T ViewSize, IN SECTION_INHERIT InheritDisposition, IN ULONG AllocationType, IN ULONG Protect ) { NTSTATUS Status; size_t size = 0; MODE previous_mode; unsigned long addr = 0L; struct win32_section *section; struct ethread *thread; struct eprocess *process; LARGE_INTEGER sec_off = { .QuadPart = 0LL }; ktrace("\n"); if (!(thread = get_current_ethread())) return STATUS_UNSUCCESSFUL; /* FIXME */ previous_mode = (unsigned long)BaseAddress > TASK_SIZE ? KernelMode : UserMode; if (!BaseAddress) return STATUS_INVALID_PARAMETER; if (!ViewSize) return STATUS_INVALID_PARAMETER; if (previous_mode == UserMode) { if (copy_from_user(&addr, BaseAddress, sizeof(PVOID))) return STATUS_INVALID_ADDRESS; if (copy_from_user(&size, ViewSize, sizeof(size))) return STATUS_INVALID_ADDRESS; if (SectionOffset && copy_from_user(&sec_off, SectionOffset, sizeof(sec_off))) return STATUS_INVALID_ADDRESS; } else { addr = (unsigned long)*BaseAddress; size = (size_t)*ViewSize; if (SectionOffset) sec_off = *SectionOffset; } if (addr > WIN32_TASK_SIZE || size > WIN32_TASK_SIZE) return STATUS_INVALID_PARAMETER; /* TODO: not support 64bit offset */ if (sec_off.u.HighPart) return STATUS_INVALID_PARAMETER; /* access the section object */ Status = ref_object_by_handle( SectionHandle, SECTION_ALL_ACCESS, section_object_type, KernelMode, (PVOID *)§ion, NULL ); if (Status) return Status; if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) { process = thread->threads_process; ref_object((PVOID)process); } else { Status = ref_object_by_handle( ProcessHandle, PROCESS_ALL_ACCESS, process_object_type, KernelMode, (PVOID *)&process, NULL ); if (Status) goto cleanup_section; } Status = map_section_view( (PVOID)section, process, (PVOID *)&addr, ZeroBits, CommitSize, SectionOffset ? (PLARGE_INTEGER)&sec_off : NULL, (PSIZE_T)&size, InheritDisposition, AllocationType, Protect ); if (!NT_SUCCESS(Status)) goto cleanup_process; Status = STATUS_INVALID_ADDRESS; if (previous_mode == UserMode) { if (copy_to_user(BaseAddress, &addr, sizeof(PVOID))) goto cleanup_process; if (copy_to_user(ViewSize, &size, sizeof(PVOID))) goto cleanup_process; } else { *BaseAddress = (PVOID)addr; *ViewSize = size; } Status = STATUS_SUCCESS; cleanup_process: deref_object(process); cleanup_section: deref_object(section); return Status; } /* end NtMapViewOfSection() */ EXPORT_SYMBOL(NtMapViewOfSection); /* * unmap a mapped view of the file * - the view must start _exactly_ on the address */ NTSTATUS SERVICECALL NtUnmapViewOfSection( IN HANDLE ProcessHandle, IN PVOID BaseAddress ) { struct mm_struct *mm; struct eprocess *process; struct ethread *thread; NTSTATUS ret; ktrace("\n"); if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) { mm = current->mm; process = get_current_eprocess(); ref_object((PVOID)process); } else { ret = ref_object_by_handle( ProcessHandle, PROCESS_ALL_ACCESS, process_object_type, KernelMode, (PVOID *)&process, NULL ); if (!NT_SUCCESS(ret)) return ret; thread = get_first_thread(process); if (!thread) { ret = STATUS_THREAD_NOT_IN_PROCESS; goto out; } mm = thread->et_task->mm; } ret = unmap_section_view(process, mm, (unsigned long)BaseAddress); out: deref_object(process); return ret; } /* NtUnmapViewOfSection() */ EXPORT_SYMBOL(NtUnmapViewOfSection); NTSTATUS SERVICECALL NtOpenSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) { HANDLE hSection; POBJECT_ATTRIBUTES obj_attr = NULL; MODE previous_mode; NTSTATUS Status = STATUS_SUCCESS; ktrace("\n"); previous_mode = (unsigned long)ObjectAttributes > TASK_SIZE ? KernelMode : UserMode; if (ObjectAttributes) { if (previous_mode == UserMode) { if (copy_object_attr_from_user(ObjectAttributes, &obj_attr)) return STATUS_NO_MEMORY; } else obj_attr = ObjectAttributes; } if (obj_attr && obj_attr->RootDirectory) obj_attr->RootDirectory = base_dir_handle; Status = open_object_by_name(obj_attr, section_object_type, NULL, KernelMode, DesiredAccess, NULL, &hSection); if (!NT_SUCCESS(Status)) goto cleanup; if (previous_mode == UserMode) { if (copy_to_user(SectionHandle, &hSection, sizeof(HANDLE))) { Status = STATUS_INVALID_ADDRESS; goto cleanup; } } else *SectionHandle = hSection; cleanup: if (obj_attr && previous_mode == UserMode) kfree(obj_attr); return Status; } /* end NtOpenSection */
NTSTATUS STDCALL create_thread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, IN struct eprocess* TargetProcess, /* FIXME */ OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended, IN PKSTART_ROUTINE StartRoutine OPTIONAL, /* FIXME */ IN PVOID StartContext OPTIONAL) /* FIXME */ { struct eprocess * process; struct ethread * thread, *first_thread, *cur_thread; struct task_struct *new_tsk = NULL; unsigned clone_flags = 0; PTEB teb_base; long cpid; HANDLE hthread; NTSTATUS status = STATUS_SUCCESS; ktrace("\n"); if (!(cur_thread = get_current_ethread())) { return STATUS_INVALID_PARAMETER; } /* current still be regarded */ if (ProcessHandle && ProcessHandle != NtCurrentProcess()) { status = ref_object_by_handle(ProcessHandle, PROCESS_ALL_ACCESS, process_object_type, KernelMode, (PVOID *)&process, NULL); if (!NT_SUCCESS(status)) return status; } else { if (TargetProcess) process = (struct eprocess *)TargetProcess; else process = cur_thread->threads_process; ref_object(process); } if (!process->fork_in_progress) { /* second and after */ if (!ProcessHandle || ProcessHandle == NtCurrentProcess()) first_thread = cur_thread; else first_thread = get_first_thread(process); if (!first_thread) { status = STATUS_INVALID_PARAMETER; goto cleanup_process; } clone_flags = SIGCHLD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_PARENT | CLONE_THREAD; cpid = do_fork_from_task(first_thread->et_task, CREATE_THREAD, clone_flags, first_thread->tcb.trap_frame->esp, (struct pt_regs *)first_thread->tcb.trap_frame, 0, NULL, NULL); if (cpid < 0) { status = STATUS_INVALID_PARAMETER; goto cleanup_process; } new_tsk = find_task_by_vpid(cpid); memset(&new_tsk->thread.tls_array, 0, sizeof(new_tsk->thread.tls_array)); set_tls_array(&new_tsk->thread, first_thread->et_task->thread.gs >> 3, (unsigned long)InitialTeb->StackBase + 0x800, 0xfffff); /* allocate a Win32 thread object */ status = create_object(KernelMode, thread_object_type, ObjectAttributes, KernelMode, NULL, sizeof(struct ethread), 0, 0, (PVOID *)&thread); if (!NT_SUCCESS(status)) goto cleanup_tsk; ethread_init(thread, process, new_tsk); deref_object(thread); } else {