Reworked initial process loader.

Crash the system if the initial process fails within 5 seconds.

svn path=/trunk/; revision=3748
This commit is contained in:
Eric Kohl 2002-11-12 19:12:34 +00:00
parent 2f04a917bb
commit eb1c9c77ee
3 changed files with 364 additions and 304 deletions

View file

@ -21,11 +21,10 @@
extern ULONG_PTR LdrHalBase; extern ULONG_PTR LdrHalBase;
NTSTATUS NTSTATUS
LdrLoadInitialProcess ( LdrLoadInitialProcess(PHANDLE ProcessHandle,
VOID PHANDLE ThreadHandle);
);
VOID VOID
LdrLoadAutoConfigDrivers ( LdrLoadAutoConfigDrivers (
VOID VOID

View file

@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
/* $Id: main.c,v 1.139 2002/09/17 23:48:14 dwelch Exp $ /* $Id: main.c,v 1.140 2002/11/12 19:12:13 ekohl Exp $
* *
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/main.c * FILE: ntoskrnl/ke/main.c
@ -282,9 +282,13 @@ InitSystemSharedUserPage (PCSZ ParameterLine)
} }
} }
VOID VOID
ExpInitializeExecutive(VOID) ExpInitializeExecutive(VOID)
{ {
LARGE_INTEGER Timeout;
HANDLE ProcessHandle;
HANDLE ThreadHandle;
ULONG BootDriverCount; ULONG BootDriverCount;
ULONG i; ULONG i;
ULONG start; ULONG start;
@ -575,7 +579,27 @@ ExpInitializeExecutive(VOID)
/* /*
* Launch initial process * Launch initial process
*/ */
LdrLoadInitialProcess(); Status = LdrLoadInitialProcess(&ProcessHandle,
&ThreadHandle);
if (!NT_SUCCESS(Status))
{
KeBugCheckEx(SESSION4_INITIALIZATION_FAILED, Status, 0, 0, 0);
}
/*
* Crash the system if the initial process terminates within 5 seconds.
*/
Timeout.QuadPart = 50000000;
Status = NtWaitForSingleObject(ProcessHandle,
FALSE,
&Timeout);
if (Status != STATUS_TIMEOUT)
{
KeBugCheckEx(SESSION5_INITIALIZATION_FAILED, Status, 0, 0, 0);
}
NtClose(ThreadHandle);
NtClose(ProcessHandle);
PsTerminateSystemThread(STATUS_SUCCESS); PsTerminateSystemThread(STATUS_SUCCESS);
} }

View file

@ -45,331 +45,368 @@
#include <internal/ldr.h> #include <internal/ldr.h>
#include <napi/teb.h> #include <napi/teb.h>
#define NDEBUG //#define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
/*
* TODO: Read the location of the initial process from command line before static NTSTATUS
* trying the registry - embedded setups, like the installation CD-ROM, may not LdrpMapProcessImage(PHANDLE SectionHandle,
* have a SYSTEM hive PUNICODE_STRING ImagePath)
*/
NTSTATUS LdrLoadInitialProcess (VOID)
{ {
NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE ProcessHandle; HANDLE FileHandle;
UNICODE_STRING ProcessName = {0, 0, NULL}; NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandle; /* Open image file */
HANDLE SectionHandle; InitializeObjectAttributes(&ObjectAttributes,
PIMAGE_NT_HEADERS NTHeaders; ImagePath,
PEPROCESS Process; 0,
CONTEXT Context; NULL,
HANDLE ThreadHandle; NULL);
INITIAL_TEB InitialTeb;
ULONG OldPageProtection; DPRINT("Opening image file %S\n", ObjectAttributes.ObjectName->Buffer);
SECTION_IMAGE_INFORMATION Sii; Status = NtOpenFile(&FileHandle,
ULONG ResultLength; FILE_ALL_ACCESS,
PVOID ImageBaseAddress; &ObjectAttributes,
ULONG InitialStack[5]; NULL,
0,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
return(Status);
}
/* Create a section for the image */
DPRINT("Creating section\n");
Status = NtCreateSection(SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_READWRITE,
SEC_COMMIT | SEC_IMAGE,
FileHandle);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateSection() failed (Status %lx)\n", Status);
}
return(Status);
}
static NTSTATUS
LdrpCreateProcessEnvironment(HANDLE ProcessHandle,
PUNICODE_STRING ImagePath,
PVOID* ImageBaseAddress)
{
NTSTATUS Status;
ULONG BytesWritten;
ULONG Offset;
#if 0 #if 0
/* FIXME: Test this please */ PVOID PpbBase;
HANDLE RootDir; ULONG PpbSize;
PWSTR Environment = L"SystemRoot=\\SystemRoot\0";
RTL_QUERY_REGISTRY_TABLE RegistryValues[] = {
{
NULL,
RTL_QUERY_REGISTRY_DIRECT,
L"Path",
&ProcessName,
REG_SZ,
L"\\SystemRoot\\system32\\smss.exe"
sizeof(L"\\SystemRoot\\system32\\smss.exe") - sizeof(WCHAR)
},
{ NULL, 0, NULL, NULL, 0, NULL, 0 }
};
/* try to query the SMSS path from the registry */ /* create the PPB */
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, PpbBase = NULL;
L"Session Manager", PpbSize = Ppb->AllocationSize;
RegistryValues, Status = NtAllocateVirtualMemory(ProcessHandle,
NULL, &PpbBase,
Environment); 0,
&PpbSize,
/* failure or invalid data: use default */ MEM_RESERVE | MEM_COMMIT,
if(!NT_SUCCESS(Status) || ProcessName.Length < sizeof(WCHAR)) PAGE_READWRITE);
RtlInitUnicodeStringFromLiteral(&ProcessName, if (!NT_SUCCESS(Status))
L"\\SystemRoot\\system32\\smss.exe"); {
/* relative path: open \SystemRoot\system32 */ return(Status);
else if(ProcessName.Buffer[0] != L'\\') }
{
UNICODE_STRING DirPath;
RtlInitUnicodeStringFromLiteral(&DirPath, L"\\SystemRoot\\system32");
InitializeObjectAttributes(&ObjectAttributes, DPRINT("Ppb->AllocationSize %x\n", Ppb->AllocationSize);
&DirPath, DPRINT("Ppb->Size %x\n", Ppb->Size);
0,
NULL,
NULL);
if(!NT_SUCCESS(ZwOpenFile(&RootDir, 0, &ObjectAttributes, NULL, 0, 0))) /* write process parameters block*/
/* failure: use default */ NtWriteVirtualMemory(ProcessHandle,
RtlInitUnicodeStringFromLiteral(&ProcessName, PpbBase,
L"\\SystemRoot\\system32\\smss.exe"); Ppb,
} Ppb->AllocationSize,
&BytesWritten);
InitializeObjectAttributes(&ObjectAttributes, /* write pointer to process parameter block */
&ProcessName, Offset = FIELD_OFFSET(PEB, ProcessParameters);
0, NtWriteVirtualMemory(ProcessHandle,
RootDir, (PVOID)(PEB_BASE + Offset),
NULL); &PpbBase,
#else sizeof(PpbBase),
/* &BytesWritten);
* Get the absolute path to smss.exe using the
* SystemRoot link.
*/
RtlInitUnicodeStringFromLiteral(&ProcessName,
L"\\SystemRoot\\system32\\smss.exe");
/*
* Open process image to determine ImageBase
* and StackBase/Size.
*/
InitializeObjectAttributes(&ObjectAttributes,
&ProcessName,
0,
NULL,
NULL);
#endif #endif
DPRINT("Opening image file %S\n", ObjectAttributes.ObjectName->Buffer);
Status = ZwOpenFile(&FileHandle,
FILE_ALL_ACCESS,
&ObjectAttributes,
NULL,
0,
0);
#if 0
/* FIXME? ExFreePool() should ignore non-pool data */
RtlFreeUnicodeString(&ProcessName);
NtClose(RootDir);
#endif
if (!NT_SUCCESS(Status))
{
DPRINT("Image open failed (Status was %x)\n", Status);
return Status;
}
/*
* Create a section for the image
*/
DPRINT("Creating section\n");
Status = ZwCreateSection(&SectionHandle,
SECTION_ALL_ACCESS,
NULL,
NULL,
PAGE_READWRITE,
SEC_COMMIT | SEC_IMAGE,
FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT("ZwCreateSection failed (Status %x)\n", Status);
ZwClose(FileHandle);
return(Status);
}
ZwClose(FileHandle);
/* /* Set image file name */
* Get information about the process image. Status = NtSetInformationProcess(ProcessHandle,
*/ ProcessImageFileName,
Status = ZwQuerySection(SectionHandle, "SMSS",
5);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetInformationProcess() failed (Status %lx)\n", Status);
return(Status);
}
/* Read image base address. */
Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
NtReadVirtualMemory(ProcessHandle,
(PVOID)(PEB_BASE + Offset),
ImageBaseAddress,
sizeof(PVOID),
&BytesWritten);
return(STATUS_SUCCESS);
}
static NTSTATUS
LdrpCreateStack(HANDLE ProcessHandle,
PINITIAL_TEB InitialTeb)
{
ULONG OldPageProtection;
NTSTATUS Status;
InitialTeb->StackAllocate = NULL;
/* Allocate the reserved stack space */
Status = NtAllocateVirtualMemory(ProcessHandle,
&InitialTeb->StackAllocate,
0,
&InitialTeb->StackReserve,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Stack allocation failed (Status %x)", Status);
return(Status);
}
DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
InitialTeb->StackAllocate, InitialTeb->StackReserve);
InitialTeb->StackBase = (PVOID)((ULONG)InitialTeb->StackAllocate + InitialTeb->StackReserve);
InitialTeb->StackLimit = (PVOID)((ULONG)InitialTeb->StackBase - InitialTeb->StackCommit);
DPRINT("StackBase: %p StackCommit: 0x%lX\n",
InitialTeb->StackBase, InitialTeb->StackCommit);
/* Commit stack */
Status = NtAllocateVirtualMemory(ProcessHandle,
&InitialTeb->StackLimit,
0,
&InitialTeb->StackCommit,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error comitting stack page!\n");
/* release the stack space */
NtFreeVirtualMemory(ProcessHandle,
InitialTeb->StackAllocate,
&InitialTeb->StackReserve,
MEM_RELEASE);
return(Status);
}
DPRINT1("StackLimit: %p\nStackCommit: 0x%lX\n",
InitialTeb->StackLimit,
InitialTeb->StackCommit);
/* Protect guard page */
Status = NtProtectVirtualMemory(ProcessHandle,
InitialTeb->StackLimit,
PAGE_SIZE,
PAGE_GUARD | PAGE_READWRITE,
&OldPageProtection);
if (!NT_SUCCESS(Status))
{
DPRINT1("Error protecting guard page!\n");
/* release the stack space */
NtFreeVirtualMemory(ProcessHandle,
InitialTeb->StackAllocate,
&InitialTeb->StackReserve,
MEM_RELEASE);
return(Status);
}
return(STATUS_SUCCESS);
}
NTSTATUS
LdrLoadInitialProcess(PHANDLE ProcessHandle,
PHANDLE ThreadHandle)
{
SECTION_IMAGE_INFORMATION Sii;
UNICODE_STRING ImagePath;
HANDLE SectionHandle;
CONTEXT Context;
INITIAL_TEB InitialTeb;
ULONG ResultLength;
PVOID ImageBaseAddress;
ULONG InitialStack[5];
NTSTATUS Status;
/* Get the absolute path to smss.exe. */
RtlInitUnicodeStringFromLiteral(&ImagePath,
L"\\SystemRoot\\system32\\smss.exe");
/* Map process image */
Status = LdrpMapProcessImage(&SectionHandle,
&ImagePath);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrpMapImage() failed (Status %lx)\n", Status);
return(Status);
}
/* Get information about the process image. */
Status = NtQuerySection(SectionHandle,
SectionImageInformation, SectionImageInformation,
&Sii, &Sii,
sizeof(Sii), sizeof(Sii),
&ResultLength); &ResultLength);
if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii)) if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
{ {
DPRINT("ZwQuerySection failed (Status %X)\n", Status); DPRINT1("ZwQuerySection failed (Status %X)\n", Status);
ZwClose(SectionHandle); NtClose(ProcessHandle);
return(Status); NtClose(SectionHandle);
} return(Status);
}
DPRINT("Creating process\n");
Status = ZwCreateProcess(&ProcessHandle,
PROCESS_ALL_ACCESS,
NULL,
SystemProcessHandle,
FALSE,
SectionHandle,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("Could not create process\n");
return Status;
}
/* DPRINT("Creating process\n");
* Create initial stack and thread Status = NtCreateProcess(ProcessHandle,
*/ PROCESS_ALL_ACCESS,
/*
* Create page backed section for stack
*/
DPRINT("Allocating stack\n");
DPRINT("Referencing process\n");
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_ALL_ACCESS,
PsProcessType,
KernelMode,
(PVOID*)&Process,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("ObReferenceObjectByProcess() failed (Status %x)\n", Status);
return(Status);
}
DPRINT("Attaching to process\n");
KeAttachProcess(Process);
ImageBaseAddress = Process->Peb->ImageBaseAddress;
NTHeaders = RtlImageNtHeader(ImageBaseAddress);
DPRINT("NTHeaders %x\n", NTHeaders);
InitialTeb.StackReserve = NTHeaders->OptionalHeader.SizeOfStackReserve;
/* FIXME: use correct commit size */
InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackReserve - PAGE_SIZE;
// InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackCommit;
/* add guard page size */
InitialTeb.StackCommit += PAGE_SIZE;
DPRINT("StackReserve 0x%lX StackCommit 0x%lX\n",
InitialTeb.StackReserve, InitialTeb.StackCommit);
KeDetachProcess();
DPRINT("Dereferencing process\n");
ObDereferenceObject(Process);
DPRINT("Allocating stack\n");
InitialTeb.StackAllocate = NULL;
Status = NtAllocateVirtualMemory(ProcessHandle,
&InitialTeb.StackAllocate,
0,
&InitialTeb.StackReserve,
MEM_RESERVE,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
DPRINT("Stack allocation failed (Status %x)", Status);
return(Status);
}
DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
InitialTeb.StackAllocate, InitialTeb.StackReserve);
InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
DPRINT("StackBase: %p StackCommit: 0x%lX\n",
InitialTeb.StackBase, InitialTeb.StackCommit);
/* Commit stack */
Status = NtAllocateVirtualMemory(ProcessHandle,
&InitialTeb.StackLimit,
0,
&InitialTeb.StackCommit,
MEM_COMMIT,
PAGE_READWRITE);
if (!NT_SUCCESS(Status))
{
/* release the stack space */
NtFreeVirtualMemory(ProcessHandle,
InitialTeb.StackAllocate,
&InitialTeb.StackReserve,
MEM_RELEASE);
DPRINT("Error comitting stack page!\n");
return(Status);
}
DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
InitialTeb.StackLimit,
InitialTeb.StackCommit);
/* Protect guard page */
Status = NtProtectVirtualMemory(ProcessHandle,
InitialTeb.StackLimit,
PAGE_SIZE,
PAGE_GUARD | PAGE_READWRITE,
&OldPageProtection);
if (!NT_SUCCESS(Status))
{
/* release the stack space */
NtFreeVirtualMemory(ProcessHandle,
InitialTeb.StackAllocate,
&InitialTeb.StackReserve,
MEM_RELEASE);
DPRINT("Error protecting guard page!\n");
return(Status);
}
/*
* Initialize context to point to LdrStartup
*/
memset(&Context,0,sizeof(CONTEXT));
Context.Eip = (ULONG)(ImageBaseAddress + (ULONG)Sii.EntryPoint);
Context.SegCs = USER_CS;
Context.SegDs = USER_DS;
Context.SegEs = USER_DS;
Context.SegFs = TEB_SELECTOR;
Context.SegGs = USER_DS;
Context.SegSs = USER_DS;
Context.EFlags = 0x202;
Context.Esp = (ULONG)InitialTeb.StackBase - 20;
/*
* Write in the initial stack.
*/
InitialStack[0] = 0;
InitialStack[1] = PEB_BASE;
Status = ZwWriteVirtualMemory(ProcessHandle,
(PVOID)Context.Esp,
InitialStack,
sizeof(InitialStack),
&ResultLength);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to write initial stack.\n");
return(Status);
}
/*
* FIXME: Create process and let 'er rip
*/
DPRINT("Creating thread for initial process\n");
Status = ZwCreateThread(&ThreadHandle,
THREAD_ALL_ACCESS,
NULL, NULL,
ProcessHandle, SystemProcessHandle,
FALSE,
SectionHandle,
NULL, NULL,
&Context, NULL);
&InitialTeb, NtClose(SectionHandle);
FALSE);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT("Thread creation failed (Status %x)\n", Status); DPRINT1("NtCreateProcess() failed (Status %lx)\n", Status);
return(Status);
NtFreeVirtualMemory(ProcessHandle, }
/* Create process environment */
DPRINT("Creating the process environment\n");
Status = LdrpCreateProcessEnvironment(*ProcessHandle,
&ImagePath,
&ImageBaseAddress);
if (!NT_SUCCESS(Status))
{
DPRINT1("LdrpCreateProcessEnvironment() failed (Status %lx)\n", Status);
NtClose(*ProcessHandle);
return(Status);
}
DPRINT("ImageBaseAddress: %p\n", ImageBaseAddress);
/* Calculate initial stack sizes */
if (Sii.StackReserve > 0x100000)
InitialTeb.StackReserve = Sii.StackReserve;
else
InitialTeb.StackReserve = 0x100000; /* 1MByte */
/* FIXME */
#if 0
if (Sii.StackCommit > PAGE_SIZE)
InitialTeb.StackCommit = Sii.StackCommit;
else
InitialTeb.StackCommit = PAGE_SIZE;
#endif
InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
/* add guard page size */
InitialTeb.StackCommit += PAGE_SIZE;
DPRINT("StackReserve 0x%lX StackCommit 0x%lX\n",
InitialTeb.StackReserve, InitialTeb.StackCommit);
/* Create the process stack */
Status = LdrpCreateStack(*ProcessHandle,
&InitialTeb);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to write initial stack.\n");
NtClose(ProcessHandle);
return(Status);
}
/*
* Initialize context to point to LdrStartup
*/
memset(&Context,0,sizeof(CONTEXT));
Context.Eip = (ULONG)(ImageBaseAddress + (ULONG)Sii.EntryPoint);
Context.SegCs = USER_CS;
Context.SegDs = USER_DS;
Context.SegEs = USER_DS;
Context.SegFs = TEB_SELECTOR;
Context.SegGs = USER_DS;
Context.SegSs = USER_DS;
Context.EFlags = 0x202;
Context.Esp = (ULONG)InitialTeb.StackBase - 20;
/*
* Write in the initial stack.
*/
InitialStack[0] = 0;
InitialStack[1] = PEB_BASE;
Status = NtWriteVirtualMemory(*ProcessHandle,
(PVOID)Context.Esp,
InitialStack,
sizeof(InitialStack),
&ResultLength);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to write initial stack.\n");
NtFreeVirtualMemory(*ProcessHandle,
InitialTeb.StackAllocate,
&InitialTeb.StackReserve,
MEM_RELEASE);
NtClose(*ProcessHandle);
return(Status);
}
/* Create initial thread */
DPRINT1("Creating thread for initial process\n");
Status = NtCreateThread(ThreadHandle,
THREAD_ALL_ACCESS,
NULL,
*ProcessHandle,
NULL,
&Context,
&InitialTeb,
FALSE);
if (!NT_SUCCESS(Status))
{
DPRINT("NtCreateThread() failed (Status %lx)\n", Status);
NtFreeVirtualMemory(*ProcessHandle,
InitialTeb.StackAllocate, InitialTeb.StackAllocate,
&InitialTeb.StackReserve, &InitialTeb.StackReserve,
MEM_RELEASE); MEM_RELEASE);
/* FIXME: unmap the section here */ NtClose(*ProcessHandle);
/* FIXME: destroy the section here */
/* FIXME: Kill the process here */
return(Status); return(Status);
} }
DPRINT("Process created successfully\n");
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }