Second part of patch, implements the new RTL functions which will be used (not used by kernel yet).

- RtlCreateUserProcess:
        * Created RtlpInitEnvironment to manage Environment Block creation. Rougly based on
          old KlInitPeb code but with some optimizations.
        * Don't ignore Process Security Descriptor if one was specified.
        * Don't ignore ZeroBits, get correct entrypoint, and don't assume PEB address.
        * Don't close handle of section before closing process handle on failure.
        * Support new undocumented flag which pre-allocates 1MB of memory for Native Processes
        * FIXME: Hande duplication should be done, but wasn't and still isn't.
    
    - RtlpCreateUserStack:
        * New function to create a stack for a Thread, similar to BasepCreateStack but
          has some differences related to StackCommit/StackReserve.
        * Also create Guard Page
        
    - RtlpFreeUserStack:
        * Undoes what the function above does, in case of failure in code using it.
        
    - RtlCreateUserThread:
        * Use the new functions instead of rosrtl.
        
    - RtlInitializeContext:
        * New function similar to BasepInitializeContext but;
            > Uses a single entrypoint, not many possible thunks like Kernel32 (no need)
            > The starting EFLAGS is Interrupts Enabled, not IOPL 3.
            > We don't initialize the same Context Flags
            > The initial context registers are different
            
    - RtlFreeUserThreadStack
        * Don't assume the TEB address
          
    - RtlExitUserThread
        * Remove deprecated stack-switching semantics and use new TEB flag to tell the Kernel
          to deallocate the stack for us.

svn path=/trunk/; revision=16542
This commit is contained in:
Alex Ionescu 2005-07-12 04:41:41 +00:00
parent 36a1230e2b
commit e6523bb71e
5 changed files with 611 additions and 350 deletions

View file

@ -16,7 +16,7 @@
/* FIXME */ /* FIXME */
#include <rosrtl/thread.h> #include <rosrtl/thread.h>
//#define NDEBUG #define NDEBUG
#include "../include/debug.h" #include "../include/debug.h"
/* FUNCTIONS ****************************************************************/ /* FUNCTIONS ****************************************************************/
@ -1378,11 +1378,11 @@ CreateProcessW(LPCWSTR lpApplicationName,
* Create the thread for the kernel * Create the thread for the kernel
*/ */
DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n", DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress)); Sii.TransferAddress);
hThread = KlCreateFirstThread(hProcess, hThread = KlCreateFirstThread(hProcess,
lpThreadAttributes, lpThreadAttributes,
&Sii, &Sii,
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress), Sii.TransferAddress,
dwCreationFlags, dwCreationFlags,
&lpProcessInformation->dwThreadId); &lpProcessInformation->dwThreadId);
if (hThread == NULL) if (hThread == NULL)

View file

@ -90,4 +90,19 @@ RtlGetVersion(RTL_OSVERSIONINFOW *Info)
return STATUS_INVALID_PARAMETER; return STATUS_INVALID_PARAMETER;
} }
/*
* @implemented
*/
VOID
STDCALL
RtlExitUserThread(NTSTATUS Status)
{
/* Call the Loader and tell him to notify the DLLs */
LdrShutdownThread();
/* Shut us down */
NtCurrentTeb()->FreeStackOnTermination = TRUE;
NtTerminateThread(NtCurrentThread(), Status);
}
/* EOF */ /* EOF */

View file

@ -16,51 +16,38 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* FUNCTIONS ****************************************************************/ /* INTERNAL FUNCTIONS *******************************************************/
NTSTATUS
static NTSTATUS STDCALL
RtlpMapFile(PUNICODE_STRING ImageFileName, RtlpMapFile(PUNICODE_STRING ImageFileName,
PRTL_USER_PROCESS_PARAMETERS Ppb,
ULONG Attributes, ULONG Attributes,
PHANDLE Section) PHANDLE Section)
{ {
HANDLE hFile;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
NTSTATUS Status; NTSTATUS Status;
HANDLE hFile = NULL;
IO_STATUS_BLOCK IoStatusBlock;
hFile = NULL; /* Open the Image File */
RtlDeNormalizeProcessParams (Ppb);
/* DbgPrint("ImagePathName 0x%p\n", Ppb->ImagePathName.Buffer); */
InitializeObjectAttributes(&ObjectAttributes, InitializeObjectAttributes(&ObjectAttributes,
ImageFileName, ImageFileName,
Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT), Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
NULL, NULL,
SecurityDescriptor); NULL);
RtlNormalizeProcessParams (Ppb);
/*
* Try to open the executable
*/
Status = ZwOpenFile(&hFile, Status = ZwOpenFile(&hFile,
SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA, SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
&ObjectAttributes, &ObjectAttributes,
&IoStatusBlock, &IoStatusBlock,
FILE_SHARE_DELETE|FILE_SHARE_READ, FILE_SHARE_DELETE | FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE); FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to read image file from disk\n");
return(Status); return(Status);
} }
/* Now create a section for this image */
Status = ZwCreateSection(Section, Status = ZwCreateSection(Section,
SECTION_ALL_ACCESS, SECTION_ALL_ACCESS,
NULL, NULL,
@ -68,124 +55,122 @@ RtlpMapFile(PUNICODE_STRING ImageFileName,
PAGE_EXECUTE, PAGE_EXECUTE,
SEC_IMAGE, SEC_IMAGE,
hFile); hFile);
ZwClose(hFile);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
return(Status); DPRINT1("Failed to create section for image file\n");
} }
return(STATUS_SUCCESS); ZwClose(hFile);
return Status;
} }
static NTSTATUS KlInitPeb (HANDLE ProcessHandle, /* FUNCTIONS ****************************************************************/
PRTL_USER_PROCESS_PARAMETERS Ppb,
PVOID* ImageBaseAddress) NTSTATUS
STDCALL
RtlpInitEnvironment(HANDLE ProcessHandle,
PPEB Peb,
PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
{ {
NTSTATUS Status; NTSTATUS Status;
PVOID PpbBase; PVOID BaseAddress = NULL;
ULONG PpbSize; ULONG EnviroSize;
ULONG BytesWritten; ULONG Size;
ULONG Offset; PWCHAR Environment = 0;
PVOID EnvPtr = NULL;
ULONG EnvSize = 0;
/* create the Environment */ DPRINT("RtlpInitEnvironment (hProcess: %lx, Peb: %p Params: %p)\n",
if (Ppb->Environment != NULL) ProcessHandle, Peb, ProcessParameters);
/* Give the caller 1MB if he requested it */
if (ProcessParameters->Flags & PPF_RESERVE_1MB)
{ {
MEMORY_BASIC_INFORMATION MemInfo; /* Give 1MB starting at 0x4 */
BaseAddress = (PVOID)4;
EnviroSize = 1024 * 1024;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&BaseAddress,
0,
&EnviroSize,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to reserve 1MB of space \n");
return(Status);
}
}
Status = ZwQueryVirtualMemory (NtCurrentProcess (), /* Find the end of the Enviroment Block */
Ppb->Environment, if ((Environment = (PWCHAR)ProcessParameters->Environment))
MemoryBasicInformation, {
&MemInfo, while (*Environment++) while (*Environment++);
sizeof(MEMORY_BASIC_INFORMATION),
/* Calculate the size of the block */
EnviroSize = (ULONG)((ULONG_PTR)Environment -
(ULONG_PTR)ProcessParameters->Environment);
DPRINT("EnvironmentSize %ld\n", EnviroSize);
/* Allocate and Initialize new Environment Block */
Size = EnviroSize;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&BaseAddress,
0,
&Size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to allocate Environment Block\n");
return(Status);
}
/* Write the Environment Block */
ZwWriteVirtualMemory(ProcessHandle,
BaseAddress,
ProcessParameters->Environment,
EnviroSize,
NULL); NULL);
if (!NT_SUCCESS(Status))
{
return Status;
}
EnvSize = MemInfo.RegionSize;
}
DPRINT("EnvironmentSize %ld\n", EnvSize);
/* allocate and initialize new environment block */ /* Save pointer */
if (EnvSize != 0) ProcessParameters->Environment = BaseAddress;
{ }
DPRINT("EnvironmentPointer %p\n", BaseAddress);
DPRINT("Ppb->MaximumLength %x\n", ProcessParameters->MaximumLength);
/* Now allocate space for the Parameter Block */
BaseAddress = NULL;
Size = ProcessParameters->MaximumLength;
Status = ZwAllocateVirtualMemory(ProcessHandle, Status = ZwAllocateVirtualMemory(ProcessHandle,
&EnvPtr, &BaseAddress,
0, 0,
&EnvSize, &Size,
MEM_RESERVE | MEM_COMMIT, MEM_COMMIT,
PAGE_READWRITE); PAGE_READWRITE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to allocate Parameter Block\n");
return(Status); return(Status);
} }
/* Write the Parameter Block */
ZwWriteVirtualMemory(ProcessHandle, ZwWriteVirtualMemory(ProcessHandle,
EnvPtr, BaseAddress,
Ppb->Environment, ProcessParameters,
EnvSize, ProcessParameters->Length,
&BytesWritten); NULL);
}
DPRINT("EnvironmentPointer %p\n", EnvPtr);
/* create the PPB */ /* Write pointer to Parameter Block */
PpbBase = NULL;
PpbSize = Ppb->MaximumLength;
Status = ZwAllocateVirtualMemory(ProcessHandle,
&PpbBase,
0,
&PpbSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
return(Status);
}
DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
/* write process parameters block*/
RtlDeNormalizeProcessParams (Ppb);
ZwWriteVirtualMemory(ProcessHandle, ZwWriteVirtualMemory(ProcessHandle,
PpbBase, &Peb->ProcessParameters,
Ppb, &BaseAddress,
Ppb->MaximumLength, sizeof(BaseAddress),
NULL);
&BytesWritten); /* Return */
RtlNormalizeProcessParams (Ppb); return STATUS_SUCCESS;
/* write pointer to environment */
Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)((ULONG_PTR)PpbBase + Offset),
&EnvPtr,
sizeof(EnvPtr),
&BytesWritten);
/* write pointer to process parameter block */
Offset = FIELD_OFFSET(PEB, ProcessParameters);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)(PEB_BASE + Offset),
&PpbBase,
sizeof(PpbBase),
&BytesWritten);
/* Read image base address. */
Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
ZwReadVirtualMemory(ProcessHandle,
(PVOID)(PEB_BASE + Offset),
ImageBaseAddress,
sizeof(PVOID),
&BytesWritten);
return(STATUS_SUCCESS);
} }
/* /*
* @implemented * @implemented
* *
@ -200,9 +185,9 @@ static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
* *
* -Gunnar * -Gunnar
*/ */
NTSTATUS STDCALL NTSTATUS
RtlCreateUserProcess( STDCALL
IN PUNICODE_STRING ImageFileName, RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
IN ULONG Attributes, IN ULONG Attributes,
IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters, IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL, IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
@ -211,35 +196,58 @@ RtlCreateUserProcess(
IN BOOLEAN InheritHandles, IN BOOLEAN InheritHandles,
IN HANDLE DebugPort OPTIONAL, IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL,
OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
)
{ {
HANDLE hSection;
NTSTATUS Status; NTSTATUS Status;
HANDLE hSection;
PROCESS_BASIC_INFORMATION ProcessBasicInfo; PROCESS_BASIC_INFORMATION ProcessBasicInfo;
ULONG retlen; OBJECT_ATTRIBUTES ObjectAttributes;
SECTION_IMAGE_INFORMATION Sii;
ULONG ResultLength;
PVOID ImageBaseAddress;
DPRINT("RtlCreateUserProcess\n"); DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
/* Map and Load the File */
Status = RtlpMapFile(ImageFileName, Status = RtlpMapFile(ImageFileName,
ProcessParameters,
Attributes, Attributes,
&hSection); &hSection);
if( !NT_SUCCESS( Status ) ) if(!NT_SUCCESS(Status))
{
DPRINT1("Could not map process image\n");
return Status; return Status;
}
/* Clean out the CurDir Handle if we won't use it */
if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
/* Use us as parent if none other specified */
if (!ParentProcess) ParentProcess = NtCurrentProcess();
/* Initialize the Object Attributes */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
ProcessSecurityDescriptor);
/* /*
* Create a new process * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
* watch of WindowsSS
*/ */
if (ParentProcess == NULL) if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) &&
ParentProcess = NtCurrentProcess(); (wcsstr(ImageFileName->Buffer, L"csrss")))
{
Status = ZwCreateProcess(&(ProcessInfo->ProcessHandle), UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
PROCESS_ALL_ACCESS, InitializeObjectAttributes(&ObjectAttributes,
&DebugString,
0,
NULL, NULL,
ProcessSecurityDescriptor);
}
/* Create Kernel Process Object */
Status = ZwCreateProcess(&ProcessInfo->ProcessHandle,
PROCESS_ALL_ACCESS,
&ObjectAttributes,
ParentProcess, ParentProcess,
InheritHandles, InheritHandles,
hSection, hSection,
@ -247,67 +255,66 @@ RtlCreateUserProcess(
ExceptionPort); ExceptionPort);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Could not create Kernel Process Object\n");
ZwClose(hSection); ZwClose(hSection);
return(Status); return(Status);
} }
/* /* Get some information on the image */
* Get some information about the process Status = ZwQuerySection(hSection,
*/ SectionImageInformation,
&ProcessInfo->ImageInformation,
sizeof(SECTION_IMAGE_INFORMATION),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Could not query Section Info\n");
ZwClose(ProcessInfo->ProcessHandle);
ZwClose(hSection);
return(Status);
}
/* Get some information about the process */
ZwQueryInformationProcess(ProcessInfo->ProcessHandle, ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
ProcessBasicInformation, ProcessBasicInformation,
&ProcessBasicInfo, &ProcessBasicInfo,
sizeof(ProcessBasicInfo), sizeof(ProcessBasicInfo),
&retlen); NULL);
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
ProcessBasicInfo.UniqueProcessId);
ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
/*
* Create Process Environment Block
*/
DPRINT("Creating peb\n");
KlInitPeb(ProcessInfo->ProcessHandle,
ProcessParameters,
&ImageBaseAddress);
Status = ZwQuerySection(hSection,
SectionImageInformation,
&Sii,
sizeof(Sii),
&ResultLength);
if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
{
DPRINT("Failed to get section image information.\n");
ZwClose(hSection);
return(Status);
}
DPRINT("Creating thread for process\n");
Status = RtlCreateUserThread(
ProcessInfo->ProcessHandle,
NULL,
TRUE, /* CreateSuspended? */
0,
Sii.MaximumStackSize,
Sii.CommittedStackSize,
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
(PVOID)PEB_BASE,
&ProcessInfo->ThreadHandle,
&ProcessInfo->ClientId
);
ZwClose(hSection);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT("Failed to create thread\n"); DPRINT1("Could not query Process Info\n");
ZwClose(ProcessInfo->ProcessHandle);
ZwClose(hSection);
return(Status); return(Status);
} }
return(STATUS_SUCCESS); /* Create Process Environment */
RtlpInitEnvironment(ProcessInfo->ProcessHandle,
ProcessBasicInfo.PebBaseAddress,
ProcessParameters);
/* Create the first Thread */
Status = RtlCreateUserThread(ProcessInfo->ProcessHandle,
ThreadSecurityDescriptor,
TRUE,
ProcessInfo->ImageInformation.ZeroBits,
ProcessInfo->ImageInformation.MaximumStackSize,
ProcessInfo->ImageInformation.CommittedStackSize,
ProcessInfo->ImageInformation.TransferAddress,
ProcessBasicInfo.PebBaseAddress,
&ProcessInfo->ThreadHandle,
&ProcessInfo->ClientId);
if (!NT_SUCCESS(Status))
{
DPRINT1("Could not Create Thread\n");
ZwClose(ProcessInfo->ProcessHandle);
ZwClose(hSection); /* Don't try to optimize this on top! */
return Status;
}
/* Close the Section Handle and return */
ZwClose(hSection);
return STATUS_SUCCESS;
} }
/* EOF */ /* EOF */

View file

@ -3,35 +3,176 @@
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* PURPOSE: Rtl user thread functions * PURPOSE: Rtl user thread functions
* FILE: lib/ntdll/rtl/thread.c * FILE: lib/ntdll/rtl/thread.c
* PROGRAMER: Eric Kohl * PROGRAMERS:
* REVISION HISTORY: * Alex Ionescu (alex@relsoft.net)
* 09/07/99: Created * Eric Kohl
* 09/10/99: Cleanup and full stack support. * KJK::Hyperion
* 25/04/03: Near rewrite. Made code more readable, replaced
* INITIAL_TEB with USER_STACK, added support for
* fixed-size stacks
* 28/04/03: Moved all code to a new statically linked
* library (ROSRTL) so it can be shared with
* kernel32.dll without exporting non-standard
* functions from ntdll.dll
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
#include "rtl.h" #include "rtl.h"
#include <rosrtl/thread.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* PRIVATE FUNCTIONS *******************************************************/
NTSTATUS
STDCALL
RtlpCreateUserStack(HANDLE hProcess,
ULONG StackReserve,
ULONG StackCommit,
ULONG StackZeroBits,
PINITIAL_TEB InitialTeb)
{
NTSTATUS Status;
SYSTEM_BASIC_INFORMATION SystemBasicInfo;
PIMAGE_NT_HEADERS Headers;
ULONG_PTR Stack = 0;
BOOLEAN UseGuard = FALSE;
DPRINT("RtlpCreateUserStack\n");
/* Get some memory information */
Status = NtQuerySystemInformation(SystemBasicInformation,
&SystemBasicInfo,
sizeof(SYSTEM_BASIC_INFORMATION),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to query system info\n");
return Status;
}
/* Use the Image Settings if we are dealing with the current Process */
if (hProcess == NtCurrentProcess())
{
/* Get the Image Headers */
Headers = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
DPRINT("Headers: %p\n", Headers);
/* If we didn't get the parameters, find them ourselves */
StackReserve = (StackReserve) ?
StackReserve : Headers->OptionalHeader.SizeOfStackReserve;
StackCommit = (StackCommit) ?
StackCommit : Headers->OptionalHeader.SizeOfStackCommit;
}
else
{
/* Use the System Settings if needed */
StackReserve = (StackReserve) ? StackReserve :
SystemBasicInfo.AllocationGranularity;
StackCommit = (StackCommit) ? StackCommit : SystemBasicInfo.PageSize;
}
/* Align everything to Page Size */
StackReserve = ROUND_UP(StackReserve, SystemBasicInfo.AllocationGranularity);
StackCommit = ROUND_UP(StackCommit, SystemBasicInfo.PageSize);
#if 1 // FIXME: Remove once Guard Page support is here
StackCommit = StackReserve;
#endif
DPRINT("StackReserve: %lx, StackCommit: %lx\n", StackReserve, StackCommit);
/* Reserve memory for the stack */
Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack,
StackZeroBits,
&StackReserve,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to reserve stack\n");
return Status;
}
/* Now set up some basic Initial TEB Parameters */
InitialTeb->AllocatedStackBase = (PVOID)Stack;
InitialTeb->StackBase = (PVOID)(Stack + StackReserve);
/* Update the Stack Position */
Stack += StackReserve - StackCommit;
/* Check if we will need a guard page */
if (StackReserve > StackCommit)
{
Stack -= SystemBasicInfo.PageSize;
StackCommit += SystemBasicInfo.PageSize;
UseGuard = TRUE;
}
DPRINT("AllocatedBase: %p, StackBase: %p, Stack: %p, StackCommit: %lx\n",
InitialTeb->AllocatedStackBase, InitialTeb->StackBase, Stack,
StackCommit);
/* Allocate memory for the stack */
Status = ZwAllocateVirtualMemory(hProcess,
(PVOID*)&Stack,
0,
&StackCommit,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to allocate stack\n");
return Status;
}
/* Now set the current Stack Limit */
InitialTeb->StackLimit = (PVOID)Stack;
DPRINT("StackLimit: %p\n", Stack);
/* Create a guard page */
if (UseGuard)
{
ULONG GuardPageSize = SystemBasicInfo.PageSize;
ULONG Dummy;
/* Attempt maximum space possible */
Status = ZwProtectVirtualMemory(hProcess,
(PVOID*)&Stack,
&GuardPageSize,
PAGE_GUARD | PAGE_READWRITE,
&Dummy);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to create guard page\n");
return Status;
}
/* Update the Stack Limit keeping in mind the Guard Page */
InitialTeb->StackLimit = (PVOID)((ULONG_PTR)InitialTeb->StackLimit -
GuardPageSize);
DPRINT1("StackLimit: %p\n", Stack);
}
/* We are done! */
return Status;
}
NTSTATUS
STDCALL
RtlpFreeUserStack(HANDLE hProcess,
PINITIAL_TEB InitialTeb)
{
ULONG Dummy = 0;
/* Free the Stack */
return ZwFreeVirtualMemory(hProcess,
&InitialTeb->AllocatedStackBase,
&Dummy,
MEM_RELEASE);
}
/* FUNCTIONS ***************************************************************/ /* FUNCTIONS ***************************************************************/
/* /*
@implemented @implemented
*/ */
NTSTATUS STDCALL RtlCreateUserThread NTSTATUS
( STDCALL
HANDLE ProcessHandle, RtlCreateUserThread(HANDLE ProcessHandle,
PSECURITY_DESCRIPTOR SecurityDescriptor, PSECURITY_DESCRIPTOR SecurityDescriptor,
BOOLEAN CreateSuspended, BOOLEAN CreateSuspended,
LONG StackZeroBits, LONG StackZeroBits,
@ -40,76 +181,171 @@ NTSTATUS STDCALL RtlCreateUserThread
PTHREAD_START_ROUTINE StartAddress, PTHREAD_START_ROUTINE StartAddress,
PVOID Parameter, PVOID Parameter,
PHANDLE ThreadHandle, PHANDLE ThreadHandle,
PCLIENT_ID ClientId PCLIENT_ID ClientId)
)
{ {
OBJECT_ATTRIBUTES oaThreadAttribs; NTSTATUS Status;
HANDLE Handle;
CLIENT_ID ThreadCid;
INITIAL_TEB InitialTeb;
OBJECT_ATTRIBUTES ObjectAttributes;
CONTEXT Context;
InitializeObjectAttributes DPRINT("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx,"
( "ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx,"
&oaThreadAttribs, "StartAddress: %p, Parameter: %lx)\n", ProcessHandle,
CreateSuspended, StackZeroBits, StackReserve, StackCommit,
StartAddress, Parameter);
/* First, we'll create the Stack */
Status = RtlpCreateUserStack(ProcessHandle,
StackReserve,
StackCommit,
StackZeroBits,
&InitialTeb);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failure to create User Stack\n");
return Status;
}
/* Next, we'll set up the Initial Context */
RtlInitializeContext(ProcessHandle,
&Context,
Parameter,
StartAddress,
InitialTeb.StackBase);
/* We are now ready to create the Kernel Thread Object */
InitializeObjectAttributes(&ObjectAttributes,
NULL, NULL,
0, 0,
NULL, NULL,
SecurityDescriptor SecurityDescriptor);
); Status = ZwCreateThread(&Handle,
THREAD_ALL_ACCESS,
return RtlRosCreateUserThread &ObjectAttributes,
(
ProcessHandle, ProcessHandle,
&oaThreadAttribs, &ThreadCid,
CreateSuspended, &Context,
StackZeroBits, &InitialTeb,
&StackReserve, CreateSuspended);
&StackCommit, if (!NT_SUCCESS(Status))
StartAddress, {
ThreadHandle, DPRINT1("Failure to create Thread\n");
ClientId,
1, /* Free the stack */
(ULONG_PTR *)&Parameter RtlpFreeUserStack(ProcessHandle, &InitialTeb);
); }
else
{
DPRINT("Thread created: %lx\n", Handle);
if (ThreadHandle) *ThreadHandle = Handle;
if (ClientId) *ClientId = ThreadCid;
}
/* Return success or the previous failure */
return Status;
} }
/* /*
* FIXME: Should go in /i386
@implemented @implemented
*/ */
VOID STDCALL VOID
RtlInitializeContext( STDCALL
IN HANDLE ProcessHandle, RtlInitializeContext(IN HANDLE ProcessHandle,
OUT PCONTEXT ThreadContext, OUT PCONTEXT ThreadContext,
IN PVOID ThreadStartParam OPTIONAL, IN PVOID ThreadStartParam OPTIONAL,
IN PTHREAD_START_ROUTINE ThreadStartAddress, IN PTHREAD_START_ROUTINE ThreadStartAddress,
IN PINITIAL_TEB InitialTeb) IN PINITIAL_TEB InitialTeb)
{ {
RtlRosInitializeContext DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n",
( ProcessHandle, ThreadContext, InitialTeb);
ProcessHandle,
ThreadContext, /*
ThreadStartAddress, * Set the Initial Registers
InitialTeb, * This is based on NT's default values -- crazy apps might expect this...
1, */
(ULONG_PTR *)&ThreadStartParam ThreadContext->Ebp = 0;
); ThreadContext->Eax = 0;
ThreadContext->Ebx = 1;
ThreadContext->Ecx = 2;
ThreadContext->Edx = 3;
ThreadContext->Esi = 4;
ThreadContext->Edi = 5;
/* Set the Selectors */
ThreadContext->SegGs = 0;
ThreadContext->SegFs = TEB_SELECTOR;
ThreadContext->SegEs = USER_DS;
ThreadContext->SegDs = USER_DS;
ThreadContext->SegCs = USER_CS;
ThreadContext->SegSs = USER_DS;
/* Enable Interrupts */
ThreadContext->EFlags = 0x200; /*X86_EFLAGS_IF */
/* Settings passed */
ThreadContext->Eip = (ULONG)ThreadStartAddress;
ThreadContext->Esp = (ULONG)InitialTeb;
/* Only the basic Context is initialized */
ThreadContext->ContextFlags = CONTEXT_CONTROL |
CONTEXT_INTEGER |
CONTEXT_SEGMENTS;
/* Set up ESP to the right value */
ThreadContext->Esp -= sizeof(PVOID);
ZwWriteVirtualMemory(ProcessHandle,
(PVOID)ThreadContext->Esp,
(PVOID)&ThreadStartParam,
sizeof(PVOID),
NULL);
/* Push it down one more notch for RETEIP */
ThreadContext->Esp -= sizeof(PVOID);
} }
/* /*
@implemented @implemented
*/ */
NTSTATUS STDCALL RtlFreeUserThreadStack VOID
( STDCALL
HANDLE ProcessHandle, RtlFreeUserThreadStack(HANDLE ProcessHandle,
HANDLE ThreadHandle HANDLE ThreadHandle)
)
{ {
return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle); NTSTATUS Status;
} THREAD_BASIC_INFORMATION ThreadBasicInfo;
ULONG Dummy, Size = 0;
PVOID StackLocation;
/* /* Query the Basic Info */
@implemented Status = NtQueryInformationThread(ThreadHandle,
*/ ThreadBasicInformation,
VOID STDCALL RtlExitUserThread(NTSTATUS Status) &ThreadBasicInfo,
{ sizeof(THREAD_BASIC_INFORMATION),
RtlRosExitUserThread(Status); NULL);
if (!NT_SUCCESS(Status) || !ThreadBasicInfo.TebBaseAddress)
{
DPRINT1("Could not query info, or TEB is NULL\n");
return;
}
/* Get the deallocation stack */
Status = NtReadVirtualMemory(ProcessHandle,
&((PTEB)ThreadBasicInfo.TebBaseAddress)->
DeallocationStack,
&StackLocation,
sizeof(PVOID),
&Dummy);
if (!NT_SUCCESS(Status) || !StackLocation)
{
DPRINT1("Could not read Deallocation Base\n");
return;
}
/* Free it */
NtFreeVirtualMemory(ProcessHandle, &StackLocation, &Size, MEM_RELEASE);
} }
/* EOF */ /* EOF */

View file

@ -483,7 +483,10 @@ l_ReadHeaderFromFile:
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint)); ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, AddressOfEntryPoint));
if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint)) if(RTL_CONTAINS_FIELD(piohOptHeader, cbOptHeaderSize, AddressOfEntryPoint))
ImageSectionObject->EntryPoint = piohOptHeader->AddressOfEntryPoint; {
ImageSectionObject->EntryPoint = piohOptHeader->ImageBase +
piohOptHeader->AddressOfEntryPoint;
}
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode)); ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, SizeOfCode));