mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
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:
parent
36a1230e2b
commit
e6523bb71e
5 changed files with 611 additions and 350 deletions
|
@ -16,7 +16,7 @@
|
|||
/* FIXME */
|
||||
#include <rosrtl/thread.h>
|
||||
|
||||
//#define NDEBUG
|
||||
#define NDEBUG
|
||||
#include "../include/debug.h"
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
@ -1378,11 +1378,11 @@ CreateProcessW(LPCWSTR lpApplicationName,
|
|||
* Create the thread for the kernel
|
||||
*/
|
||||
DPRINT("Creating thread for process (EntryPoint = 0x%.08x)\n",
|
||||
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress));
|
||||
Sii.TransferAddress);
|
||||
hThread = KlCreateFirstThread(hProcess,
|
||||
lpThreadAttributes,
|
||||
&Sii,
|
||||
(PVOID)((ULONG_PTR)ImageBaseAddress + (ULONG_PTR)Sii.TransferAddress),
|
||||
Sii.TransferAddress,
|
||||
dwCreationFlags,
|
||||
&lpProcessInformation->dwThreadId);
|
||||
if (hThread == NULL)
|
||||
|
|
|
@ -90,4 +90,19 @@ RtlGetVersion(RTL_OSVERSIONINFOW *Info)
|
|||
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 */
|
||||
|
|
|
@ -16,176 +16,161 @@
|
|||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* INTERNAL FUNCTIONS *******************************************************/
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
RtlpMapFile(PUNICODE_STRING ImageFileName,
|
||||
ULONG Attributes,
|
||||
PHANDLE Section)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
NTSTATUS Status;
|
||||
HANDLE hFile = NULL;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
|
||||
/* Open the Image File */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
ImageFileName,
|
||||
Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwOpenFile(&hFile,
|
||||
SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_DELETE | FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to read image file from disk\n");
|
||||
return(Status);
|
||||
}
|
||||
|
||||
/* Now create a section for this image */
|
||||
Status = ZwCreateSection(Section,
|
||||
SECTION_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
PAGE_EXECUTE,
|
||||
SEC_IMAGE,
|
||||
hFile);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create section for image file\n");
|
||||
}
|
||||
|
||||
ZwClose(hFile);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
||||
static NTSTATUS
|
||||
RtlpMapFile(PUNICODE_STRING ImageFileName,
|
||||
PRTL_USER_PROCESS_PARAMETERS Ppb,
|
||||
ULONG Attributes,
|
||||
PHANDLE Section)
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
RtlpInitEnvironment(HANDLE ProcessHandle,
|
||||
PPEB Peb,
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
|
||||
{
|
||||
HANDLE hFile;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
|
||||
NTSTATUS Status;
|
||||
NTSTATUS Status;
|
||||
PVOID BaseAddress = NULL;
|
||||
ULONG EnviroSize;
|
||||
ULONG Size;
|
||||
PWCHAR Environment = 0;
|
||||
|
||||
DPRINT("RtlpInitEnvironment (hProcess: %lx, Peb: %p Params: %p)\n",
|
||||
ProcessHandle, Peb, ProcessParameters);
|
||||
|
||||
/* Give the caller 1MB if he requested it */
|
||||
if (ProcessParameters->Flags & PPF_RESERVE_1MB)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the end of the Enviroment Block */
|
||||
if ((Environment = (PWCHAR)ProcessParameters->Environment))
|
||||
{
|
||||
while (*Environment++) while (*Environment++);
|
||||
|
||||
hFile = NULL;
|
||||
/* Calculate the size of the block */
|
||||
EnviroSize = (ULONG)((ULONG_PTR)Environment -
|
||||
(ULONG_PTR)ProcessParameters->Environment);
|
||||
DPRINT("EnvironmentSize %ld\n", EnviroSize);
|
||||
|
||||
RtlDeNormalizeProcessParams (Ppb);
|
||||
/* 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);
|
||||
|
||||
/* Save pointer */
|
||||
ProcessParameters->Environment = BaseAddress;
|
||||
}
|
||||
|
||||
DPRINT("EnvironmentPointer %p\n", BaseAddress);
|
||||
DPRINT("Ppb->MaximumLength %x\n", ProcessParameters->MaximumLength);
|
||||
|
||||
/* DbgPrint("ImagePathName 0x%p\n", Ppb->ImagePathName.Buffer); */
|
||||
/* Now allocate space for the Parameter Block */
|
||||
BaseAddress = NULL;
|
||||
Size = ProcessParameters->MaximumLength;
|
||||
Status = ZwAllocateVirtualMemory(ProcessHandle,
|
||||
&BaseAddress,
|
||||
0,
|
||||
&Size,
|
||||
MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to allocate Parameter Block\n");
|
||||
return(Status);
|
||||
}
|
||||
|
||||
/* Write the Parameter Block */
|
||||
ZwWriteVirtualMemory(ProcessHandle,
|
||||
BaseAddress,
|
||||
ProcessParameters,
|
||||
ProcessParameters->Length,
|
||||
NULL);
|
||||
|
||||
/* Write pointer to Parameter Block */
|
||||
ZwWriteVirtualMemory(ProcessHandle,
|
||||
&Peb->ProcessParameters,
|
||||
&BaseAddress,
|
||||
sizeof(BaseAddress),
|
||||
NULL);
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
ImageFileName,
|
||||
Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
|
||||
NULL,
|
||||
SecurityDescriptor);
|
||||
|
||||
RtlNormalizeProcessParams (Ppb);
|
||||
|
||||
/*
|
||||
* Try to open the executable
|
||||
*/
|
||||
|
||||
Status = ZwOpenFile(&hFile,
|
||||
SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_DELETE|FILE_SHARE_READ,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
Status = ZwCreateSection(Section,
|
||||
SECTION_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
PAGE_EXECUTE,
|
||||
SEC_IMAGE,
|
||||
hFile);
|
||||
ZwClose(hFile);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
/* Return */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
|
||||
PRTL_USER_PROCESS_PARAMETERS Ppb,
|
||||
PVOID* ImageBaseAddress)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PVOID PpbBase;
|
||||
ULONG PpbSize;
|
||||
ULONG BytesWritten;
|
||||
ULONG Offset;
|
||||
PVOID EnvPtr = NULL;
|
||||
ULONG EnvSize = 0;
|
||||
|
||||
/* create the Environment */
|
||||
if (Ppb->Environment != NULL)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION MemInfo;
|
||||
|
||||
Status = ZwQueryVirtualMemory (NtCurrentProcess (),
|
||||
Ppb->Environment,
|
||||
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)
|
||||
{
|
||||
Status = ZwAllocateVirtualMemory(ProcessHandle,
|
||||
&EnvPtr,
|
||||
0,
|
||||
&EnvSize,
|
||||
MEM_RESERVE | MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
ZwWriteVirtualMemory(ProcessHandle,
|
||||
EnvPtr,
|
||||
Ppb->Environment,
|
||||
EnvSize,
|
||||
&BytesWritten);
|
||||
}
|
||||
DPRINT("EnvironmentPointer %p\n", EnvPtr);
|
||||
|
||||
/* create the PPB */
|
||||
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,
|
||||
PpbBase,
|
||||
Ppb,
|
||||
Ppb->MaximumLength,
|
||||
|
||||
&BytesWritten);
|
||||
RtlNormalizeProcessParams (Ppb);
|
||||
|
||||
/* 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
|
||||
*
|
||||
|
@ -200,114 +185,136 @@ static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
|
|||
*
|
||||
* -Gunnar
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
RtlCreateUserProcess(
|
||||
IN PUNICODE_STRING ImageFileName,
|
||||
IN ULONG Attributes,
|
||||
IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
|
||||
IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
|
||||
IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
|
||||
IN HANDLE ParentProcess OPTIONAL,
|
||||
IN BOOLEAN InheritHandles,
|
||||
IN HANDLE DebugPort OPTIONAL,
|
||||
IN HANDLE ExceptionPort OPTIONAL,
|
||||
OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo
|
||||
)
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
|
||||
IN ULONG Attributes,
|
||||
IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
|
||||
IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
|
||||
IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
|
||||
IN HANDLE ParentProcess OPTIONAL,
|
||||
IN BOOLEAN InheritHandles,
|
||||
IN HANDLE DebugPort OPTIONAL,
|
||||
IN HANDLE ExceptionPort OPTIONAL,
|
||||
OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
|
||||
{
|
||||
HANDLE hSection;
|
||||
NTSTATUS Status;
|
||||
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
|
||||
ULONG retlen;
|
||||
SECTION_IMAGE_INFORMATION Sii;
|
||||
ULONG ResultLength;
|
||||
PVOID ImageBaseAddress;
|
||||
NTSTATUS Status;
|
||||
HANDLE hSection;
|
||||
PROCESS_BASIC_INFORMATION ProcessBasicInfo;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
|
||||
DPRINT("RtlCreateUserProcess\n");
|
||||
DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
|
||||
|
||||
Status = RtlpMapFile(ImageFileName,
|
||||
ProcessParameters,
|
||||
Attributes,
|
||||
&hSection);
|
||||
if( !NT_SUCCESS( Status ) )
|
||||
return Status;
|
||||
/* Map and Load the File */
|
||||
Status = RtlpMapFile(ImageFileName,
|
||||
Attributes,
|
||||
&hSection);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Could not map process image\n");
|
||||
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 (ParentProcess == NULL)
|
||||
ParentProcess = NtCurrentProcess();
|
||||
/*
|
||||
* If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
|
||||
* watch of WindowsSS
|
||||
*/
|
||||
if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) &&
|
||||
(wcsstr(ImageFileName->Buffer, L"csrss")))
|
||||
{
|
||||
UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&DebugString,
|
||||
0,
|
||||
NULL,
|
||||
ProcessSecurityDescriptor);
|
||||
}
|
||||
|
||||
|
||||
/* Create Kernel Process Object */
|
||||
Status = ZwCreateProcess(&ProcessInfo->ProcessHandle,
|
||||
PROCESS_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
ParentProcess,
|
||||
InheritHandles,
|
||||
hSection,
|
||||
DebugPort,
|
||||
ExceptionPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Could not create Kernel Process Object\n");
|
||||
ZwClose(hSection);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
/* Get some information on the image */
|
||||
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);
|
||||
}
|
||||
|
||||
Status = ZwCreateProcess(&(ProcessInfo->ProcessHandle),
|
||||
PROCESS_ALL_ACCESS,
|
||||
NULL,
|
||||
ParentProcess,
|
||||
InheritHandles,
|
||||
hSection,
|
||||
DebugPort,
|
||||
ExceptionPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ZwClose(hSection);
|
||||
return(Status);
|
||||
}
|
||||
/* Get some information about the process */
|
||||
ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
|
||||
ProcessBasicInformation,
|
||||
&ProcessBasicInfo,
|
||||
sizeof(ProcessBasicInfo),
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Could not query Process Info\n");
|
||||
ZwClose(ProcessInfo->ProcessHandle);
|
||||
ZwClose(hSection);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get some information about the process
|
||||
*/
|
||||
ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
|
||||
ProcessBasicInformation,
|
||||
&ProcessBasicInfo,
|
||||
sizeof(ProcessBasicInfo),
|
||||
&retlen);
|
||||
DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
|
||||
ProcessBasicInfo.UniqueProcessId);
|
||||
ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
|
||||
/* Create Process Environment */
|
||||
RtlpInitEnvironment(ProcessInfo->ProcessHandle,
|
||||
ProcessBasicInfo.PebBaseAddress,
|
||||
ProcessParameters);
|
||||
|
||||
/*
|
||||
* 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))
|
||||
{
|
||||
DPRINT("Failed to create thread\n");
|
||||
return(Status);
|
||||
}
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
/* 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 */
|
||||
|
|
|
@ -3,113 +3,349 @@
|
|||
* PROJECT: ReactOS kernel
|
||||
* PURPOSE: Rtl user thread functions
|
||||
* FILE: lib/ntdll/rtl/thread.c
|
||||
* PROGRAMER: Eric Kohl
|
||||
* REVISION HISTORY:
|
||||
* 09/07/99: Created
|
||||
* 09/10/99: Cleanup and full stack support.
|
||||
* 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
|
||||
* PROGRAMERS:
|
||||
* Alex Ionescu (alex@relsoft.net)
|
||||
* Eric Kohl
|
||||
* KJK::Hyperion
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include "rtl.h"
|
||||
#include <rosrtl/thread.h>
|
||||
|
||||
#define NDEBUG
|
||||
#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 ***************************************************************/
|
||||
|
||||
/*
|
||||
@implemented
|
||||
*/
|
||||
NTSTATUS STDCALL RtlCreateUserThread
|
||||
(
|
||||
HANDLE ProcessHandle,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
BOOLEAN CreateSuspended,
|
||||
LONG StackZeroBits,
|
||||
ULONG StackReserve,
|
||||
ULONG StackCommit,
|
||||
PTHREAD_START_ROUTINE StartAddress,
|
||||
PVOID Parameter,
|
||||
PHANDLE ThreadHandle,
|
||||
PCLIENT_ID ClientId
|
||||
)
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
RtlCreateUserThread(HANDLE ProcessHandle,
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
BOOLEAN CreateSuspended,
|
||||
LONG StackZeroBits,
|
||||
ULONG StackReserve,
|
||||
ULONG StackCommit,
|
||||
PTHREAD_START_ROUTINE StartAddress,
|
||||
PVOID Parameter,
|
||||
PHANDLE ThreadHandle,
|
||||
PCLIENT_ID ClientId)
|
||||
{
|
||||
OBJECT_ATTRIBUTES oaThreadAttribs;
|
||||
NTSTATUS Status;
|
||||
HANDLE Handle;
|
||||
CLIENT_ID ThreadCid;
|
||||
INITIAL_TEB InitialTeb;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
CONTEXT Context;
|
||||
|
||||
DPRINT("RtlCreateUserThread: (hProcess: %lx, Suspended: %lx,"
|
||||
"ZeroBits: %lx, StackReserve: %lx, StackCommit: %lx,"
|
||||
"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,
|
||||
0,
|
||||
NULL,
|
||||
SecurityDescriptor);
|
||||
Status = ZwCreateThread(&Handle,
|
||||
THREAD_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
ProcessHandle,
|
||||
&ThreadCid,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
CreateSuspended);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failure to create Thread\n");
|
||||
|
||||
/* Free the stack */
|
||||
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;
|
||||
}
|
||||
|
||||
InitializeObjectAttributes
|
||||
(
|
||||
&oaThreadAttribs,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
SecurityDescriptor
|
||||
);
|
||||
/*
|
||||
* FIXME: Should go in /i386
|
||||
@implemented
|
||||
*/
|
||||
VOID
|
||||
STDCALL
|
||||
RtlInitializeContext(IN HANDLE ProcessHandle,
|
||||
OUT PCONTEXT ThreadContext,
|
||||
IN PVOID ThreadStartParam OPTIONAL,
|
||||
IN PTHREAD_START_ROUTINE ThreadStartAddress,
|
||||
IN PINITIAL_TEB InitialTeb)
|
||||
{
|
||||
DPRINT("RtlInitializeContext: (hProcess: %lx, ThreadContext: %p, Teb: %p\n",
|
||||
ProcessHandle, ThreadContext, InitialTeb);
|
||||
|
||||
return RtlRosCreateUserThread
|
||||
(
|
||||
ProcessHandle,
|
||||
&oaThreadAttribs,
|
||||
CreateSuspended,
|
||||
StackZeroBits,
|
||||
&StackReserve,
|
||||
&StackCommit,
|
||||
StartAddress,
|
||||
ThreadHandle,
|
||||
ClientId,
|
||||
1,
|
||||
(ULONG_PTR *)&Parameter
|
||||
);
|
||||
/*
|
||||
* Set the Initial Registers
|
||||
* This is based on NT's default values -- crazy apps might expect this...
|
||||
*/
|
||||
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
|
||||
*/
|
||||
VOID STDCALL
|
||||
RtlInitializeContext(
|
||||
IN HANDLE ProcessHandle,
|
||||
OUT PCONTEXT ThreadContext,
|
||||
IN PVOID ThreadStartParam OPTIONAL,
|
||||
IN PTHREAD_START_ROUTINE ThreadStartAddress,
|
||||
IN PINITIAL_TEB InitialTeb)
|
||||
VOID
|
||||
STDCALL
|
||||
RtlFreeUserThreadStack(HANDLE ProcessHandle,
|
||||
HANDLE ThreadHandle)
|
||||
{
|
||||
RtlRosInitializeContext
|
||||
(
|
||||
ProcessHandle,
|
||||
ThreadContext,
|
||||
ThreadStartAddress,
|
||||
InitialTeb,
|
||||
1,
|
||||
(ULONG_PTR *)&ThreadStartParam
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
@implemented
|
||||
*/
|
||||
NTSTATUS STDCALL RtlFreeUserThreadStack
|
||||
(
|
||||
HANDLE ProcessHandle,
|
||||
HANDLE ThreadHandle
|
||||
)
|
||||
{
|
||||
return RtlRosFreeUserThreadStack(ProcessHandle, ThreadHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
@implemented
|
||||
*/
|
||||
VOID STDCALL RtlExitUserThread(NTSTATUS Status)
|
||||
{
|
||||
RtlRosExitUserThread(Status);
|
||||
NTSTATUS Status;
|
||||
THREAD_BASIC_INFORMATION ThreadBasicInfo;
|
||||
ULONG Dummy, Size = 0;
|
||||
PVOID StackLocation;
|
||||
|
||||
/* Query the Basic Info */
|
||||
Status = NtQueryInformationThread(ThreadHandle,
|
||||
ThreadBasicInformation,
|
||||
&ThreadBasicInfo,
|
||||
sizeof(THREAD_BASIC_INFORMATION),
|
||||
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 */
|
||||
|
|
|
@ -483,7 +483,10 @@ l_ReadHeaderFromFile:
|
|||
ASSERT(PEFMT_FIELDS_EQUAL(IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, 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));
|
||||
|
||||
|
|
Loading…
Reference in a new issue