From 1e8c8e3fe6019c5c578d3445f12cd11ccc776389 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 26 Jul 2005 04:14:10 +0000 Subject: [PATCH] - Final ROSRTL removal patch. The next patch will remove the actual library and code. - Changes: - CreateProcess * Cleanup creation of the initial thread using new utility functions and remove rosrtl * Almost entirely rewrote the function to support features such as: - SxS (locally only, patch will follow), - SFP (SAFER) (locally only, patch will follow), - DllPaths (locally only, patch will follow), - Proper process environment/paramter block creation - Proper console handle management (needs more work in kernel32/csr), - Tokens/CreateProcessAsUser (locally only, patch will follow), - Simpler code for path lookup, and more robust. - Support for "auto-correction" (see Raymond Chen's blog) - 16-bit/NE detection - A variety of creation flags are now properly supported - Added support for an undocumented-yet-known (see comment) shell flag - Alert for flags we don't support yet - Catch invalid flag combinations and other caller errors - Improve and correct path searcing to use documented behaviours - Created a multitude of helper functions to make the code easier to read and allow them to be used for other apis as time goes on. - BaseProcessStartup * Call NtSetThreadInformation to let the Kernel know of the Thread's Start Address. * Correct prototype of Thread Startup function for this case. This fixes MANY things, some of which may not be evident, and possibly creates regressions which I have not yet seen but will try to correct. Some of these may be caused by the fact that I've seen code send CreateProcessW incorrect flags. Some things of note: DO NOT send partial names as "lpApplicationName". It's not supposed to work unless you're in the same current directory. Also, do NOT send CREATE_UNICODE_ENVIRONMENT if you don't have a unicode environement, and vice-versa. I've seen lots of code doing mistakes related to this. I hope you appreciate this patch and won't all jump on me for possbile regressions :(. svn path=/trunk/; revision=16730 --- reactos/lib/kernel32/process/create.c | 2744 +++++++++++---------- reactos/lib/kernel32/thread/i386/thread.S | 64 +- reactos/lib/kernel32/thread/thread.c | 399 ++- reactos/ntoskrnl/mm/process.c | 955 ++++--- 4 files changed, 2083 insertions(+), 2079 deletions(-) diff --git a/reactos/lib/kernel32/process/create.c b/reactos/lib/kernel32/process/create.c index 05e4b0ab9b1..26d89cbd44e 100644 --- a/reactos/lib/kernel32/process/create.c +++ b/reactos/lib/kernel32/process/create.c @@ -1,113 +1,608 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/kernel32/process/create.c * PURPOSE: Process functions - * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) - * UPDATE HISTORY: - * Created 01/11/98 + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * Ariadne ( ariadne@xs4all.nl) */ /* INCLUDES ****************************************************************/ #include -/* FIXME */ -#include - #define NDEBUG -#include "../include/debug.h" +#include + +#define CMD_STRING L"cmd /c " + +extern __declspec(noreturn) +VOID +CALLBACK +ConsoleControlDispatcher(DWORD CodeAndFlag); + +/* INTERNAL FUNCTIONS *******************************************************/ + +_SEH_FILTER(BaseExceptionFilter) +{ + EXCEPTION_POINTERS *ExceptionInfo = _SEH_GetExceptionPointers(); + LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER; + + if (GlobalTopLevelExceptionFilter != NULL) + { + _SEH_TRY + { + ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo); + } + _SEH_HANDLE + { + ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo); + } + _SEH_END; + } + + return ExceptionDisposition; +} + +VOID +STDCALL +BaseProcessStartup(PPROCESS_START_ROUTINE lpStartAddress) +{ + UINT uExitCode = 0; + + DPRINT("BaseProcessStartup(..) - setting up exception frame.\n"); + + _SEH_TRY + { + /* Set our Start Address */ + NtSetInformationThread(NtCurrentThread(), + ThreadQuerySetWin32StartAddress, + &lpStartAddress, + sizeof(PPROCESS_START_ROUTINE)); + + /* Call the Start Routine */ + uExitCode = (lpStartAddress)(); + } + _SEH_EXCEPT(BaseExceptionFilter) + { + /* Get the SEH Error */ + uExitCode = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* Exit the Process with our error */ + ExitProcess(uExitCode); +} + +/* + * Tells CSR that a new process was created + */ +NTSTATUS +STDCALL +BasepNotifyCsrOfCreation(ULONG dwCreationFlags, + IN HANDLE ProcessId, + IN ULONG SubsystemType, + OUT PHANDLE ConsoleHandle, + OUT PHANDLE InputHandle, + OUT PHANDLE OutputHandle) +{ + ULONG Request = CREATE_PROCESS; + CSR_API_MESSAGE CsrRequest; + NTSTATUS Status; + + DPRINT("BasepNotifyCsrOfCreation\n"); + + /* Some hacks (heck, this whole API is a hack) */ + if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) + { + dwCreationFlags = (dwCreationFlags &~ CREATE_NEW_CONSOLE) | + DETACHED_PROCESS; + } + else if (SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI) + { + dwCreationFlags |= CREATE_NEW_CONSOLE; + } + + /* Fill out the request */ + CsrRequest.Data.CreateProcessRequest.NewProcessId = ProcessId; + CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags; + CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher; + CsrRequest.Data.CreateProcessRequest.InputHandle = 0; + CsrRequest.Data.CreateProcessRequest.OutputHandle = 0; + CsrRequest.Data.CreateProcessRequest.Console = 0; + + /* Call CSR */ + Status = CsrClientCallServer(&CsrRequest, + NULL, + MAKE_CSR_API(Request, CSR_NATIVE), + sizeof(CSR_API_MESSAGE)); + if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) + { + DPRINT1("Failed to tell csrss about new process\n"); + return CsrRequest.Status; + } + /* Return Handles */ + *ConsoleHandle = CsrRequest.Data.CreateProcessRequest.Console; + *InputHandle = CsrRequest.Data.CreateProcessRequest.InputHandle; + *OutputHandle = CsrRequest.Data.CreateProcessRequest.OutputHandle; + DPRINT("CSR Created: %lx %lx\n", *InputHandle, *OutputHandle); + + /* REturn Success */ + return STATUS_SUCCESS; +} + +/* + * Creates the first Thread in a Proces + */ +HANDLE +STDCALL +BasepCreateFirstThread(HANDLE ProcessHandle, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + PSECTION_IMAGE_INFORMATION SectionImageInfo, + PCLIENT_ID ClientId) +{ + OBJECT_ATTRIBUTES LocalObjectAttributes; + POBJECT_ATTRIBUTES ObjectAttributes; + CONTEXT Context; + INITIAL_TEB InitialTeb; + NTSTATUS Status; + HANDLE hThread; + + DPRINT("BasepCreateFirstThread. hProcess: %lx\n", ProcessHandle); + + /* Create the Thread's Stack */ + BasepCreateStack(ProcessHandle, + SectionImageInfo->MaximumStackSize, + SectionImageInfo->CommittedStackSize, + &InitialTeb); + + /* Create the Thread's Context */ + BasepInitializeContext(&Context, + NtCurrentPeb(), + SectionImageInfo->TransferAddress, + InitialTeb.StackBase, + 0); + + /* Convert the thread attributes */ + ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes, + lpThreadAttributes, + NULL); + + /* Create the Kernel Thread Object */ + Status = NtCreateThread(&hThread, + THREAD_ALL_ACCESS, + ObjectAttributes, + ProcessHandle, + ClientId, + &Context, + &InitialTeb, + TRUE); + + /* Success */ + return hThread; +} + +/* + * Converts ANSI to Unicode Environment + */ +PVOID +STDCALL +BasepConvertUnicodeEnvironment(IN PVOID lpEnvironment) +{ + PCHAR pcScan; + SIZE_T EnvSize = 0; + ANSI_STRING AnsiEnv; + UNICODE_STRING UnicodeEnv; + NTSTATUS Status; + + DPRINT("BasepConvertUnicodeEnvironment\n"); + + /* Scan the environment to calculate its Unicode size */ + AnsiEnv.Buffer = pcScan = lpEnvironment; + while (*pcScan) while (*pcScan++); + + /* Create our ANSI String */ + AnsiEnv.Length = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1; + AnsiEnv.MaximumLength = AnsiEnv.Length + 1; + + /* Allocate memory for the Unicode Environment */ + UnicodeEnv.Buffer = NULL; + EnvSize = AnsiEnv.MaximumLength * sizeof(WCHAR); + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + (PVOID)&UnicodeEnv.Buffer, + 0, + &EnvSize, + MEM_COMMIT, + PAGE_READWRITE); + /* Failure */ + if (!NT_SUCCESS(Status)) + { + SetLastError(Status); + return NULL; + } + + /* Use the allocated size */ + UnicodeEnv.MaximumLength = EnvSize; + + /* Convert */ + RtlAnsiStringToUnicodeString(&UnicodeEnv, &AnsiEnv, FALSE); + return UnicodeEnv.Buffer; +} + +/* + * Converts a Win32 Priority Class to NT + */ +ULONG +STDCALL +BasepConvertPriorityClass(IN ULONG dwCreationFlags) +{ + ULONG ReturnClass; + + if(dwCreationFlags & IDLE_PRIORITY_CLASS) + { + ReturnClass = PROCESS_PRIORITY_CLASS_IDLE; + } + else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS) + { + ReturnClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; + } + else if(dwCreationFlags & NORMAL_PRIORITY_CLASS) + { + ReturnClass = PROCESS_PRIORITY_CLASS_NORMAL; + } + else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS) + { + ReturnClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; + } + else if(dwCreationFlags & HIGH_PRIORITY_CLASS) + { + ReturnClass = PROCESS_PRIORITY_CLASS_HIGH; + } + else if(dwCreationFlags & REALTIME_PRIORITY_CLASS) + { + /* Check for Privilege First */ + if (BasepCheckRealTimePrivilege()) + { + ReturnClass = PROCESS_PRIORITY_CLASS_REALTIME; + } + else + { + ReturnClass = PROCESS_PRIORITY_CLASS_HIGH; + } + } + else + { + ReturnClass = 0 /* FIXME */; + } + + return ReturnClass; +} + +/* + * Duplicates a standard handle and writes it where requested. + */ +VOID +STDCALL +BasepDuplicateAndWriteHandle(IN HANDLE ProcessHandle, + IN HANDLE StandardHandle, + IN PHANDLE Address) +{ + NTSTATUS Status; + HANDLE DuplicatedHandle; + ULONG Dummy; + + DPRINT("BasepDuplicateAndWriteHandle. hProcess: %lx, Handle: %lx," + "Address: %p\n", ProcessHandle, StandardHandle, Address); + + /* Don't touch Console Handles */ + if (IsConsoleHandle(StandardHandle)) return; + + /* Duplicate the handle */ + Status = NtDuplicateObject(NtCurrentProcess(), + StandardHandle, + ProcessHandle, + &DuplicatedHandle, + DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES, + 0, + 0); + if (NT_SUCCESS(Status)) + { + /* Write it */ + NtWriteVirtualMemory(ProcessHandle, + Address, + &DuplicatedHandle, + sizeof(HANDLE), + &Dummy); + } +} + +LPWSTR +STDCALL +BasepGetDllPath(LPWSTR FullPath, + PVOID Environment) +{ + /* FIXME: Not yet implemented */ + return NULL; +} + +VOID +STDCALL +BasepCopyHandles(IN PRTL_USER_PROCESS_PARAMETERS Params, + IN PRTL_USER_PROCESS_PARAMETERS PebParams, + IN BOOL InheritHandles) +{ + /* Copy the handle if we are inheriting or if it's a console handle */ + if (InheritHandles || IsConsoleHandle(PebParams->StandardInput)) + { + Params->StandardInput = PebParams->StandardInput; + } + if (InheritHandles || IsConsoleHandle(PebParams->StandardOutput)) + { + Params->StandardOutput = PebParams->StandardOutput; + } + if (InheritHandles || IsConsoleHandle(PebParams->StandardError)) + { + Params->StandardError = PebParams->StandardError; + } +} + +NTSTATUS +STDCALL +BasepInitializeEnvironment(HANDLE ProcessHandle, + PPEB Peb, + LPWSTR ApplicationPathName, + LPWSTR lpCurrentDirectory, + LPWSTR lpCommandLine, + LPVOID Environment, + LPSTARTUPINFOW StartupInfo, + DWORD CreationFlags, + BOOL InheritHandles, + HANDLE hInput, + HANDLE hOutput) +{ + WCHAR FullPath[MAX_PATH]; + LPWSTR Remaining; + LPWSTR DllPathString; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PRTL_USER_PROCESS_PARAMETERS RemoteParameters = NULL; + UNICODE_STRING DllPath, ImageName, CommandLine, CurrentDirectory; + UINT RetVal; + NTSTATUS Status; + PWCHAR ScanChar; + ULONG EnviroSize; + ULONG Size; + UNICODE_STRING Desktop, Shell, Runtime, Title; + PPEB OurPeb = NtCurrentPeb(); + + DPRINT("BasepInitializeEnvironment\n"); + + /* Get the full path name */ + RetVal = GetFullPathNameW(ApplicationPathName, + MAX_PATH, + FullPath, + &Remaining); + DPRINT("ApplicationPathName: %S, FullPath: %S\n", ApplicationPathName, + FullPath); + + /* Get the DLL Path */ + DllPathString = BasepGetDllPath(FullPath, Environment); + + /* Initialize Strings */ + RtlInitUnicodeString(&DllPath, DllPathString); + RtlInitUnicodeString(&ImageName, FullPath); + RtlInitUnicodeString(&CommandLine, lpCommandLine); + RtlInitUnicodeString(&CurrentDirectory, lpCurrentDirectory); + + /* Initialize more Strings from the Startup Info */ + if (StartupInfo->lpDesktop) + { + RtlInitUnicodeString(&Desktop, StartupInfo->lpDesktop); + } + else + { + RtlInitUnicodeString(&Desktop, L""); + } + if (StartupInfo->lpReserved) + { + RtlInitUnicodeString(&Shell, StartupInfo->lpReserved); + } + else + { + RtlInitUnicodeString(&Shell, L""); + } + if (StartupInfo->lpTitle) + { + RtlInitUnicodeString(&Title, StartupInfo->lpTitle); + } + else + { + RtlInitUnicodeString(&Title, L""); + } + + /* This one is special because the length can differ */ + Runtime.Buffer = (LPWSTR)StartupInfo->lpReserved2; + Runtime.MaximumLength = Runtime.Length = StartupInfo->cbReserved2; + + /* Create the Parameter Block */ + DPRINT("Creating Process Parameters: %wZ %wZ %wZ %wZ %wZ %wZ %wZ\n", + &ImageName, &DllPath, &CommandLine, &Desktop, &Title, &Shell, + &Runtime); + Status = RtlCreateProcessParameters(&ProcessParameters, + &ImageName, + &DllPath, + lpCurrentDirectory ? + &CurrentDirectory : NULL, + &CommandLine, + Environment, + &Title, + &Desktop, + &Shell, + &Runtime); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create process parameters!\n"); + return Status; + } + + /* Check if we got an environment. If not, use ours */ + if (Environment) + { + /* Save pointer and start lookup */ + Environment = ScanChar = ProcessParameters->Environment; + } + else + { + /* Save pointer and start lookup */ + Environment = ScanChar = OurPeb->ProcessParameters->Environment; + } + + /* Find the environment size */ + if (ScanChar) + { + while (*ScanChar) while (*ScanChar++); + + /* Calculate the size of the block */ + EnviroSize = (ULONG)((ULONG_PTR)ScanChar - (ULONG_PTR)Environment); + DPRINT("EnvironmentSize %ld\n", EnviroSize); + + /* Allocate and Initialize new Environment Block */ + Size = EnviroSize; + ProcessParameters->Environment = NULL; + Status = ZwAllocateVirtualMemory(ProcessHandle, + (PVOID*)&ProcessParameters->Environment, + 0, + &Size, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to allocate Environment Block\n"); + return(Status); + } + + /* Write the Environment Block */ + ZwWriteVirtualMemory(ProcessHandle, + ProcessParameters->Environment, + Environment, + EnviroSize, + NULL); + } + + /* Write new parameters */ + ProcessParameters->StartingX = StartupInfo->dwX; + ProcessParameters->StartingY = StartupInfo->dwY; + ProcessParameters->CountX = StartupInfo->dwXSize; + ProcessParameters->CountY = StartupInfo->dwYSize; + ProcessParameters->CountCharsX = StartupInfo->dwXCountChars; + ProcessParameters->CountCharsY = StartupInfo->dwYCountChars; + ProcessParameters->FillAttribute = StartupInfo->dwFillAttribute; + ProcessParameters->WindowFlags = StartupInfo->dwFlags; + ProcessParameters->ShowWindowFlags = StartupInfo->wShowWindow; + + /* Write the handles only if we have to */ + if (StartupInfo->dwFlags & STARTF_USESTDHANDLES) + { + ProcessParameters->StandardInput = StartupInfo->hStdInput; + ProcessParameters->StandardOutput = StartupInfo->hStdOutput; + ProcessParameters->StandardError = StartupInfo->hStdError; + } + + /* Use Special Flags for ConDllInitialize in Kernel32 */ + if (CreationFlags & DETACHED_PROCESS) + { + ProcessParameters->ConsoleHandle = HANDLE_DETACHED_PROCESS; + } + else if (CreationFlags & CREATE_NO_WINDOW) + { + ProcessParameters->ConsoleHandle = HANDLE_CREATE_NO_WINDOW; + } + else if (CreationFlags & CREATE_NEW_CONSOLE) + { + ProcessParameters->ConsoleHandle = HANDLE_CREATE_NEW_CONSOLE; + } + else + { + /* Inherit our Console Handle */ + ProcessParameters->ConsoleHandle = OurPeb->ProcessParameters->ConsoleHandle; + + /* Is the shell trampling on our Handles? */ + if (!(StartupInfo->dwFlags & + (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) + { + /* Use handles from PEB, if inheriting or they are console */ + BasepCopyHandles(ProcessParameters, + OurPeb->ProcessParameters, + InheritHandles); + } + } + + /* Also set the Console Flag */ + if (CreationFlags & CREATE_NEW_PROCESS_GROUP) + { + ProcessParameters->ConsoleFlags = 1; + } + + /* Allocate memory for the parameter block */ + Size = ProcessParameters->Length; + Status = NtAllocateVirtualMemory(ProcessHandle, + (PVOID*)&RemoteParameters, + 0, + &Size, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to allocate Parameters Block\n"); + return(Status); + } + + /* Set the allocated size */ + ProcessParameters->MaximumLength = Size; + + /* Handle some Parameter Flags */ + ProcessParameters->ConsoleFlags = (CreationFlags & CREATE_NEW_PROCESS_GROUP); + ProcessParameters->Flags |= (CreationFlags & PROFILE_USER) ? + PPF_PROFILE_USER : 0; + ProcessParameters->Flags |= (CreationFlags & PROFILE_KERNEL) ? + PPF_PROFILE_KERNEL : 0; + ProcessParameters->Flags |= (CreationFlags & PROFILE_SERVER) ? + PPF_PROFILE_SERVER : 0; + ProcessParameters->Flags |= (NtCurrentPeb()->ProcessParameters->Flags & + PPF_DISABLE_HEAP_CHECKS); + + /* + * FIXME: Our console init stuff is messy. See my comment in kernel32's + * DllMain. + */ + if (!ProcessParameters->StandardInput) ProcessParameters->StandardInput = hInput; + if (!ProcessParameters->StandardOutput) ProcessParameters->StandardOutput = hOutput; + if (!ProcessParameters->StandardError) ProcessParameters->StandardError = hOutput; + + /* Write the Parameter Block */ + Status = NtWriteVirtualMemory(ProcessHandle, + RemoteParameters, + ProcessParameters, + ProcessParameters->Length, + NULL); + + /* Write the PEB Pointer */ + Status = NtWriteVirtualMemory(ProcessHandle, + &Peb->ProcessParameters, + &RemoteParameters, + sizeof(PVOID), + NULL); + + /* Cleanup */ + RtlFreeHeap(GetProcessHeap(), 0, DllPath.Buffer); + RtlDestroyProcessParameters(ProcessParameters); + + DPRINT("Completed\n"); + return STATUS_SUCCESS; +} /* FUNCTIONS ****************************************************************/ -extern __declspec(noreturn) -VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag); - -__declspec(dllimport) -PRTL_BASE_PROCESS_START_ROUTINE RtlBaseProcessStartRoutine; - -typedef NTSTATUS STDCALL (K32_MBSTR_TO_WCSTR) -( - UNICODE_STRING *, - ANSI_STRING *, - BOOLEAN -); - -NTSTATUS STDCALL K32MbStrToWcStr(IN K32_MBSTR_TO_WCSTR * True, - UNICODE_STRING * DestStr, - ANSI_STRING * SourceStr, - BOOLEAN Allocate) -{ - if(SourceStr->Buffer == NULL) - { - DestStr->Length = DestStr->MaximumLength = 0; - DestStr->Buffer = NULL; - return STATUS_SUCCESS; - } - - return True(DestStr, SourceStr, Allocate); -} - -VOID STDCALL RtlRosR32AttribsToNativeAttribs(OUT OBJECT_ATTRIBUTES * NativeAttribs, - IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL) -{ - NativeAttribs->Length = sizeof(*NativeAttribs); - NativeAttribs->ObjectName = NULL; - NativeAttribs->RootDirectory = NULL; - NativeAttribs->Attributes = 0; - NativeAttribs->SecurityQualityOfService = NULL; - - - if(Ros32Attribs != NULL && Ros32Attribs->nLength >= sizeof(*Ros32Attribs)) - { - NativeAttribs->SecurityDescriptor = Ros32Attribs->lpSecurityDescriptor; - - if(Ros32Attribs->bInheritHandle) - { - NativeAttribs->Attributes |= OBJ_INHERIT; - } - } - else - { - NativeAttribs->SecurityDescriptor = NULL; - } -} - -VOID STDCALL RtlRosR32AttribsToNativeAttribsNamed(OUT OBJECT_ATTRIBUTES * NativeAttribs, - IN SECURITY_ATTRIBUTES * Ros32Attribs OPTIONAL, - OUT UNICODE_STRING * NativeName OPTIONAL, - IN WCHAR * Ros32Name OPTIONAL, - IN HANDLE Ros32NameRoot OPTIONAL) -{ - if(!NativeAttribs) return; - - RtlRosR32AttribsToNativeAttribs(NativeAttribs, Ros32Attribs); - - if(Ros32Name != NULL && NativeName != NULL) - { - RtlInitUnicodeString(NativeName, Ros32Name); - - NativeAttribs->ObjectName = NativeName; - NativeAttribs->RootDirectory = Ros32NameRoot; - NativeAttribs->Attributes |= OBJ_CASE_INSENSITIVE; - } -} - - -/* - * @implemented - */ -BOOL STDCALL CreateProcessA(LPCSTR lpApplicationName, - LPSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCSTR lpCurrentDirectory, - LPSTARTUPINFOA lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation) /* * FUNCTION: The CreateProcess function creates a new process and its * primary thread. The new process executes the specified executable file @@ -123,1277 +618,838 @@ BOOL STDCALL CreateProcessA(LPCSTR lpApplicationName, * lpCurrentDirectory = Pointer to current directory name * lpStartupInfo = Pointer to startup info * lpProcessInformation = Pointer to process information - */ -{ - UNICODE_STRING wstrApplicationName; - UNICODE_STRING wstrCurrentDirectory; - UNICODE_STRING wstrCommandLine; - UNICODE_STRING wstrReserved; - UNICODE_STRING wstrDesktop; - UNICODE_STRING wstrTitle; - UNICODE_STRING wstrEnvVar; - ANSI_STRING strApplicationName; - ANSI_STRING strCurrentDirectory; - ANSI_STRING strCommandLine; - ANSI_STRING strReserved; - ANSI_STRING strDesktop; - ANSI_STRING strTitle; - BOOL bRetVal; - STARTUPINFOW wsiStartupInfo; - - NTSTATUS (STDCALL *pTrue)(UNICODE_STRING *, - ANSI_STRING *, - BOOLEAN); - - ULONG (STDCALL *pRtlMbStringToUnicodeSize)(ANSI_STRING *); - - DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, " - "lpStartupInfo %x, lpProcessInformation %x\n", - dwCreationFlags, lpEnvironment, lpCurrentDirectory, - lpStartupInfo, lpProcessInformation); - - /* multibyte strings are ANSI */ - if(bIsFileApiAnsi) - { - pTrue = RtlAnsiStringToUnicodeString; - pRtlMbStringToUnicodeSize = RtlAnsiStringToUnicodeSize; - } - /* multibyte strings are OEM */ - else - { - pTrue = RtlOemStringToUnicodeString; - pRtlMbStringToUnicodeSize = RtlOemStringToUnicodeSize; - } - - /* invalid parameter */ - if(lpStartupInfo == NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - /* convert the environment */ - if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) - { - PCHAR pcScan; - SIZE_T nEnvLen = 0; - ANSI_STRING strEnvVar; - NTSTATUS Status; - - /* scan the environment to calculate its Unicode size */ - pcScan = lpEnvironment; - do - { - pcScan += strlen(pcScan) + 1; - } - while (*pcScan); - - nEnvLen = (ULONG_PTR)pcScan - (ULONG_PTR)lpEnvironment + 1; - - /* environment too large */ - if(nEnvLen > (SIZE_T)((USHORT)~0)) - { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - - strEnvVar.Buffer = lpEnvironment; - strEnvVar.MaximumLength = strEnvVar.Length = nEnvLen; - - Status = K32MbStrToWcStr(pTrue, &wstrEnvVar, &strEnvVar, TRUE); - - /* failure */ - if (!NT_SUCCESS(Status)) - { - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } - } - - - /* convert the strings */ - RtlInitAnsiString(&strCommandLine, lpCommandLine); - RtlInitAnsiString(&strApplicationName, (LPSTR)lpApplicationName); - RtlInitAnsiString(&strCurrentDirectory, (LPSTR)lpCurrentDirectory); - RtlInitAnsiString(&strReserved, (LPSTR)lpStartupInfo->lpReserved); - RtlInitAnsiString(&strDesktop, (LPSTR)lpStartupInfo->lpDesktop); - RtlInitAnsiString(&strTitle, (LPSTR)lpStartupInfo->lpTitle); - - K32MbStrToWcStr(pTrue, &wstrCommandLine, &strCommandLine, TRUE); - K32MbStrToWcStr(pTrue, &wstrApplicationName, &strApplicationName, TRUE); - K32MbStrToWcStr(pTrue, &wstrCurrentDirectory, &strCurrentDirectory, TRUE); - K32MbStrToWcStr(pTrue, &wstrReserved, &strReserved, TRUE); - K32MbStrToWcStr(pTrue, &wstrDesktop, &strDesktop, TRUE); - K32MbStrToWcStr(pTrue, &wstrTitle, &strTitle, TRUE); - - /* convert the startup information */ - memcpy(&wsiStartupInfo, lpStartupInfo, sizeof(wsiStartupInfo)); - - wsiStartupInfo.lpReserved = wstrReserved.Buffer; - wsiStartupInfo.lpDesktop = wstrDesktop.Buffer; - wsiStartupInfo.lpTitle = wstrTitle.Buffer; - - DPRINT("wstrApplicationName %wZ\n", &wstrApplicationName); - DPRINT("wstrCommandLine %wZ\n", &wstrCommandLine); - DPRINT("wstrCurrentDirectory %wZ\n", &wstrCurrentDirectory); - DPRINT("wstrReserved %wZ\n", &wstrReserved); - DPRINT("wstrDesktop %wZ\n", &wstrDesktop); - DPRINT("wstrTitle %wZ\n", &wstrTitle); - - DPRINT("wstrApplicationName.Buffer %p\n", wstrApplicationName.Buffer); - DPRINT("wstrCommandLine.Buffer %p\n", wstrCommandLine.Buffer); - DPRINT("wstrCurrentDirectory.Buffer %p\n", wstrCurrentDirectory.Buffer); - DPRINT("wstrReserved.Buffer %p\n", wstrReserved.Buffer); - DPRINT("wstrDesktop.Buffer %p\n", wstrDesktop.Buffer); - DPRINT("wstrTitle.Buffer %p\n", wstrTitle.Buffer); - - DPRINT("sizeof(STARTUPINFOA) %lu\n", sizeof(STARTUPINFOA)); - DPRINT("sizeof(STARTUPINFOW) %lu\n", sizeof(STARTUPINFOW)); - - /* call the Unicode function */ - bRetVal = CreateProcessW(wstrApplicationName.Buffer, - wstrCommandLine.Buffer, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - !lpEnvironment || (dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ? lpEnvironment : wstrEnvVar.Buffer, - wstrCurrentDirectory.Buffer, - &wsiStartupInfo, - lpProcessInformation); - - RtlFreeUnicodeString(&wstrApplicationName); - RtlFreeUnicodeString(&wstrCommandLine); - RtlFreeUnicodeString(&wstrCurrentDirectory); - RtlFreeUnicodeString(&wstrReserved); - RtlFreeUnicodeString(&wstrDesktop); - RtlFreeUnicodeString(&wstrTitle); - - if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) - { - RtlFreeUnicodeString(&wstrEnvVar); - } - - return bRetVal; -} - - -_SEH_FILTER(BaseExceptionFilter) -{ - EXCEPTION_POINTERS * ExceptionInfo = _SEH_GetExceptionPointers(); - LONG ExceptionDisposition = EXCEPTION_EXECUTE_HANDLER; - - if (GlobalTopLevelExceptionFilter != NULL) - { - _SEH_TRY - { - ExceptionDisposition = GlobalTopLevelExceptionFilter(ExceptionInfo); - } - _SEH_HANDLE - { - ExceptionDisposition = UnhandledExceptionFilter(ExceptionInfo); - } - _SEH_END; - } - - return ExceptionDisposition; -} - - -VOID STDCALL -BaseProcessStart(LPTHREAD_START_ROUTINE lpStartAddress, - DWORD lpParameter) -{ - UINT uExitCode = 0; - - DPRINT("BaseProcessStart(..) - setting up exception frame.\n"); - - _SEH_TRY - { - uExitCode = (lpStartAddress)((PVOID)lpParameter); - } - _SEH_EXCEPT(BaseExceptionFilter) - { - uExitCode = _SEH_GetExceptionCode(); - } - _SEH_END; - - ExitProcess(uExitCode); -} - - -HANDLE STDCALL KlCreateFirstThread(HANDLE ProcessHandle, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - PSECTION_IMAGE_INFORMATION Sii, - LPTHREAD_START_ROUTINE lpStartAddress, - DWORD dwCreationFlags, - LPDWORD lpThreadId) -{ - OBJECT_ATTRIBUTES oaThreadAttribs; - CLIENT_ID cidClientId; - PVOID pTrueStartAddress; - NTSTATUS nErrCode; - HANDLE hThread; - - /* convert the thread attributes */ - RtlRosR32AttribsToNativeAttribs(&oaThreadAttribs, lpThreadAttributes); - - /* native image */ - if(Sii->SubsystemType != IMAGE_SUBSYSTEM_NATIVE) - { - pTrueStartAddress = (PVOID)BaseProcessStart; - } - /* Win32 image */ - else - { - pTrueStartAddress = (PVOID)RtlBaseProcessStartRoutine; - } - - DPRINT("RtlRosCreateUserThreadVa\n" - "(\n" - " ProcessHandle %p,\n" - " ObjectAttributes %p,\n" - " CreateSuspended %d,\n" - " StackZeroBits %d,\n" - " StackReserve %lu,\n" - " StackCommit %lu,\n" - " StartAddress %p,\n" - " ThreadHandle %p,\n" - " ClientId %p,\n" - " ParameterCount %u,\n" - " Parameters[0] %p,\n" - " Parameters[1] %p\n" - ")\n", - ProcessHandle, - &oaThreadAttribs, - dwCreationFlags & CREATE_SUSPENDED, - 0, - Sii->MaximumStackSize, - Sii->CommittedStackSize, - pTrueStartAddress, - &hThread, - &cidClientId, - 2, - lpStartAddress, - PEB_BASE); - - /* create the first thread */ - nErrCode = RtlRosCreateUserThreadVa(ProcessHandle, - &oaThreadAttribs, - dwCreationFlags & CREATE_SUSPENDED, - 0, - &(Sii->MaximumStackSize), - &(Sii->CommittedStackSize), - pTrueStartAddress, - &hThread, - &cidClientId, - 2, - (ULONG_PTR)lpStartAddress, - (ULONG_PTR)PEB_BASE); - /* failure */ - if(!NT_SUCCESS(nErrCode)) - { - SetLastErrorByStatus(nErrCode); - return NULL; - } - - DPRINT("StackReserve %p\n" - "StackCommit %p\n" - "ThreadHandle %p\n" - "ClientId.UniqueThread %p\n", - Sii->MaximumStackSize, - Sii->CommittedStackSize, - hThread, - cidClientId.UniqueThread); - - /* success */ - if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread; - return hThread; -} - -HANDLE KlMapFile(LPCWSTR lpApplicationName) -{ - HANDLE hFile; - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING ApplicationNameString; - OBJECT_ATTRIBUTES ObjectAttributes; - PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; - NTSTATUS Status; - HANDLE hSection; - - hFile = NULL; - - /* - * Find the application name - */ - - if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpApplicationName, - &ApplicationNameString, - NULL, - NULL)) - return NULL; - - DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer); - - InitializeObjectAttributes(&ObjectAttributes, - &ApplicationNameString, - OBJ_CASE_INSENSITIVE, - NULL, - SecurityDescriptor); - - /* - * Try to open the executable - */ - - Status = NtOpenFile(&hFile, - SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_DELETE|FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE); - - RtlFreeUnicodeString (&ApplicationNameString); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Failed to open file\n"); - SetLastErrorByStatus (Status); - return(NULL); - } - - Status = NtCreateSection(&hSection, - SECTION_ALL_ACCESS, - NULL, - NULL, - PAGE_EXECUTE, - SEC_IMAGE, - hFile); - NtClose(hFile); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Failed to create section\n"); - SetLastErrorByStatus (Status); - return(NULL); - } - - return(hSection); -} - -static NTSTATUS KlInitPeb(HANDLE ProcessHandle, - PRTL_USER_PROCESS_PARAMETERS Ppb, - PVOID * ImageBaseAddress, - ULONG ImageSubSystem) -{ - NTSTATUS Status; - PVOID PpbBase; - ULONG PpbSize; - ULONG BytesWritten; - ULONG Offset; - PVOID ParentEnv = NULL; - PVOID EnvPtr = NULL; - PWCHAR ptr; - ULONG EnvSize = 0, EnvSize1 = 0; - - /* create the Environment */ - if (Ppb->Environment != NULL) - { - ParentEnv = Ppb->Environment; - ptr = ParentEnv; - while (*ptr) - { - while(*ptr++); - } - ptr++; - EnvSize = (ULONG)((ULONG_PTR)ptr - (ULONG_PTR)ParentEnv); - } - else if (NtCurrentPeb()->ProcessParameters->Environment != NULL) - { - MEMORY_BASIC_INFORMATION MemInfo; - ParentEnv = NtCurrentPeb()->ProcessParameters->Environment; - - Status = NtQueryVirtualMemory (NtCurrentProcess (), - ParentEnv, - MemoryBasicInformation, - &MemInfo, - sizeof(MEMORY_BASIC_INFORMATION), - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - EnvSize = MemInfo.RegionSize; - } - DPRINT("EnvironmentSize %ld\n", EnvSize); - - /* allocate and initialize new environment block */ - if (EnvSize != 0) - { - EnvSize1 = EnvSize; - Status = NtAllocateVirtualMemory(ProcessHandle, - &EnvPtr, - 0, - &EnvSize1, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - NtWriteVirtualMemory(ProcessHandle, - EnvPtr, - ParentEnv, - EnvSize, - &BytesWritten); - } - - /* create the PPB */ - PpbBase = NULL; - PpbSize = Ppb->MaximumLength; - Status = NtAllocateVirtualMemory(ProcessHandle, - &PpbBase, - 0, - &PpbSize, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - //DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength); - NtWriteVirtualMemory(ProcessHandle, - PpbBase, - Ppb, - Ppb->MaximumLength, - &BytesWritten); - - /* write pointer to environment */ - Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment); - NtWriteVirtualMemory(ProcessHandle, - (PVOID)((ULONG_PTR)PpbBase + Offset), - &EnvPtr, - sizeof(EnvPtr), - &BytesWritten); - - /* write pointer to process parameter block */ - Offset = FIELD_OFFSET(PEB, ProcessParameters); - NtWriteVirtualMemory(ProcessHandle, - (PVOID)(PEB_BASE + Offset), - &PpbBase, - sizeof(PpbBase), - &BytesWritten); - - /* Write image subsystem */ - Offset = FIELD_OFFSET(PEB, ImageSubSystem); - NtWriteVirtualMemory(ProcessHandle, - (PVOID)(PEB_BASE + Offset), - &ImageSubSystem, - sizeof(ImageSubSystem), - &BytesWritten); - - /* Read image base address. */ - Offset = FIELD_OFFSET(PEB, ImageBaseAddress); - NtReadVirtualMemory(ProcessHandle, - (PVOID)(PEB_BASE + Offset), - ImageBaseAddress, - sizeof(PVOID), - &BytesWritten); - - return(STATUS_SUCCESS); -} - - -/************************************************************************* - * GetFileName * - * Helper for CreateProcessW: retrieve the file name to load from the - * app name and command line. Store the file name in buffer, and - * return a possibly modified command line. - * - * FIXME: use CurDir to search for the executable file in the new working directory + * @implemented */ -static LPWSTR FASTCALL -GetFileName(LPCWSTR CurDir, LPCWSTR AppName, LPWSTR CmdLine, LPWSTR Buffer, - unsigned BufLen) -{ - WCHAR *Name, *Pos, *Ret = NULL; - const WCHAR *p; +BOOL +STDCALL +CreateProcessA(LPCSTR lpApplicationName, + LPSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCSTR lpCurrentDirectory, + LPSTARTUPINFOA lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) +{ + PUNICODE_STRING CommandLine = NULL; + UNICODE_STRING DummyString; + UNICODE_STRING LiveCommandLine; + UNICODE_STRING ApplicationName; + UNICODE_STRING CurrentDirectory; + BOOL bRetVal; + STARTUPINFOW StartupInfo; - /* if we have an app name, everything is easy */ + DPRINT("dwCreationFlags %x, lpEnvironment %x, lpCurrentDirectory %x, " + "lpStartupInfo %x, lpProcessInformation %x\n", + dwCreationFlags, lpEnvironment, lpCurrentDirectory, + lpStartupInfo, lpProcessInformation); + + /* Copy Startup Info */ + DPRINT("Foo\n"); + RtlMoveMemory(&StartupInfo, lpStartupInfo, sizeof(*lpStartupInfo)); + DPRINT("Foo\n"); + + /* Initialize all strings to nothing */ + LiveCommandLine.Buffer = NULL; + DummyString.Buffer = NULL; + ApplicationName.Buffer = NULL; + CurrentDirectory.Buffer = NULL; + StartupInfo.lpDesktop = NULL; + StartupInfo.lpReserved = NULL; + StartupInfo.lpTitle = NULL; + + /* Convert the Command line */ + if (lpCommandLine) + { + DPRINT("Foo\n"); + /* If it's too long, then we'll have a problem */ + if ((strlen(lpCommandLine) + 1) * sizeof(WCHAR) < + NtCurrentTeb()->StaticUnicodeString.MaximumLength) + { + /* Cache it in the TEB */ + DPRINT("Foo\n"); + CommandLine = Basep8BitStringToCachedUnicodeString(lpCommandLine); + } + else + { + /* Use a dynamic version */ + DPRINT("Foo\n"); + Basep8BitStringToLiveUnicodeString(&LiveCommandLine, + lpCommandLine); + } + } + else + { + DPRINT("Foo\n"); + /* The logic below will use CommandLine, so we must make it valid */ + CommandLine = &DummyString; + } + + /* Convert the Name and Directory */ + if (lpApplicationName) + { + DPRINT("Foo\n"); + Basep8BitStringToLiveUnicodeString(&ApplicationName, + lpApplicationName); + } + if (lpCurrentDirectory) + { + DPRINT("Foo\n"); + Basep8BitStringToLiveUnicodeString(&CurrentDirectory, + lpCurrentDirectory); + } + + /* Now convert Startup Strings */ + if (lpStartupInfo->lpReserved) + { + DPRINT("Foo\n"); + BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpReserved, + &StartupInfo.lpReserved); + } + if (lpStartupInfo->lpDesktop) + { + DPRINT("Foo\n"); + BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpDesktop, + &StartupInfo.lpDesktop); + } + if (lpStartupInfo->lpTitle) + { + DPRINT("Foo\n"); + BasepAnsiStringToHeapUnicodeString(lpStartupInfo->lpTitle, + &StartupInfo.lpTitle); + } - if (NULL != AppName) - { - /* use the unmodified app name as file name */ - wcsncpy(Buffer, AppName, BufLen ); - Ret = CmdLine; - if (NULL == Ret || L'\0' == CmdLine[0]) - { - /* no command-line, create one */ - Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(AppName) + 3) * sizeof(WCHAR)); - if (NULL != Ret) - { - Ret[0] = L'"'; - wcscpy(Ret + 1, AppName); - wcscat(Ret, L"\""); - } - } - return Ret; - } + /* Call the Unicode function */ + bRetVal = CreateProcessW(ApplicationName.Buffer, + LiveCommandLine.Buffer ? + LiveCommandLine.Buffer : CommandLine->Buffer, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + CurrentDirectory.Buffer, + &StartupInfo, + lpProcessInformation); - if (NULL == CmdLine) - { - SetLastError(ERROR_INVALID_PARAMETER); - return NULL; - } + /* Clean up */ + RtlFreeUnicodeString(&ApplicationName); + RtlFreeUnicodeString(&LiveCommandLine); + RtlFreeUnicodeString(&CurrentDirectory); + RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpDesktop); + RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpReserved); + RtlFreeHeap(GetProcessHeap(), 0, StartupInfo.lpTitle); - /* first check for a quoted file name */ - if (L'"' == CmdLine[0] && NULL != (p = wcschr(CmdLine + 1, L'"'))) - { - int Len = p - CmdLine - 1; - /* extract the quoted portion as file name */ - Name = RtlAllocateHeap(GetProcessHeap(), 0, (Len + 1) * sizeof(WCHAR)); - if (NULL == Name) - { - return NULL; - } - memcpy(Name, CmdLine + 1, Len * sizeof(WCHAR)); - Name[Len] = L'\0'; - - if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL)) - { - Ret = CmdLine; /* no change necessary */ - } - - RtlFreeHeap(GetProcessHeap(), 0, Name); - return Ret; - } - - /* now try the command-line word by word */ - Name = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 1) * sizeof(WCHAR)); - if (NULL == Name) - { - return NULL; - } - Pos = Name; - p = CmdLine; - - while (L'\0' != *p) - { - do - { - *Pos++ = *p++; - } - while (L'\0' != *p && L' ' != *p); - *Pos = 0; - if (SearchPathW(NULL, Name, L".exe", BufLen, Buffer, NULL)) - { - Ret = CmdLine; - break; - } - } - - if (NULL == Ret || NULL == wcschr(Name, L' ')) - { - RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */ - return Ret; - } - - /* now build a new command-line with quotes */ - Ret = RtlAllocateHeap(GetProcessHeap(), 0, (wcslen(CmdLine) + 3) * sizeof(WCHAR)); - if (NULL == Ret) - { - RtlFreeHeap(GetProcessHeap(), 0, Name); /* no change necessary */ - return NULL; - } - Ret[0] = L'"'; - wcscpy(Ret + 1, Name); - wcscat(Ret, L"\""); - wcscat(Ret, p); - - RtlFreeHeap(GetProcessHeap(), 0, Name); - return Ret; + /* Return what Unicode did */ + return bRetVal; } - /* * @implemented */ -BOOL STDCALL +BOOL +STDCALL CreateProcessW(LPCWSTR lpApplicationName, - LPWSTR lpCommandLine, - LPSECURITY_ATTRIBUTES lpProcessAttributes, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - BOOL bInheritHandles, - DWORD dwCreationFlags, - LPVOID lpEnvironment, - LPCWSTR lpCurrentDirectory, - LPSTARTUPINFOW lpStartupInfo, - LPPROCESS_INFORMATION lpProcessInformation) + LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, + DWORD dwCreationFlags, + LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) { - HANDLE hSection, hProcess, hThread; - NTSTATUS Status; - WCHAR ImagePathName[256]; - UNICODE_STRING ImagePathName_U; - PROCESS_BASIC_INFORMATION ProcessBasicInfo; - ULONG retlen; - PRTL_USER_PROCESS_PARAMETERS Ppb; - UNICODE_STRING CommandLine_U; - CSR_API_MESSAGE CsrRequest; - ULONG Request; - PWCHAR s, e; - ULONG i; - UNICODE_STRING CurrentDirectory_U; - SECTION_IMAGE_INFORMATION Sii; - WCHAR TempCurrentDirectoryW[256]; - WCHAR TempApplicationNameW[256]; - WCHAR TempCommandLineNameW[256]; - UNICODE_STRING RuntimeInfo_U; - PVOID ImageBaseAddress; - BOOL InputSet, OutputSet, ErrorSet; - BOOL InputDup = FALSE, OutputDup = FALSE, ErrorDup = FALSE; - WCHAR Name[MAX_PATH]; - WCHAR *TidyCmdLine; - BOOL IsBatchFile = FALSE; - PROCESS_PRIORITY_CLASS PriorityClass; - OBJECT_ATTRIBUTES ProcObjectAttributes; - ULONG ProcAttributes = 0; - PVOID ProcSecurity = NULL; - - DPRINT("CreateProcessW(lpApplicationName '%S', lpCommandLine '%S')\n", - lpApplicationName, lpCommandLine); - - TidyCmdLine = GetFileName(lpCurrentDirectory, lpApplicationName, lpCommandLine, Name, - sizeof(Name) / sizeof(WCHAR)); - if (NULL == TidyCmdLine) - { - return FALSE; - } - DPRINT("TidyCmdLine '%S'\n", TidyCmdLine); - - if (lpApplicationName != NULL && lpApplicationName[0] != 0) - { - wcscpy (TempApplicationNameW, lpApplicationName); - i = wcslen(TempApplicationNameW); - if (TempApplicationNameW[i - 1] == L'.') - { - TempApplicationNameW[i - 1] = 0; - } - else - { - s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/')); - if (s == NULL) - { - s = TempApplicationNameW; - } - else - { - s++; - } - e = wcsrchr(s, L'.'); - if (e == NULL) - { - wcscat(s, L".exe"); - e = wcsrchr(s, L'.'); - } - } - } - else if (L'"' == TidyCmdLine[0]) - { - wcscpy(TempApplicationNameW, TidyCmdLine + 1); - s = wcschr(TempApplicationNameW, L'"'); - if (NULL == s) - { - return FALSE; - } - *s = L'\0'; - } - else - { - wcscpy(TempApplicationNameW, TidyCmdLine); - s = wcschr(TempApplicationNameW, L' '); - if (NULL != s) - { - *s = L'\0'; - } - } - s = max(wcsrchr(TempApplicationNameW, L'\\'), wcsrchr(TempApplicationNameW, L'/')); - if (NULL == s) - { - s = TempApplicationNameW; - } - s = wcsrchr(s, L'.'); - if (NULL == s) - { - wcscat(TempApplicationNameW, L".exe"); - } - - if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s)) - { - return FALSE; - } - - e = wcsrchr(s, L'.'); - if (e != NULL && (!_wcsicmp(e, L".bat") || !_wcsicmp(e, L".cmd"))) - { - // the command is a batch file - IsBatchFile = TRUE; - if (lpApplicationName != NULL && lpApplicationName[0]) - { - // FIXME: use COMSPEC for the command interpreter - wcscpy(TempCommandLineNameW, L"cmd /c "); - wcscat(TempCommandLineNameW, lpApplicationName); - lpCommandLine = TempCommandLineNameW; - wcscpy(TempApplicationNameW, L"cmd.exe"); - if (!SearchPathW(NULL, TempApplicationNameW, NULL, sizeof(ImagePathName)/sizeof(WCHAR), ImagePathName, &s)) - { - return FALSE; - } - } - else - { - return FALSE; - } - } - - /* - * Process the application name and command line - */ - RtlInitUnicodeString(&ImagePathName_U, ImagePathName); - RtlInitUnicodeString(&CommandLine_U, IsBatchFile ? lpCommandLine : TidyCmdLine); - - DPRINT("ImagePathName_U '%S'\n", ImagePathName_U.Buffer); - DPRINT("lpCommandLine '%S'\n", lpCommandLine); - DPRINT("TidyCmdLine '%S'\n", TidyCmdLine); - - /* Initialize the current directory string */ - if (lpCurrentDirectory != NULL) - { - RtlInitUnicodeString(&CurrentDirectory_U, - lpCurrentDirectory); - } - else - { - GetCurrentDirectoryW(256, TempCurrentDirectoryW); - RtlInitUnicodeString(&CurrentDirectory_U, - TempCurrentDirectoryW); - } - - /* - * Create a section for the executable - */ - - hSection = KlMapFile (ImagePathName); - if (hSection == NULL) - { -///////////////////////////////////////// - /* - * Inspect the image to determine executable flavour - */ - IO_STATUS_BLOCK IoStatusBlock; - UNICODE_STRING ApplicationNameString; - OBJECT_ATTRIBUTES ObjectAttributes; - PSECURITY_DESCRIPTOR SecurityDescriptor = NULL; - IMAGE_DOS_HEADER DosHeader; - IO_STATUS_BLOCK Iosb; - LARGE_INTEGER Offset; - HANDLE hFile = NULL; - DPRINT("Inspecting Image Header for image type id\n"); - - // Find the application name - if (!RtlDosPathNameToNtPathName_U((LPWSTR)lpApplicationName, - &ApplicationNameString, NULL, NULL)) - { - return FALSE; - } - DPRINT("ApplicationName %S\n",ApplicationNameString.Buffer); - - InitializeObjectAttributes(&ObjectAttributes, - &ApplicationNameString, - OBJ_CASE_INSENSITIVE, - NULL, - SecurityDescriptor); - - // Try to open the executable - Status = NtOpenFile(&hFile, - SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA, - &ObjectAttributes, - &IoStatusBlock, - FILE_SHARE_DELETE|FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE); - - RtlFreeUnicodeString(&ApplicationNameString); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Failed to open file\n"); - SetLastErrorByStatus(Status); - return FALSE; - } - - // Read the dos header - Offset.QuadPart = 0; - Status = ZwReadFile(hFile, - NULL, - NULL, - NULL, - &Iosb, - &DosHeader, - sizeof(DosHeader), - &Offset, - 0); - - if (!NT_SUCCESS(Status)) - { - DPRINT("Failed to read from file\n"); - SetLastErrorByStatus(Status); - return FALSE; - } - if (Iosb.Information != sizeof(DosHeader)) - { - DPRINT("Failed to read dos header from file\n"); - SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT); - return FALSE; - } - - // Check the DOS signature - if (DosHeader.e_magic != IMAGE_DOS_SIGNATURE) - { - DPRINT("Failed dos magic check\n"); - SetLastErrorByStatus(STATUS_INVALID_IMAGE_FORMAT); - return FALSE; - } - NtClose(hFile); - - DPRINT("Launching VDM...\n"); - return CreateProcessW(L"ntvdm.exe", - (LPWSTR)lpApplicationName, - lpProcessAttributes, - lpThreadAttributes, - bInheritHandles, - dwCreationFlags, - lpEnvironment, - lpCurrentDirectory, - lpStartupInfo, - lpProcessInformation); - } -///////////////////////////////////////// - - /* - * Get some information about the executable - */ - Status = ZwQuerySection(hSection, - SectionImageInformation, - &Sii, - sizeof(Sii), - &i); - if (! NT_SUCCESS(Status)) - { - NtClose(hSection); - DPRINT("Unable to get SectionImageInformation, status 0x%x\n", Status); - SetLastErrorByStatus(Status); - return FALSE; - } - - if (0 != (Sii.ImageCharacteristics & IMAGE_FILE_DLL)) - { - NtClose(hSection); - DPRINT("Can't execute a DLL\n"); - SetLastError(ERROR_BAD_EXE_FORMAT); - return FALSE; - } - - if (IMAGE_SUBSYSTEM_WINDOWS_GUI != Sii.SubsystemType - && IMAGE_SUBSYSTEM_WINDOWS_CUI != Sii.SubsystemType) - { - NtClose(hSection); - DPRINT("Invalid subsystem %d\n", Sii.SubsystemType); - SetLastError(ERROR_CHILD_NOT_COMPLETE); - return FALSE; - } - - /* - * Initialize the process object attributes - */ - - if(lpProcessAttributes != NULL) - { - if(lpProcessAttributes->bInheritHandle) - { - ProcAttributes |= OBJ_INHERIT; - } - ProcSecurity = lpProcessAttributes->lpSecurityDescriptor; - } - - InitializeObjectAttributes(&ProcObjectAttributes, - NULL, - ProcAttributes, - NULL, - ProcSecurity); - /* - * initialize the process priority class structure - */ - PriorityClass.Foreground = FALSE; - - if(dwCreationFlags & IDLE_PRIORITY_CLASS) - { - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; - } - else if(dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS) - { - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL; - } - else if(dwCreationFlags & NORMAL_PRIORITY_CLASS) - { - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; - } - else if(dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS) - { - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL; - } - else if(dwCreationFlags & HIGH_PRIORITY_CLASS) - { - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH; - } - else if(dwCreationFlags & REALTIME_PRIORITY_CLASS) - { - /* FIXME - This is a privileged operation. If we don't have the privilege we should - rather use PROCESS_PRIORITY_CLASS_HIGH. */ - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME; - } - else - { - /* FIXME - what to do in this case? */ - PriorityClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL; - } - - /* - * Create a new process - */ - Status = NtCreateProcess(&hProcess, - PROCESS_ALL_ACCESS, - &ProcObjectAttributes, - NtCurrentProcess(), - bInheritHandles, - hSection, - NULL, - NULL); - /* FIXME - handle failure!!!!! */ - - Status = NtSetInformationProcess(hProcess, - ProcessPriorityClass, - &PriorityClass, - sizeof(PROCESS_PRIORITY_CLASS)); - /* FIXME - handle failure!!!!! */ - - if (lpStartupInfo) - { - if (lpStartupInfo->lpReserved2) - { - /* FIXME: - * ROUND_UP(xxx,2) + 2 is a dirty hack. RtlCreateProcessParameters assumes that - * the runtimeinfo is a unicode string and use RtlCopyUnicodeString for duplication. - * If is possible that this function overwrite the last information in runtimeinfo - * with the null terminator for the unicode string. - */ - RuntimeInfo_U.Length = RuntimeInfo_U.MaximumLength = (lpStartupInfo->cbReserved2 + 1) & ~1; - RuntimeInfo_U.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, RuntimeInfo_U.Length); - memcpy(RuntimeInfo_U.Buffer, lpStartupInfo->lpReserved2, lpStartupInfo->cbReserved2); - } - } - - /* - * Create the PPB - */ - RtlCreateProcessParameters(&Ppb, - &ImagePathName_U, - NULL, - lpCurrentDirectory ? &CurrentDirectory_U : NULL, - &CommandLine_U, - lpEnvironment, - NULL, - NULL, - NULL, - lpStartupInfo && lpStartupInfo->lpReserved2 ? &RuntimeInfo_U : NULL); - - if (lpStartupInfo && lpStartupInfo->lpReserved2) - RtlFreeHeap(GetProcessHeap(), 0, RuntimeInfo_U.Buffer); - - - /* - * Translate some handles for the new process - */ - if (Ppb->CurrentDirectory.Handle) - { - Status = NtDuplicateObject (NtCurrentProcess(), - Ppb->CurrentDirectory.Handle, - hProcess, - &Ppb->CurrentDirectory.Handle, - 0, - TRUE, - DUPLICATE_SAME_ACCESS); - /* FIXME - handle failure!!!!! */ - } - - /* - * Close the section - */ - NtClose(hSection); - - /* - * Get some information about the process - */ - NtQueryInformationProcess(hProcess, - ProcessBasicInformation, - &ProcessBasicInfo, - sizeof(ProcessBasicInfo), - &retlen); - DPRINT("ProcessBasicInfo.UniqueProcessId 0x%x\n", - ProcessBasicInfo.UniqueProcessId); - lpProcessInformation->dwProcessId = (DWORD)ProcessBasicInfo.UniqueProcessId; - - /* - * Tell the csrss server we are creating a new process - */ - Request = CREATE_PROCESS; - CsrRequest.Data.CreateProcessRequest.NewProcessId = - (HANDLE)ProcessBasicInfo.UniqueProcessId; - if (Sii.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI) - { - /* Do not create a console for GUI applications */ - dwCreationFlags &= ~CREATE_NEW_CONSOLE; - dwCreationFlags |= DETACHED_PROCESS; - } - else if (Sii.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI) - { - if (NULL == Ppb->ConsoleHandle) - { - dwCreationFlags |= CREATE_NEW_CONSOLE; - } - } - CsrRequest.Data.CreateProcessRequest.Flags = dwCreationFlags; - CsrRequest.Data.CreateProcessRequest.CtrlDispatcher = ConsoleControlDispatcher; - Status = CsrClientCallServer(&CsrRequest, - NULL, - MAKE_CSR_API(Request, CSR_NATIVE), - sizeof(CSR_API_MESSAGE)); - if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) - { - DbgPrint("Failed to tell csrss about new process. Expect trouble.\n"); - } - - Ppb->ConsoleHandle = CsrRequest.Data.CreateProcessRequest.Console; - - InputSet = FALSE; - OutputSet = FALSE; - ErrorSet = FALSE; - - /* Set the child console handles */ - - /* First check if handles were passed in startup info */ - if (lpStartupInfo && (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)) - { - if (lpStartupInfo->hStdInput) - { - Ppb->StandardInput = lpStartupInfo->hStdInput; - InputSet = TRUE; - InputDup = TRUE; - } - if (lpStartupInfo->hStdOutput) - { - Ppb->StandardOutput = lpStartupInfo->hStdOutput; - OutputSet = TRUE; - OutputDup = TRUE; - } - if (lpStartupInfo->hStdError) - { - Ppb->StandardError = lpStartupInfo->hStdError; - ErrorSet = TRUE; - ErrorDup = TRUE; - } - } - - /* Check if new console was created, use it for input and output if - not overridden */ - if (0 != (dwCreationFlags & CREATE_NEW_CONSOLE) - && NT_SUCCESS(Status) && NT_SUCCESS(CsrRequest.Status)) - { - if (! InputSet) - { - Ppb->StandardInput = CsrRequest.Data.CreateProcessRequest.InputHandle; - InputSet = TRUE; - InputDup = FALSE; - } - if (! OutputSet) - { - Ppb->StandardOutput = CsrRequest.Data.CreateProcessRequest.OutputHandle; - OutputSet = TRUE; - OutputDup = FALSE; - } - if (! ErrorSet) - { - Ppb->StandardError = CsrRequest.Data.CreateProcessRequest.OutputHandle; - ErrorSet = TRUE; - ErrorDup = FALSE; - } - } - - /* Use existing handles otherwise */ - if (! InputSet) - { - Ppb->StandardInput = NtCurrentPeb()->ProcessParameters->StandardInput; - InputDup = TRUE; - } - if (! OutputSet) - { - Ppb->StandardOutput = NtCurrentPeb()->ProcessParameters->StandardOutput; - OutputDup = TRUE; - } - if (! ErrorSet) - { - Ppb->StandardError = NtCurrentPeb()->ProcessParameters->StandardError; - ErrorDup = TRUE; - } - - /* Now duplicate handles if required */ - if (InputDup && Ppb->StandardInput != NULL) - { - if (IsConsoleHandle(Ppb->StandardInput)) - { - Ppb->StandardInput = CsrRequest.Data.CreateProcessRequest.InputHandle; - } - else - { - DPRINT("Duplicate input handle\n"); - Status = NtDuplicateObject (NtCurrentProcess(), - Ppb->StandardInput, - hProcess, - &Ppb->StandardInput, + NTSTATUS Status; + PROCESS_PRIORITY_CLASS PriorityClass; + BOOLEAN FoundQuotes = FALSE; + BOOLEAN QuotesNeeded = FALSE; + BOOLEAN CmdLineIsAppName = FALSE; + UNICODE_STRING ApplicationName; + OBJECT_ATTRIBUTES LocalObjectAttributes; + POBJECT_ATTRIBUTES ObjectAttributes; + HANDLE hSection, hProcess, hThread; + SECTION_IMAGE_INFORMATION SectionImageInfo; + LPWSTR CurrentDirectory = NULL; + LPWSTR CurrentDirectoryPart; + PROCESS_BASIC_INFORMATION ProcessBasicInfo; + STARTUPINFOW StartupInfo; + ULONG Dummy; + LPWSTR QuotedCmdLine = NULL; + LPWSTR ScanString; + LPWSTR NullBuffer; + LPWSTR NameBuffer = NULL; + WCHAR SaveChar; + ULONG RetVal; + UINT Error; + BOOLEAN SearchDone = FALSE; + HANDLE hConsole, hInput, hOutput; + CLIENT_ID ClientId; + PPEB OurPeb = NtCurrentPeb(); + PPEB RemotePeb; + + DPRINT("CreateProcessW: lpApplicationName: %S lpCommandLine: %S" + " lpEnvironment: %p lpCurrentDirectory: %S dwCreationFlags: %lx\n", + lpApplicationName, lpCommandLine, lpEnvironment, lpCurrentDirectory, + dwCreationFlags); + + /* Flags we don't handle yet */ + if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM) + { + DPRINT1("CREATE_SEPARATE_WOW_VDM not handled\n"); + } + if (dwCreationFlags & CREATE_SHARED_WOW_VDM) + { + DPRINT1("CREATE_SHARED_WOW_VDM not handled\n"); + } + if (dwCreationFlags & CREATE_FORCEDOS) + { + DPRINT1("CREATE_FORCEDOS not handled\n"); + } + + /* Fail on this flag, it's only valid with the WithLogonW function */ + if (dwCreationFlags & CREATE_WITH_USERPROFILE) + { + DPRINT1("Invalid flag used\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* This combination is illegal (see MSDN) */ + if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) == + (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) + { + DPRINT1("Invalid flag combo used\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* Another illegal combo */ + if ((dwCreationFlags & (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) == + (CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM)) + { + DPRINT1("Invalid flag combo used\n"); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + DPRINT("Foo\n"); + /* + * We're going to modify and mask out flags and stuff in lpStartupInfo, + * so we'll use our own local copy for that. + */ + StartupInfo = *lpStartupInfo; + DPRINT("Foo\n"); + /* FIXME: Use default Separate/Shared VDM Flag */ + + /* If we are inside a Job, use Separate VDM so it won't escape the Job */ + if (!(dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) + { + if (NtIsProcessInJob(NtCurrentProcess(), NULL)) + { + /* Remove the shared flag and add the separate flag. */ + dwCreationFlags = (dwCreationFlags &~ CREATE_SHARED_WOW_VDM) | + CREATE_SEPARATE_WOW_VDM; + } + } + DPRINT("Foo\n"); + /* + * According to some sites, ShellExecuteEx uses an undocumented flag to + * send private handle data (such as HMONITOR or HICON). See: + * www.catch22.net/tuts/undoc01.asp. This implies that we can't use the + * standard handles anymore since we'd be overwriting this private data + */ + if ((StartupInfo.dwFlags & STARTF_USESTDHANDLES) && + (StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_SHELLPRIVATE))) + { + StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES; + } + DPRINT("Foo\n"); + /* Start by zeroing out the fields */ + RtlZeroMemory(lpProcessInformation, sizeof(PROCESS_INFORMATION)); + DPRINT("Foo\n"); + /* Easy stuff first, convert the process priority class */ + PriorityClass.Foreground = FALSE; + PriorityClass.PriorityClass = BasepConvertPriorityClass(dwCreationFlags); + DPRINT("Foo\n"); + /* Convert the environment */ + if(lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) + { + lpEnvironment = BasepConvertUnicodeEnvironment(lpEnvironment); + if (!lpEnvironment) return FALSE; + } +DPRINT("Foo\n"); + /* Get the application name and do all the proper formating necessary */ +GetAppName: + /* See if we have an application name (oh please let us have one!) */ + if (!lpApplicationName) + { + /* The fun begins */ + NameBuffer = RtlAllocateHeap(GetProcessHeap(), 0, - TRUE, - DUPLICATE_SAME_ACCESS); - if(!NT_SUCCESS(Status)) - { - DPRINT("NtDuplicateObject failed, status %x\n", Status); - } - } - } + MAX_PATH * sizeof(WCHAR)); + + /* This is all we have to work with :( */ + lpApplicationName = lpCommandLine; + + /* Initialize our friends at the beginning */ + NullBuffer = (LPWSTR)lpApplicationName; + ScanString = (LPWSTR)lpApplicationName; + + /* We will start by looking for a quote */ + if (*ScanString == L'\"') + { + /* That was quick */ + SearchDone = TRUE; + + /* Advance past quote */ + ScanString++; + lpApplicationName = ScanString; + DPRINT("Foo\n"); + /* Find the closing quote */ + while (*ScanString) + { + if (*ScanString == L'\"') + { + /* Found it */ + NullBuffer = ScanString; + FoundQuotes = TRUE; + break; + } + DPRINT("Foo\n"); + /* Keep looking */ + ScanString++; + NullBuffer = ScanString; + } + } + else + { + /* No quotes, so we'll be looking for white space */ + WhiteScan: + /* Reset the pointer */ + lpApplicationName = lpCommandLine; + DPRINT("Foo\n"); + /* Find whitespace of Tab */ + while (*ScanString) + { + if (*ScanString == ' ' || *ScanString == '\t') + { + /* Found it */ + NullBuffer = ScanString; + break; + } + DPRINT("Foo\n"); + /* Keep looking */ + ScanString++; + NullBuffer = ScanString; + } + } + + /* Set the Null Buffer */ + SaveChar = *NullBuffer; + *NullBuffer = UNICODE_NULL; + + /* Do a search for the file */ + DPRINT("Ready for SearchPathW: %S\n", lpApplicationName); + RetVal = SearchPathW(NULL, + lpApplicationName, + L".exe", + MAX_PATH, + NameBuffer, + NULL) * sizeof(WCHAR); + + /* Did it find something? */ + if (RetVal) + { + /* Get file attributes */ + ULONG Attributes = GetFileAttributesW(NameBuffer); + if (Attributes & FILE_ATTRIBUTE_DIRECTORY) + { + /* Give it a length of 0 to fail, this was a directory. */ + RetVal = 0; + } + else + { + /* It's a file! */ + RetVal += sizeof(WCHAR); + } + } + + /* Now check if we have a file, and if the path size is OK */ + if (!RetVal || RetVal >= (MAX_PATH / sizeof(WCHAR))) + { + ULONG PathType; + HANDLE hFile; + + /* We failed, try to get the Path Type */ + DPRINT("SearchPathW failed. Retval: %ld\n", RetVal); + PathType = RtlDetermineDosPathNameType_U(lpApplicationName); + + /* If it's not relative, try to get the error */ + if (PathType != RELATIVE_PATH) + { + /* This should fail, and give us a detailed LastError */ + hFile = CreateFileW(lpApplicationName, + GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + /* Did it actually NOT fail? */ + if (hFile != INVALID_HANDLE_VALUE) + { + /* Fake the error */ + CloseHandle(hFile); + SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND); + } + } + else + { + /* Immediately set the error */ + SetLastErrorByStatus(STATUS_OBJECT_NAME_NOT_FOUND); + } + + /* Did we already fail once? */ + if (Error) + { + SetLastError(Error); + } + else + { + /* Not yet, cache it */ + Error = GetLastError(); + } + + /* Put back the command line */ + *NullBuffer = SaveChar; + lpApplicationName = NameBuffer; + + /* + * If the search isn't done and we still have cmdline + * then start over. Ex: c:\ha ha ha\haha.exe + */ + if (*ScanString && !SearchDone) + { + /* Move in the buffer */ + ScanString++; + NullBuffer = ScanString; + + /* We will have to add a quote, since there is a space*/ + QuotesNeeded = TRUE; + + /* And we will also fake the fact we found one */ + FoundQuotes = TRUE; + + /* Start over */ + goto WhiteScan; + } + + /* We totally failed */ + return FALSE; + } + + /* Put back the command line */ + *NullBuffer = SaveChar; + lpApplicationName = NameBuffer; + DPRINT("SearchPathW suceeded (%ld): %S\n", RetVal, NameBuffer); + } + else if (!lpCommandLine || *lpCommandLine == UNICODE_NULL) + { + /* We have an app name (good!) but no command line */ + CmdLineIsAppName = TRUE; + lpCommandLine = (LPWSTR)lpApplicationName; + } + + /* At this point the name has been toyed with enough to be openable */ + Status = BasepMapFile(lpApplicationName, &hSection, &ApplicationName); + + /* Check for failure */ + if (!NT_SUCCESS(Status)) + { + /* Could be a non-PE File */ + switch (Status) + { + /* Check if the Kernel tells us it's not even valid MZ */ + case STATUS_INVALID_IMAGE_NE_FORMAT: + case STATUS_INVALID_IMAGE_PROTECT: + case STATUS_INVALID_IMAGE_NOT_MZ: + + /* If it's a DOS app, use VDM */ + //if ((BasepCheckDosApp(&ApplicationName))) + { + DPRINT1("Launching VDM...\n"); + RtlFreeHeap(GetProcessHeap(), 0, NameBuffer); + RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer); + return CreateProcessW(L"ntvdm.exe", + (LPWSTR)lpApplicationName, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation); + } + + /* It's a batch file */ + LPWSTR BatchCommandLine; + ULONG CmdLineLength; + UNICODE_STRING CommandLineString; + LPWSTR TempBuffer; + PWCHAR Extension = + &ApplicationName.Buffer[ApplicationName.Length / sizeof(WCHAR) - 4]; + + /* Make sure the extensions are correct */ + if (_wcsnicmp(Extension, L".bat", 4) && _wcsnicmp(Extension, L".cmd", 4)) + { + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } + + /* Calculate the length of the command line */ + CmdLineLength = wcslen(CMD_STRING) + wcslen(lpCommandLine) + 1; + + /* If we found quotes, then add them into the length size */ + if (CmdLineIsAppName || FoundQuotes) CmdLineLength += 2; + CmdLineLength *= sizeof(WCHAR); + + /* Allocate space for the new command line */ + BatchCommandLine = RtlAllocateHeap(GetProcessHeap(), + 0, + CmdLineLength); + + /* Build it */ + wcscpy(BatchCommandLine, CMD_STRING); + if (CmdLineIsAppName || FoundQuotes) + { + wcscat(BatchCommandLine, L"\""); + } + wcscat(BatchCommandLine, lpCommandLine); + if (CmdLineIsAppName || FoundQuotes) + { + wcscat(BatchCommandLine, L"\""); + } + + /* Create it as a Unicode String */ + RtlInitUnicodeString(&CommandLineString, BatchCommandLine); + + /* Set the command line to this */ + lpCommandLine = CommandLineString.Buffer; + lpApplicationName = NULL; + + /* Free memory */ + RtlFreeHeap(GetProcessHeap(), 0, TempBuffer); + RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer); + ApplicationName.Buffer = NULL; + TempBuffer = NULL; + goto GetAppName; + break; + + case STATUS_INVALID_IMAGE_WIN_16: + + /* It's a Win16 Image, use VDM */ + DPRINT1("Launching VDM...\n"); + RtlFreeHeap(GetProcessHeap(), 0, NameBuffer); + RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer); + return CreateProcessW(L"ntvdm.exe", + (LPWSTR)lpApplicationName, + lpProcessAttributes, + lpThreadAttributes, + bInheritHandles, + dwCreationFlags, + lpEnvironment, + lpCurrentDirectory, + lpStartupInfo, + lpProcessInformation); - if (OutputDup && Ppb->StandardOutput != NULL) - { - if (IsConsoleHandle(Ppb->StandardOutput)) - { - Ppb->StandardOutput = CsrRequest.Data.CreateProcessRequest.OutputHandle; - } - else - { - DPRINT("Duplicate output handle\n"); - Status = NtDuplicateObject (NtCurrentProcess(), - Ppb->StandardOutput, - hProcess, - &Ppb->StandardOutput, - 0, - TRUE, - DUPLICATE_SAME_ACCESS); - if(!NT_SUCCESS(Status)) - { - DPRINT("NtDuplicateObject failed, status %x\n", Status); - } - } - } + default: + /* Invalid Image Type */ + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } + } + + /* Use our desktop if we didn't get any */ + if (!StartupInfo.lpDesktop) + { + StartupInfo.lpDesktop = OurPeb->ProcessParameters->DesktopInfo.Buffer; + } + + /* FIXME: Check if Application is allowed to run */ + + /* FIXME: Allow CREATE_SEPARATE only for WOW Apps, once we have that. */ + + /* Get some information about the executable */ + Status = ZwQuerySection(hSection, + SectionImageInformation, + &SectionImageInfo, + sizeof(SectionImageInfo), + NULL); + if(!NT_SUCCESS(Status)) + { + NtClose(hSection); + DPRINT1("Unable to get SectionImageInformation, status 0x%x\n", Status); + SetLastErrorByStatus(Status); + return FALSE; + } - if (ErrorDup && Ppb->StandardError != NULL) - { - if (IsConsoleHandle(Ppb->StandardError)) - { - Request = DUPLICATE_HANDLE; - CsrRequest.Data.DuplicateHandleRequest.ProcessId = (HANDLE)ProcessBasicInfo.UniqueProcessId; - CsrRequest.Data.DuplicateHandleRequest.Handle = CsrRequest.Data.CreateProcessRequest.OutputHandle; - Status = CsrClientCallServer(&CsrRequest, - NULL, - MAKE_CSR_API(Request, CSR_NATIVE), - sizeof(CSR_API_MESSAGE)); - if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) - { - Ppb->StandardError = INVALID_HANDLE_VALUE; - } - else - { - Ppb->StandardError = CsrRequest.Data.DuplicateHandleRequest.Handle; - } - } - else - { - DPRINT("Duplicate error handle\n"); - Status = NtDuplicateObject (NtCurrentProcess(), - Ppb->StandardError, - hProcess, - &Ppb->StandardError, - 0, - TRUE, - DUPLICATE_SAME_ACCESS); - if(!NT_SUCCESS(Status)) - { - DPRINT("NtDuplicateObject failed, status %x\n", Status); - } - } - } + /* Don't execute DLLs */ + if (SectionImageInfo.ImageCharacteristics & IMAGE_FILE_DLL) + { + NtClose(hSection); + DPRINT1("Can't execute a DLL\n"); + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } + + /* FIXME: Check for Debugger */ + + /* FIXME: Check if Machine Type and SubSys Version Match */ - /* - * Initialize some other fields in the PPB - */ - if (lpStartupInfo) - { - Ppb->WindowFlags = lpStartupInfo->dwFlags; - if (Ppb->WindowFlags & STARTF_USESHOWWINDOW) - { - Ppb->ShowWindowFlags = lpStartupInfo->wShowWindow; - } - else - { - Ppb->ShowWindowFlags = SW_SHOWDEFAULT; - } - Ppb->StartingX = lpStartupInfo->dwX; - Ppb->StartingY = lpStartupInfo->dwY; - Ppb->CountX = lpStartupInfo->dwXSize; - Ppb->CountY = lpStartupInfo->dwYSize; - Ppb->FillAttribute = lpStartupInfo->dwFillAttribute; - } - else - { - Ppb->Flags = 0; - } + /* We don't support POSIX or anything else for now */ + if (IMAGE_SUBSYSTEM_WINDOWS_GUI != SectionImageInfo.SubsystemType && + IMAGE_SUBSYSTEM_WINDOWS_CUI != SectionImageInfo.SubsystemType) + { + NtClose(hSection); + DPRINT1("Invalid subsystem %d\n", SectionImageInfo.SubsystemType); + SetLastError(ERROR_BAD_EXE_FORMAT); + return FALSE; + } - /* - * Create Process Environment Block - */ - DPRINT("Creating peb\n"); + /* Initialize the process object attributes */ + ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes, + lpProcessAttributes, + NULL); + + /* Create the Process */ + Status = NtCreateProcess(&hProcess, + PROCESS_ALL_ACCESS, + ObjectAttributes, + NtCurrentProcess(), + bInheritHandles, + hSection, + NULL, + NULL); + if(!NT_SUCCESS(Status)) + { + NtClose(hSection); + DPRINT1("Unable to create process, status 0x%x\n", Status); + SetLastErrorByStatus(Status); + return FALSE; + } + + /* Set new class */ + Status = NtSetInformationProcess(hProcess, + ProcessPriorityClass, + &PriorityClass, + sizeof(PROCESS_PRIORITY_CLASS)); + if(!NT_SUCCESS(Status)) + { + NtClose(hProcess); + NtClose(hSection); + DPRINT1("Unable to set new process priority, status 0x%x\n", Status); + SetLastErrorByStatus(Status); + return FALSE; + } + + /* Set Error Mode */ + if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) + { + ULONG ErrorMode = SEM_FAILCRITICALERRORS; + NtSetInformationProcess(hProcess, + ProcessDefaultHardErrorMode, + &ErrorMode, + sizeof(ULONG)); + } - KlInitPeb(hProcess, Ppb, &ImageBaseAddress, Sii.SubsystemType); + /* Convert the directory to a full path */ + if (lpCurrentDirectory) + { + /* Allocate a buffer */ + CurrentDirectory = RtlAllocateHeap(GetProcessHeap(), + 0, + MAX_PATH * sizeof(WCHAR) + 2); + + /* Get the length */ + if (GetFullPathNameW(lpCurrentDirectory, + MAX_PATH, + CurrentDirectory, + &CurrentDirectoryPart) > MAX_PATH) + { + DPRINT1("Directory name too long\n"); + SetLastError(ERROR_DIRECTORY); + return FALSE; + } + } + + /* Insert quotes if needed */ + if (QuotesNeeded || CmdLineIsAppName) + { + /* Allocate a buffer */ + QuotedCmdLine = RtlAllocateHeap(GetProcessHeap(), + 0, + (wcslen(lpCommandLine) + 2 + 1) * + sizeof(WCHAR)); + + /* Copy the first quote */ + wcscpy(QuotedCmdLine, L"\""); + + /* Save a null char */ + if (QuotesNeeded) + { + SaveChar = *NullBuffer; + *NullBuffer = UNICODE_NULL; + } + + /* Add the command line and the finishing quote */ + wcscat(QuotedCmdLine, lpCommandLine); + wcscat(QuotedCmdLine, L"\""); + + /* Add the null char */ + if (QuotesNeeded) + { + *NullBuffer = SaveChar; + wcscat(QuotedCmdLine, NullBuffer); + } + + DPRINT("Quoted CmdLine: %S\n", QuotedCmdLine); + } + + /* Get the Process Information */ + Status = NtQueryInformationProcess(hProcess, + ProcessBasicInformation, + &ProcessBasicInfo, + sizeof(ProcessBasicInfo), + NULL); - RtlDestroyProcessParameters (Ppb); + /* Notify CSRSS */ + Status = BasepNotifyCsrOfCreation(dwCreationFlags, + (HANDLE)ProcessBasicInfo.UniqueProcessId, + SectionImageInfo.SubsystemType, + &hConsole, + &hInput, + &hOutput); - /* - * Create the thread for the kernel - */ - DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n", - Sii.TransferAddress); - hThread = KlCreateFirstThread(hProcess, - lpThreadAttributes, - &Sii, - Sii.TransferAddress, - dwCreationFlags, - &lpProcessInformation->dwThreadId); - if (hThread == NULL) - { - return FALSE; - } + if (!NT_SUCCESS(Status)) + { + DPRINT1("CSR Notification Failed"); + SetLastErrorByStatus(Status); + return FALSE; + } + + /* Create Process Environment */ + RemotePeb = ProcessBasicInfo.PebBaseAddress; + Status = BasepInitializeEnvironment(hProcess, + RemotePeb, + (LPWSTR)lpApplicationName, + CurrentDirectory, + (QuotesNeeded || CmdLineIsAppName) ? + QuotedCmdLine : lpCommandLine, + lpEnvironment, + lpStartupInfo, + dwCreationFlags, + bInheritHandles, + hInput, + hOutput); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not initialize Process Environment\n"); + SetLastErrorByStatus(Status); + return FALSE; + } + + /* Close the section */ + NtClose(hSection); + hSection = NULL; - lpProcessInformation->hProcess = hProcess; - lpProcessInformation->hThread = hThread; + /* Duplicate the handles if needed */ + if (!bInheritHandles && !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) && + SectionImageInfo.SubsystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI) + { + PRTL_USER_PROCESS_PARAMETERS RemoteParameters; + + /* Get the remote parameters */ + Status = NtReadVirtualMemory(hProcess, + &RemotePeb->ProcessParameters, + &RemoteParameters, + sizeof(PVOID), + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to read memory\n"); + return FALSE; + } + + /* Duplicate and write the handles */ + BasepDuplicateAndWriteHandle(hProcess, + OurPeb->ProcessParameters->StandardInput, + &RemoteParameters->StandardInput); + BasepDuplicateAndWriteHandle(hProcess, + OurPeb->ProcessParameters->StandardOutput, + &RemoteParameters->StandardOutput); + BasepDuplicateAndWriteHandle(hProcess, + OurPeb->ProcessParameters->StandardError, + &RemoteParameters->StandardError); + } + + /* Create the first thread */ + DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n", + SectionImageInfo.TransferAddress); + hThread = BasepCreateFirstThread(hProcess, + lpThreadAttributes, + &SectionImageInfo, + &ClientId); - return TRUE; + if (hThread == NULL) + { + DPRINT1("Could not create Initial Thread\n"); + return FALSE; + } + + if (!(dwCreationFlags & CREATE_SUSPENDED)) + { + NtResumeThread(hThread, &Dummy); + } + + /* Cleanup Environment */ + if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) + { + RtlDestroyEnvironment(lpEnvironment); + } + + /* Return Data */ + lpProcessInformation->dwProcessId = (DWORD)ClientId.UniqueProcess; + lpProcessInformation->dwThreadId = (DWORD)ClientId.UniqueThread; + lpProcessInformation->hProcess = hProcess; + lpProcessInformation->hThread = hThread; + DPRINT("hThread[%lx]: %lx inside hProcess[%lx]: %lx\n", hThread, + ClientId.UniqueThread, ClientId.UniqueProcess, hProcess); + hProcess = hThread = NULL; + + /* De-allocate heap strings */ + if (NameBuffer) RtlFreeHeap(GetProcessHeap(), 0, NameBuffer); + if (ApplicationName.Buffer) + RtlFreeHeap(GetProcessHeap(), 0, ApplicationName.Buffer); + if (CurrentDirectory) RtlFreeHeap(GetProcessHeap(), 0, CurrentDirectory); + if (QuotedCmdLine) RtlFreeHeap(GetProcessHeap(), 0, QuotedCmdLine); + + /* Kill any handles still alive */ + if (hSection) NtClose(hSection); + if (hThread) + { + /* We don't know any more details then this */ + NtTerminateProcess(hProcess, STATUS_UNSUCCESSFUL); + NtClose(hThread); + } + if (hProcess) NtClose(hProcess); + + /* Return Success */ + return TRUE; } /* EOF */ diff --git a/reactos/lib/kernel32/thread/i386/thread.S b/reactos/lib/kernel32/thread/i386/thread.S index e789f4d9b5f..47384481506 100644 --- a/reactos/lib/kernel32/thread/i386/thread.S +++ b/reactos/lib/kernel32/thread/i386/thread.S @@ -1,32 +1,32 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/kernel32/thread/i386/thread.S - * PURPOSE: Thread Start Thunks - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - */ - -.globl _BaseThreadStartupThunk@0 -.globl _BaseProcessStartThunk@0 -.intel_syntax noprefix - -_BaseThreadStartupThunk@0: - - /* Start out fresh */ - xor ebp, ebp - - push ebx /* lpParameter */ - push eax /* lpStartAddress */ - push 0 /* Return EIP */ - //jmp _BaseThreadStartup@8 - -_BaseProcessStartThunk@0: - - /* Start out fresh */ - xor ebp, ebp - - push eax /* lpStartAddress */ - push 0 /* Return EIP */ - //jmp _BaseProcessStartup@4 - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/kernel32/thread/i386/thread.S + * PURPOSE: Thread Start Thunks + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + */ + +.globl _BaseThreadStartupThunk@0 +.globl _BaseProcessStartThunk@0 +.intel_syntax noprefix + +_BaseThreadStartupThunk@0: + + /* Start out fresh */ + xor ebp, ebp + + push ebx /* lpParameter */ + push eax /* lpStartAddress */ + push 0 /* Return EIP */ + jmp _BaseThreadStartup@8 + +_BaseProcessStartThunk@0: + + /* Start out fresh */ + xor ebp, ebp + + push eax /* lpStartAddress */ + push 0 /* Return EIP */ + jmp _BaseProcessStartup@4 + +/* EOF */ diff --git a/reactos/lib/kernel32/thread/thread.c b/reactos/lib/kernel32/thread/thread.c index cf61e62f8b5..3b38ff121fd 100644 --- a/reactos/lib/kernel32/thread/thread.c +++ b/reactos/lib/kernel32/thread/thread.c @@ -1,13 +1,10 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: lib/kernel32/thread/thread.c * PURPOSE: Thread functions - * PROGRAMMER: Ariadne ( ariadne@xs4all.nl) - * Tls functions are modified from WINE - * UPDATE HISTORY: - * Created 01/11/98 + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * Ariadne ( ariadne@xs4all.nl) * */ @@ -15,13 +12,9 @@ #include -/* FIXME */ -#include - #define NDEBUG #include "../include/debug.h" - /* FUNCTIONS *****************************************************************/ _SEH_FILTER(BaseThreadExceptionFilter) { @@ -68,199 +61,196 @@ BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress, ExitThread(uExitCode); } +/* + * @implemented + */ +HANDLE +STDCALL +CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId) +{ + /* Act as if we're going to create a remote thread in ourselves */ + return CreateRemoteThread(NtCurrentProcess(), + lpThreadAttributes, + dwStackSize, + lpStartAddress, + lpParameter, + dwCreationFlags, + lpThreadId); +} /* * @implemented */ -HANDLE STDCALL -CreateThread -( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - DWORD dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId -) +HANDLE +STDCALL +CreateRemoteThread(HANDLE hProcess, + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, + DWORD dwCreationFlags, + LPDWORD lpThreadId) { - return CreateRemoteThread - ( - NtCurrentProcess(), - lpThreadAttributes, - dwStackSize, - lpStartAddress, - lpParameter, - dwCreationFlags, - lpThreadId - ); -} + NTSTATUS Status; + INITIAL_TEB InitialTeb; + CONTEXT Context; + CLIENT_ID ClientId; + OBJECT_ATTRIBUTES LocalObjectAttributes; + POBJECT_ATTRIBUTES ObjectAttributes; + HANDLE hThread; + ULONG Dummy; + + DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress" + ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess, + dwStackSize, lpStartAddress, lpParameter, dwCreationFlags); + + /* Clear the Context */ + RtlZeroMemory(&Context, sizeof(CONTEXT)); + + /* Write PID */ + ClientId.UniqueProcess = hProcess; + + /* Create the Stack */ + Status = BasepCreateStack(hProcess, + dwStackSize, + dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ? + dwStackSize : 0, + &InitialTeb); + if(!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + return NULL; + } + + /* Create Initial Context */ + BasepInitializeContext(&Context, + lpParameter, + lpStartAddress, + InitialTeb.StackBase, + 1); + + /* initialize the attributes for the thread object */ + ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes, + lpThreadAttributes, + NULL); + + /* Create the Kernel Thread Object */ + Status = NtCreateThread(&hThread, + THREAD_ALL_ACCESS, + ObjectAttributes, + hProcess, + &ClientId, + &Context, + &InitialTeb, + TRUE); + if(!NT_SUCCESS(Status)) + { + BasepFreeStack(hProcess, &InitialTeb); + SetLastErrorByStatus(Status); + return NULL; + } + + #ifdef SXS_SUPPORT_ENABLED + /* Are we in the same process? */ + if (Process = NtCurrentProcess()) + { + PTEB Teb; + PVOID ActivationContextStack; + PTHREAD_BASIC_INFORMATION ThreadBasicInfo; + PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo; + ULONG_PTR Cookie; + + /* Get the TEB */ + Status = NtQueryInformationThread(hThread, + ThreadBasicIformation, + &ThreadBasicInfo, + sizeof(ThreadBasicInfo), + NULL); + + /* Allocate the Activation Context Stack */ + Status = RtlAllocateActivationContextStack(&ActivationContextStack); + Teb = ThreadBasicInfo.TebBaseAddress; + + /* Save it */ + Teb->ActivationContextStackPointer = ActivationContextStack; + + /* Query the Context */ + Status = RtlQueryInformationActivationContext(1, + 0, + NULL, + ActivationContextBasicInformation, + &ActivationCtxInfo, + sizeof(ActivationCtxInfo), + NULL); + + /* Does it need to be activated? */ + if (!ActivationCtxInfo.hActCtx) + { + /* Activate it */ + Status = RtlActivateActivationContextEx(1, + Teb, + ActivationCtxInfo.hActCtx, + &Cookie); + } + } + #endif + + /* FIXME: Notify CSR */ + /* Success */ + if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread; + + /* Resume it if asked */ + if (!(dwCreationFlags & CREATE_SUSPENDED)) + { + NtResumeThread(hThread, &Dummy); + } + + /* Return handle to thread */ + return hThread; +} /* * @implemented */ -HANDLE STDCALL -CreateRemoteThread -( - HANDLE hProcess, - LPSECURITY_ATTRIBUTES lpThreadAttributes, - DWORD dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId -) +VOID +STDCALL +ExitThread(DWORD uExitCode) { - HANDLE hThread; - CLIENT_ID cidClientId; - NTSTATUS nErrCode; - ULONG_PTR nStackReserve; - ULONG_PTR nStackCommit; - OBJECT_ATTRIBUTES oaThreadAttribs; - PIMAGE_NT_HEADERS pinhHeader = - RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress); + NTSTATUS Status; + BOOLEAN LastThread; + + /* + * Terminate process if this is the last thread + * of the current process + */ + Status = NtQueryInformationThread(NtCurrentThread(), + ThreadAmILastThread, + &LastThread, + sizeof(BOOLEAN), + NULL); + if (NT_SUCCESS(Status) && LastThread) + { + /* Exit the Process */ + ExitProcess(uExitCode); + } - DPRINT - ( - "hProcess %08X\n" - "lpThreadAttributes %08X\n" - "dwStackSize %08X\n" - "lpStartAddress %08X\n" - "lpParameter %08X\n" - "dwCreationFlags %08X\n" - "lpThreadId %08X\n", - hProcess, - lpThreadAttributes, - dwStackSize, - lpStartAddress, - lpParameter, - dwCreationFlags, - lpThreadId - ); - - /* FIXME: do more checks - e.g. the image may not have an optional header */ - if(pinhHeader == NULL) - { - nStackReserve = 0x100000; - nStackCommit = PAGE_SIZE; - } - else - { - nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve; - nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit; - } - - /* FIXME: this should be defined in winbase.h */ -#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION -#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 -#endif - - /* use defaults */ - if(dwStackSize == 0); - /* dwStackSize specifies the size to reserve */ - else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION) - nStackReserve = dwStackSize; - /* dwStackSize specifies the size to commit */ - else - nStackCommit = dwStackSize; - - /* fix the stack reserve size */ - if(nStackCommit > nStackReserve) - nStackReserve = ROUNDUP(nStackCommit, 0x100000); - - /* initialize the attributes for the thread object */ - InitializeObjectAttributes - ( - &oaThreadAttribs, - NULL, - 0, - NULL, - NULL - ); - - if(lpThreadAttributes) - { - /* make the handle inheritable */ - if(lpThreadAttributes->bInheritHandle) - oaThreadAttribs.Attributes |= OBJ_INHERIT; - - /* user-defined security descriptor */ - oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor; - } - - DPRINT - ( - "RtlRosCreateUserThreadVa\n" - "(\n" - " ProcessHandle %p,\n" - " ObjectAttributes %p,\n" - " CreateSuspended %d,\n" - " StackZeroBits %d,\n" - " StackReserve %lu,\n" - " StackCommit %lu,\n" - " StartAddress %p,\n" - " ThreadHandle %p,\n" - " ClientId %p,\n" - " ParameterCount %u,\n" - " Parameters[0] %p,\n" - " Parameters[1] %p\n" - ")\n", - hProcess, - &oaThreadAttribs, - dwCreationFlags & CREATE_SUSPENDED, - 0, - nStackReserve, - nStackCommit, - BaseThreadStartup, - &hThread, - &cidClientId, - 2, - lpStartAddress, - lpParameter - ); - - /* create the thread */ - nErrCode = RtlRosCreateUserThreadVa - ( - hProcess, - &oaThreadAttribs, - dwCreationFlags & CREATE_SUSPENDED, - 0, - &nStackReserve, - &nStackCommit, - (PTHREAD_START_ROUTINE)BaseThreadStartup, - &hThread, - &cidClientId, - 2, - lpStartAddress, - lpParameter - ); - - /* failure */ - if(!NT_SUCCESS(nErrCode)) - { - SetLastErrorByStatus(nErrCode); - return NULL; - } - - DPRINT - ( - "StackReserve %p\n" - "StackCommit %p\n" - "ThreadHandle %p\n" - "ClientId.UniqueThread %p\n", - nStackReserve, - nStackCommit, - hThread, - cidClientId.UniqueThread - ); - - /* success */ - if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread; - return hThread; + /* Notify DLLs and TLS Callbacks of termination */ + LdrShutdownThread(); + + /* Tell the Kernel to free the Stack */ + NtCurrentTeb()->FreeStackOnTermination = TRUE; + NtTerminateThread(NULL, uExitCode); + + /* We will never reach this place. This silences the compiler */ + ExitThread(uExitCode); } - /* * @implemented */ @@ -330,37 +320,6 @@ GetCurrentThreadId(VOID) return((DWORD)(NtCurrentTeb()->Cid).UniqueThread); } -/* - * @implemented - */ -VOID STDCALL -ExitThread(DWORD uExitCode) -{ - NTSTATUS Status; - BOOLEAN LastThread; - - /* - * Terminate process if this is the last thread - * of the current process - */ - Status = NtQueryInformationThread(NtCurrentThread(), - ThreadAmILastThread, - &LastThread, - sizeof(BOOLEAN), - NULL); - if (NT_SUCCESS(Status) && LastThread == TRUE) - { - ExitProcess(uExitCode); - } - - /* FIXME: notify csrss of thread termination */ - - LdrShutdownThread(); - - RtlRosExitUserThread(uExitCode); -} - - /* * @implemented */ diff --git a/reactos/ntoskrnl/mm/process.c b/reactos/ntoskrnl/mm/process.c index 48b6156814a..b74f4f1f183 100644 --- a/reactos/ntoskrnl/mm/process.c +++ b/reactos/ntoskrnl/mm/process.c @@ -1,483 +1,472 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/mm/process.c - * PURPOSE: Memory functions related to Processes - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -extern ULONG NtMajorVersion; -extern ULONG NtMinorVersion; -extern ULONG NtOSCSDVersion; - -/* FUNCTIONS *****************************************************************/ - -PVOID -STDCALL -MiCreatePebOrTeb(PEPROCESS Process, - PVOID BaseAddress) -{ - NTSTATUS Status; - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - PMEMORY_AREA MemoryArea; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - PVOID AllocatedBase = BaseAddress; - BoundaryAddressMultiple.QuadPart = 0; - - /* Acquire the Lock */ - MmLockAddressSpace(ProcessAddressSpace); - - /* - * Create a Peb or Teb. - * Loop until it works, decreasing by PAGE_SIZE each time. The logic here - * is that a PEB allocation should never fail since the address is free, - * while TEB allocation can fail, and we should simply try the address - * below. Is there a nicer way of doing this automagically? (ie: findning) - * a gap region? -- Alex - */ - do { - DPRINT("Trying to allocate: %x\n", AllocatedBase); - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_PEB_OR_TEB, - &AllocatedBase, - PAGE_SIZE, - PAGE_READWRITE, - &MemoryArea, - TRUE, - FALSE, - BoundaryAddressMultiple); - AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE); - } while (Status != STATUS_SUCCESS); - - /* Initialize the Region */ - MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, - PAGE_SIZE, - MEM_COMMIT, - PAGE_READWRITE); - - /* Reserve the pages */ - MmReserveSwapPages(PAGE_SIZE); - - /* Unlock Address Space */ - DPRINT("Returning\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - return RVA(AllocatedBase, PAGE_SIZE); -} - -VOID -MiFreeStackPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); -} - -VOID -STDCALL -MmDeleteKernelStack(PVOID Stack, - BOOLEAN GuiStack) -{ - /* Lock the Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Delete the Stack */ - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - Stack, - MiFreeStackPage, - NULL); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - -VOID -MiFreePebPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - PEPROCESS Process = (PEPROCESS)Context; - - if (Page != 0) - { - SWAPENTRY SavedSwapEntry; - SavedSwapEntry = MmGetSavedSwapEntryPage(Page); - if (SavedSwapEntry != 0) - { - MmFreeSwapPage(SavedSwapEntry); - MmSetSavedSwapEntryPage(Page, 0); - } - MmDeleteRmap(Page, Process, Address); - MmReleasePageMemoryConsumer(MC_USER, Page); - } - else if (SwapEntry != 0) - { - MmFreeSwapPage(SwapEntry); - } -} - -VOID -STDCALL -MmDeleteTeb(PEPROCESS Process, - PTEB Teb) -{ - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - - /* Lock the Address Space */ - MmLockAddressSpace(ProcessAddressSpace); - - /* Delete the Stack */ - MmFreeMemoryAreaByPtr(ProcessAddressSpace, - Teb, - MiFreePebPage, - Process); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(ProcessAddressSpace); -} - -PVOID -STDCALL -MmCreateKernelStack(BOOLEAN GuiStack) -{ - PMEMORY_AREA StackArea; - ULONG i; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; - PVOID KernelStack = NULL; - NTSTATUS Status; - - /* Initialize the Boundary Address */ - BoundaryAddressMultiple.QuadPart = 0; - - /* Lock the Kernel Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Create a MAREA for the Kernel Stack */ - Status = MmCreateMemoryArea(NULL, - MmGetKernelAddressSpace(), - MEMORY_AREA_KERNEL_STACK, - &KernelStack, - MM_STACK_SIZE, - 0, - &StackArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create thread stack\n"); - KEBUGCHECK(0); - } - - /* Mark the Stack in use */ - for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) - { - Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); - } - - /* Create a Virtual Mapping for it */ - Status = MmCreateVirtualMapping(NULL, - KernelStack, - PAGE_READWRITE, - Page, - MM_STACK_SIZE / PAGE_SIZE); - - /* Check for success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); - KEBUGCHECK(0); - } - - return KernelStack; -} - -NTSTATUS -STDCALL -MmCreatePeb(PEPROCESS Process) -{ - PPEB Peb = NULL; - LARGE_INTEGER SectionOffset; - ULONG ViewSize = 0; - PVOID TableBase = NULL; - NTSTATUS Status; - SectionOffset.QuadPart = (ULONGLONG)0; - - DPRINT("MmCreatePeb\n"); - - /* Map NLS Tables */ - DPRINT("Mapping NLS\n"); - Status = MmMapViewOfSection(NlsSectionObject, - Process, - &TableBase, - 0, - 0, - &SectionOffset, - &ViewSize, - ViewShare, - MEM_TOP_DOWN, - PAGE_READONLY); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status); - return(Status); - } - DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize); - - /* Attach to Process */ - KeAttachProcess(&Process->Pcb); - - /* Allocate the PEB */ - Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE); - - /* Initialize the PEB */ - DPRINT("Allocated: %x\n", Peb); - RtlZeroMemory(Peb, sizeof(PEB)); - - /* Set up data */ - DPRINT("Setting up PEB\n"); - Peb->ImageBaseAddress = Process->SectionBaseAddress; - Peb->OSMajorVersion = NtMajorVersion; - Peb->OSMinorVersion = NtMinorVersion; - Peb->OSBuildNumber = 2195; - Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT; - Peb->OSCSDVersion = NtOSCSDVersion; - Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset; - Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset; - Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset; - Peb->NumberOfProcessors = KeNumberProcessors; - Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); - - Process->Peb = Peb; - KeDetachProcess(); - - DPRINT("MmCreatePeb: Peb created at %p\n", Peb); - return STATUS_SUCCESS; -} - -PTEB -STDCALL -MmCreateTeb(PEPROCESS Process, - PCLIENT_ID ClientId, - PINITIAL_TEB InitialTeb) -{ - PTEB Teb; - BOOLEAN Attached = FALSE; - - /* Attach to the process */ - DPRINT("MmCreateTeb\n"); - if (Process != PsGetCurrentProcess()) - { - /* Attach to Target */ - KeAttachProcess(&Process->Pcb); - Attached = TRUE; - } - - /* Allocate the TEB */ - Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE); - - /* Initialize the PEB */ - RtlZeroMemory(Teb, sizeof(TEB)); - - /* Set TIB Data */ - Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; - Teb->Tib.Version = 1; - Teb->Tib.Self = (PNT_TIB)Teb; - - /* Set TEB Data */ - Teb->Cid = *ClientId; - Teb->RealClientId = *ClientId; - Teb->ProcessEnvironmentBlock = Process->Peb; - Teb->CurrentLocale = PsDefaultThreadLocaleId; - - /* Store stack information from InitialTeb */ - if(InitialTeb != NULL) - { - /* fixed-size stack */ - if(InitialTeb->PreviousStackBase && InitialTeb->PreviousStackLimit) - { - Teb->Tib.StackBase = InitialTeb->PreviousStackBase; - Teb->Tib.StackLimit = InitialTeb->PreviousStackLimit; - Teb->DeallocationStack = InitialTeb->PreviousStackLimit; - } - /* expandable stack */ - else - { - Teb->Tib.StackBase = InitialTeb->StackBase; - Teb->Tib.StackLimit = InitialTeb->StackLimit; - Teb->DeallocationStack = InitialTeb->AllocatedStackBase; - } - } - - /* Return TEB Address */ - DPRINT("Allocated: %x\n", Teb); - if (Attached) KeDetachProcess(); - return Teb; -} - -NTSTATUS -STDCALL -MmCreateProcessAddressSpace(IN PEPROCESS Process, - IN PSECTION_OBJECT Section OPTIONAL) -{ - NTSTATUS Status; - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - PVOID BaseAddress; - PMEMORY_AREA MemoryArea; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - ULONG ViewSize = 0; - PVOID ImageBase = 0; - BoundaryAddressMultiple.QuadPart = 0; - - /* Initialize the Addresss Space */ - MmInitializeAddressSpace(Process, ProcessAddressSpace); - - /* Acquire the Lock */ - MmLockAddressSpace(ProcessAddressSpace); - - /* Protect the highest 64KB of the process address space */ - BaseAddress = (PVOID)MmUserProbeAddress; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_NO_ACCESS, - &BaseAddress, - 0x10000, - PAGE_NOACCESS, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to protect last 64KB\n"); - goto exit; - } - - /* Protect the 60KB above the shared user page */ - BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_NO_ACCESS, - &BaseAddress, - 0x10000 - PAGE_SIZE, - PAGE_NOACCESS, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to protect the memory above the shared user page\n"); - goto exit; - } - - /* Create the shared data page */ - BaseAddress = (PVOID)USER_SHARED_DATA; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_SHARED_DATA, - &BaseAddress, - PAGE_SIZE, - PAGE_READONLY, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create Shared User Data\n"); - goto exit; - } - - /* Check if there's a Section Object */ - if (Section) - { - UNICODE_STRING FileName; - PWCHAR szSrc; - PCHAR szDest; - USHORT lnFName = 0; - - /* Unlock the Address Space */ - DPRINT("Unlocking\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - - DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n", - Section, Process, &ImageBase); - Status = MmMapViewOfSection(Section, - Process, - (PVOID*)&ImageBase, - 0, - 0, - NULL, - &ViewSize, - 0, - MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to map process Image\n"); - ObDereferenceObject(Section); - goto exit; - } - ObDereferenceObject(Section); - - /* Save the pointer */ - Process->SectionBaseAddress = ImageBase; - - /* Determine the image file name and save it to EPROCESS */ - DPRINT("Getting Image name\n"); - FileName = Section->FileObject->FileName; - szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1); - - while(szSrc >= FileName.Buffer) - { - if(*szSrc == L'\\') - { - szSrc++; - break; - } - else - { - szSrc--; - lnFName++; - } - } - - /* Copy the to the process and truncate it to 15 characters if necessary */ - DPRINT("Copying and truncating\n"); - szDest = Process->ImageFileName; - lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1); - while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++); - - /* Return status to caller */ - return Status; - } - -exit: - /* Unlock the Address Space */ - DPRINT("Unlocking\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - - /* Return status to caller */ - return Status; -} +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/process.c + * PURPOSE: Memory functions related to Processes + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +extern ULONG NtMajorVersion; +extern ULONG NtMinorVersion; +extern ULONG NtOSCSDVersion; + +/* FUNCTIONS *****************************************************************/ + +PVOID +STDCALL +MiCreatePebOrTeb(PEPROCESS Process, + PVOID BaseAddress) +{ + NTSTATUS Status; + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + PMEMORY_AREA MemoryArea; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + PVOID AllocatedBase = BaseAddress; + BoundaryAddressMultiple.QuadPart = 0; + + /* Acquire the Lock */ + MmLockAddressSpace(ProcessAddressSpace); + + /* + * Create a Peb or Teb. + * Loop until it works, decreasing by PAGE_SIZE each time. The logic here + * is that a PEB allocation should never fail since the address is free, + * while TEB allocation can fail, and we should simply try the address + * below. Is there a nicer way of doing this automagically? (ie: findning) + * a gap region? -- Alex + */ + do { + DPRINT("Trying to allocate: %x\n", AllocatedBase); + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_PEB_OR_TEB, + &AllocatedBase, + PAGE_SIZE, + PAGE_READWRITE, + &MemoryArea, + TRUE, + FALSE, + BoundaryAddressMultiple); + AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE); + } while (Status != STATUS_SUCCESS); + + /* Initialize the Region */ + MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, + PAGE_SIZE, + MEM_COMMIT, + PAGE_READWRITE); + + /* Reserve the pages */ + MmReserveSwapPages(PAGE_SIZE); + + /* Unlock Address Space */ + DPRINT("Returning\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + return RVA(AllocatedBase, PAGE_SIZE); +} + +VOID +MiFreeStackPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PFN_TYPE Page, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + ASSERT(SwapEntry == 0); + if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); +} + +VOID +STDCALL +MmDeleteKernelStack(PVOID Stack, + BOOLEAN GuiStack) +{ + /* Lock the Address Space */ + MmLockAddressSpace(MmGetKernelAddressSpace()); + + /* Delete the Stack */ + MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), + Stack, + MiFreeStackPage, + NULL); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(MmGetKernelAddressSpace()); +} + +VOID +MiFreePebPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PFN_TYPE Page, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + PEPROCESS Process = (PEPROCESS)Context; + + if (Page != 0) + { + SWAPENTRY SavedSwapEntry; + SavedSwapEntry = MmGetSavedSwapEntryPage(Page); + if (SavedSwapEntry != 0) + { + MmFreeSwapPage(SavedSwapEntry); + MmSetSavedSwapEntryPage(Page, 0); + } + MmDeleteRmap(Page, Process, Address); + MmReleasePageMemoryConsumer(MC_USER, Page); + } + else if (SwapEntry != 0) + { + MmFreeSwapPage(SwapEntry); + } +} + +VOID +STDCALL +MmDeleteTeb(PEPROCESS Process, + PTEB Teb) +{ + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + + /* Lock the Address Space */ + MmLockAddressSpace(ProcessAddressSpace); + + /* Delete the Stack */ + MmFreeMemoryAreaByPtr(ProcessAddressSpace, + Teb, + MiFreePebPage, + Process); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(ProcessAddressSpace); +} + +PVOID +STDCALL +MmCreateKernelStack(BOOLEAN GuiStack) +{ + PMEMORY_AREA StackArea; + ULONG i; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; + PVOID KernelStack = NULL; + NTSTATUS Status; + + /* Initialize the Boundary Address */ + BoundaryAddressMultiple.QuadPart = 0; + + /* Lock the Kernel Address Space */ + MmLockAddressSpace(MmGetKernelAddressSpace()); + + /* Create a MAREA for the Kernel Stack */ + Status = MmCreateMemoryArea(NULL, + MmGetKernelAddressSpace(), + MEMORY_AREA_KERNEL_STACK, + &KernelStack, + MM_STACK_SIZE, + 0, + &StackArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(MmGetKernelAddressSpace()); + + /* Check for Success */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create thread stack\n"); + KEBUGCHECK(0); + } + + /* Mark the Stack in use */ + for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) + { + Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); + } + + /* Create a Virtual Mapping for it */ + Status = MmCreateVirtualMapping(NULL, + KernelStack, + PAGE_READWRITE, + Page, + MM_STACK_SIZE / PAGE_SIZE); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); + KEBUGCHECK(0); + } + + return KernelStack; +} + +NTSTATUS +STDCALL +MmCreatePeb(PEPROCESS Process) +{ + PPEB Peb = NULL; + LARGE_INTEGER SectionOffset; + ULONG ViewSize = 0; + PVOID TableBase = NULL; + NTSTATUS Status; + SectionOffset.QuadPart = (ULONGLONG)0; + + DPRINT("MmCreatePeb\n"); + + /* Map NLS Tables */ + DPRINT("Mapping NLS\n"); + Status = MmMapViewOfSection(NlsSectionObject, + Process, + &TableBase, + 0, + 0, + &SectionOffset, + &ViewSize, + ViewShare, + MEM_TOP_DOWN, + PAGE_READONLY); + if (!NT_SUCCESS(Status)) + { + DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status); + return(Status); + } + DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize); + + /* Attach to Process */ + KeAttachProcess(&Process->Pcb); + + /* Allocate the PEB */ + Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE); + + /* Initialize the PEB */ + DPRINT("Allocated: %x\n", Peb); + RtlZeroMemory(Peb, sizeof(PEB)); + + /* Set up data */ + DPRINT("Setting up PEB\n"); + Peb->ImageBaseAddress = Process->SectionBaseAddress; + Peb->OSMajorVersion = NtMajorVersion; + Peb->OSMinorVersion = NtMinorVersion; + Peb->OSBuildNumber = 2195; + Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT; + Peb->OSCSDVersion = NtOSCSDVersion; + Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset; + Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset; + Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset; + Peb->NumberOfProcessors = KeNumberProcessors; + Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); + + Process->Peb = Peb; + KeDetachProcess(); + + DPRINT("MmCreatePeb: Peb created at %p\n", Peb); + return STATUS_SUCCESS; +} + +PTEB +STDCALL +MmCreateTeb(PEPROCESS Process, + PCLIENT_ID ClientId, + PINITIAL_TEB InitialTeb) +{ + PTEB Teb; + BOOLEAN Attached = FALSE; + + /* Attach to the process */ + DPRINT("MmCreateTeb\n"); + if (Process != PsGetCurrentProcess()) + { + /* Attach to Target */ + KeAttachProcess(&Process->Pcb); + Attached = TRUE; + } + + /* Allocate the TEB */ + Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE); + + /* Initialize the PEB */ + RtlZeroMemory(Teb, sizeof(TEB)); + + /* Set TIB Data */ + Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; + Teb->Tib.Version = 1; + Teb->Tib.Self = (PNT_TIB)Teb; + + /* Set TEB Data */ + Teb->Cid = *ClientId; + Teb->RealClientId = *ClientId; + Teb->ProcessEnvironmentBlock = Process->Peb; + Teb->CurrentLocale = PsDefaultThreadLocaleId; + + /* Store stack information from InitialTeb */ + if(InitialTeb != NULL) + { + Teb->Tib.StackBase = InitialTeb->StackBase; + Teb->Tib.StackLimit = InitialTeb->StackLimit; + Teb->DeallocationStack = InitialTeb->AllocatedStackBase; + } + + /* Return TEB Address */ + DPRINT("Allocated: %x\n", Teb); + if (Attached) KeDetachProcess(); + return Teb; +} + +NTSTATUS +STDCALL +MmCreateProcessAddressSpace(IN PEPROCESS Process, + IN PSECTION_OBJECT Section OPTIONAL) +{ + NTSTATUS Status; + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + PVOID BaseAddress; + PMEMORY_AREA MemoryArea; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + ULONG ViewSize = 0; + PVOID ImageBase = 0; + BoundaryAddressMultiple.QuadPart = 0; + + /* Initialize the Addresss Space */ + MmInitializeAddressSpace(Process, ProcessAddressSpace); + + /* Acquire the Lock */ + MmLockAddressSpace(ProcessAddressSpace); + + /* Protect the highest 64KB of the process address space */ + BaseAddress = (PVOID)MmUserProbeAddress; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_NO_ACCESS, + &BaseAddress, + 0x10000, + PAGE_NOACCESS, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to protect last 64KB\n"); + goto exit; + } + + /* Protect the 60KB above the shared user page */ + BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_NO_ACCESS, + &BaseAddress, + 0x10000 - PAGE_SIZE, + PAGE_NOACCESS, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to protect the memory above the shared user page\n"); + goto exit; + } + + /* Create the shared data page */ + BaseAddress = (PVOID)USER_SHARED_DATA; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_SHARED_DATA, + &BaseAddress, + PAGE_SIZE, + PAGE_READONLY, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create Shared User Data\n"); + goto exit; + } + + /* Check if there's a Section Object */ + if (Section) + { + UNICODE_STRING FileName; + PWCHAR szSrc; + PCHAR szDest; + USHORT lnFName = 0; + + /* Unlock the Address Space */ + DPRINT("Unlocking\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + + DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n", + Section, Process, &ImageBase); + Status = MmMapViewOfSection(Section, + Process, + (PVOID*)&ImageBase, + 0, + 0, + NULL, + &ViewSize, + 0, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to map process Image\n"); + ObDereferenceObject(Section); + goto exit; + } + ObDereferenceObject(Section); + + /* Save the pointer */ + Process->SectionBaseAddress = ImageBase; + + /* Determine the image file name and save it to EPROCESS */ + DPRINT("Getting Image name\n"); + FileName = Section->FileObject->FileName; + szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1); + + while(szSrc >= FileName.Buffer) + { + if(*szSrc == L'\\') + { + szSrc++; + break; + } + else + { + szSrc--; + lnFName++; + } + } + + /* Copy the to the process and truncate it to 15 characters if necessary */ + DPRINT("Copying and truncating\n"); + szDest = Process->ImageFileName; + lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1); + while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++); + + /* Return status to caller */ + return Status; + } + +exit: + /* Unlock the Address Space */ + DPRINT("Unlocking\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + + /* Return status to caller */ + return Status; +}