wcscpy(): Fixed crash on ElectricFence
[reactos.git] / ntoskrnl / ldr / init.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/ldr/init.c
22  * PURPOSE:         Loaders for PE executables
23  * PROGRAMMERS:     Jean Michault
24  *                  Rex Jolliff (rex@lvcablemodem.com)
25  * UPDATE HISTORY:
26  *   DW   22/05/98  Created
27  *   RJJ  10/12/98  Completed image loader function and added hooks for MZ/PE
28  *   RJJ  10/12/98  Built driver loader function and added hooks for PE/COFF
29  *   RJJ  10/12/98  Rolled in David's code to load COFF drivers
30  *   JM   14/12/98  Built initial PE user module loader
31  *   RJJ  06/03/99  Moved user PE loader into NTDLL
32  *   EA   19990717  LdrGetSystemDirectory()
33  *   EK   20000618  Using SystemRoot link instead of LdrGetSystemDirectory()
34  *   HYP  20020911  Code to determine smss's path from the registry
35  */
36
37 /* INCLUDES *****************************************************************/
38
39 #include <ddk/ntddk.h>
40 #include <internal/i386/segment.h>
41 #include <internal/module.h>
42 #include <internal/ntoskrnl.h>
43 #include <internal/ob.h>
44 #include <internal/ps.h>
45 #include <internal/ldr.h>
46 #include <napi/teb.h>
47
48 #define NDEBUG
49 #include <internal/debug.h>
50
51 /* FUNCTIONS *****************************************************************/
52
53 /*
54  * TODO: Read the location of the initial process from command line before
55  * trying the registry - embedded setups, like the installation CD-ROM, may not
56  * have a SYSTEM hive
57  */
58 NTSTATUS LdrLoadInitialProcess (VOID)
59 {
60    NTSTATUS Status;
61    HANDLE ProcessHandle;
62    UNICODE_STRING ProcessName = {0, 0, NULL};
63    OBJECT_ATTRIBUTES ObjectAttributes;
64    HANDLE FileHandle;
65    HANDLE SectionHandle;
66    PIMAGE_NT_HEADERS NTHeaders;
67    PEPROCESS Process;
68    CONTEXT Context;
69    HANDLE ThreadHandle;
70    INITIAL_TEB InitialTeb;
71    ULONG OldPageProtection;
72    SECTION_IMAGE_INFORMATION Sii;
73    ULONG ResultLength;
74    PVOID ImageBaseAddress;
75    ULONG InitialStack[5];
76 #if 0
77    /* FIXME: Test this please */
78    HANDLE RootDir;
79    PWSTR Environment = L"SystemRoot=\\SystemRoot\0";
80    RTL_QUERY_REGISTRY_TABLE RegistryValues[] = {
81       {
82          NULL,
83          RTL_QUERY_REGISTRY_DIRECT,
84          L"Path",
85          &ProcessName,
86          REG_SZ,
87          L"\\SystemRoot\\system32\\smss.exe"
88          sizeof(L"\\SystemRoot\\system32\\smss.exe") - sizeof(WCHAR)
89       },
90       { NULL, 0, NULL, NULL, 0, NULL, 0 }
91    };
92
93    /* try to query the SMSS path from the registry */
94    Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
95                                    L"Session Manager",
96                                    RegistryValues,
97                                    NULL,
98                                    Environment);
99    
100    /* failure or invalid data: use default */
101    if(!NT_SUCCESS(Status) || ProcessName.Length < sizeof(WCHAR))
102       RtlInitUnicodeStringFromLiteral(&ProcessName,
103                                       L"\\SystemRoot\\system32\\smss.exe");
104    /* relative path: open \SystemRoot\system32 */
105    else if(ProcessName.Buffer[0] != L'\\')
106    {
107       UNICODE_STRING DirPath;
108     
109       RtlInitUnicodeStringFromLiteral(&DirPath, L"\\SystemRoot\\system32");
110
111       InitializeObjectAttributes(&ObjectAttributes,
112                                  &DirPath,
113                                  0,
114                                  NULL,
115                                  NULL);
116
117       if(!NT_SUCCESS(ZwOpenFile(&RootDir, 0, &ObjectAttributes, NULL, 0, 0)))
118          /* failure: use default */
119          RtlInitUnicodeStringFromLiteral(&ProcessName,
120                                          L"\\SystemRoot\\system32\\smss.exe");
121    }
122
123    InitializeObjectAttributes(&ObjectAttributes,
124                               &ProcessName,
125                               0,
126                               RootDir,
127                               NULL);
128 #else
129    /*
130     * Get the absolute path to smss.exe using the
131     * SystemRoot link.
132     */
133    RtlInitUnicodeStringFromLiteral(&ProcessName,
134                         L"\\SystemRoot\\system32\\smss.exe");
135    /*
136     * Open process image to determine ImageBase
137     * and StackBase/Size.
138     */
139    InitializeObjectAttributes(&ObjectAttributes,
140                               &ProcessName,
141                               0,
142                               NULL,
143                               NULL);
144 #endif
145    DPRINT("Opening image file %S\n", ObjectAttributes.ObjectName->Buffer);
146    Status = ZwOpenFile(&FileHandle,
147                        FILE_ALL_ACCESS,
148                        &ObjectAttributes,
149                        NULL,
150                        0,
151                        0);
152 #if 0
153    /* FIXME? ExFreePool() should ignore non-pool data */
154    RtlFreeUnicodeString(&ProcessName);
155    NtClose(RootDir);
156 #endif
157    if (!NT_SUCCESS(Status))
158      {
159         DPRINT("Image open failed (Status was %x)\n", Status);
160         return Status;
161      }
162    
163    /*
164     * Create a section for the image
165     */
166    DPRINT("Creating section\n");
167    Status = ZwCreateSection(&SectionHandle,
168                             SECTION_ALL_ACCESS,
169                             NULL,
170                             NULL,
171                             PAGE_READWRITE,
172                             SEC_COMMIT | SEC_IMAGE,
173                             FileHandle);
174    if (!NT_SUCCESS(Status))
175      {
176         DPRINT("ZwCreateSection failed (Status %x)\n", Status);
177         ZwClose(FileHandle);
178         return(Status);
179      }
180    ZwClose(FileHandle);
181
182    /*
183     * Get information about the process image.
184     */
185    Status = ZwQuerySection(SectionHandle,
186                            SectionImageInformation,
187                            &Sii,
188                            sizeof(Sii),
189                            &ResultLength);
190    if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
191      {
192        DPRINT("ZwQuerySection failed (Status %X)\n", Status);
193        ZwClose(SectionHandle);
194        return(Status);
195      }
196    
197    DPRINT("Creating process\n");
198    Status = ZwCreateProcess(&ProcessHandle,
199                             PROCESS_ALL_ACCESS,
200                             NULL,
201                             SystemProcessHandle,
202                             FALSE,
203                             SectionHandle,
204                             NULL,
205                             NULL);
206    if (!NT_SUCCESS(Status))
207      {
208         DPRINT("Could not create process\n");
209         return Status;
210      }
211
212    /*
213     * Create initial stack and thread
214     */
215    
216    /*
217     * Create page backed section for stack
218     */
219    DPRINT("Allocating stack\n");
220    
221    DPRINT("Referencing process\n");
222    Status = ObReferenceObjectByHandle(ProcessHandle,
223                                       PROCESS_ALL_ACCESS,
224                                       PsProcessType,
225                                       KernelMode,
226                                       (PVOID*)&Process,
227                                       NULL);
228    if (!NT_SUCCESS(Status))
229      {
230         DPRINT("ObReferenceObjectByProcess() failed (Status %x)\n", Status);
231         return(Status);
232      }
233    
234    DPRINT("Attaching to process\n");
235    KeAttachProcess(Process);
236    ImageBaseAddress = Process->Peb->ImageBaseAddress;
237    NTHeaders = RtlImageNtHeader(ImageBaseAddress);
238    DPRINT("NTHeaders %x\n", NTHeaders);
239    InitialTeb.StackReserve = NTHeaders->OptionalHeader.SizeOfStackReserve;
240    /* FIXME: use correct commit size */
241    InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackReserve - PAGE_SIZE;
242    //   InitialTeb.StackCommit = NTHeaders->OptionalHeader.SizeOfStackCommit;
243    /* add guard page size */
244    InitialTeb.StackCommit += PAGE_SIZE;
245    DPRINT("StackReserve 0x%lX  StackCommit 0x%lX\n",
246           InitialTeb.StackReserve, InitialTeb.StackCommit);
247    KeDetachProcess();
248    DPRINT("Dereferencing process\n");
249    ObDereferenceObject(Process);
250    
251    DPRINT("Allocating stack\n");
252    InitialTeb.StackAllocate = NULL;
253    Status = NtAllocateVirtualMemory(ProcessHandle,
254                                     &InitialTeb.StackAllocate,
255                                     0,
256                                     &InitialTeb.StackReserve,
257                                     MEM_RESERVE,
258                                     PAGE_READWRITE);
259    if (!NT_SUCCESS(Status))
260      {
261        DPRINT("Stack allocation failed (Status %x)", Status);
262        return(Status);
263      }
264    
265    DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
266           InitialTeb.StackAllocate, InitialTeb.StackReserve);
267    
268    InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
269    InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
270    
271    DPRINT("StackBase: %p  StackCommit: 0x%lX\n",
272           InitialTeb.StackBase, InitialTeb.StackCommit);
273    
274    /* Commit stack */
275    Status = NtAllocateVirtualMemory(ProcessHandle,
276                                     &InitialTeb.StackLimit,
277                                     0,
278                                     &InitialTeb.StackCommit,
279                                     MEM_COMMIT,
280                                     PAGE_READWRITE);
281    if (!NT_SUCCESS(Status))
282      {
283        /* release the stack space */
284        NtFreeVirtualMemory(ProcessHandle,
285                            InitialTeb.StackAllocate,
286                            &InitialTeb.StackReserve,
287                            MEM_RELEASE);
288        
289        DPRINT("Error comitting stack page!\n");
290        return(Status);
291      }
292    
293    DPRINT("StackLimit: %p\nStackCommit: 0x%lX\n",
294           InitialTeb.StackLimit,
295           InitialTeb.StackCommit);
296    
297    /* Protect guard page */
298    Status = NtProtectVirtualMemory(ProcessHandle,
299                                    InitialTeb.StackLimit,
300                                    PAGE_SIZE,
301                                    PAGE_GUARD | PAGE_READWRITE,
302                                    &OldPageProtection);
303    if (!NT_SUCCESS(Status))
304      {
305        /* release the stack space */
306        NtFreeVirtualMemory(ProcessHandle,
307                            InitialTeb.StackAllocate,
308                            &InitialTeb.StackReserve,
309                            MEM_RELEASE);
310
311        DPRINT("Error protecting guard page!\n");
312        return(Status);
313      }
314    
315    /*
316     * Initialize context to point to LdrStartup
317     */
318    memset(&Context,0,sizeof(CONTEXT));
319    Context.Eip = (ULONG)(ImageBaseAddress + (ULONG)Sii.EntryPoint);
320    Context.SegCs = USER_CS;
321    Context.SegDs = USER_DS;
322    Context.SegEs = USER_DS;
323    Context.SegFs = TEB_SELECTOR;
324    Context.SegGs = USER_DS;
325    Context.SegSs = USER_DS;
326    Context.EFlags = 0x202;
327    Context.Esp = (ULONG)InitialTeb.StackBase - 20;
328
329    /*
330     * Write in the initial stack.
331     */
332    InitialStack[0] = 0;
333    InitialStack[1] = PEB_BASE;
334    Status = ZwWriteVirtualMemory(ProcessHandle,
335                                  (PVOID)Context.Esp,
336                                  InitialStack,
337                                  sizeof(InitialStack),
338                                  &ResultLength);
339    if (!NT_SUCCESS(Status))
340      {
341        DPRINT1("Failed to write initial stack.\n");
342        return(Status);
343      }
344    
345    /*
346     * FIXME: Create process and let 'er rip
347     */
348    DPRINT("Creating thread for initial process\n");
349    Status = ZwCreateThread(&ThreadHandle,
350                            THREAD_ALL_ACCESS,
351                            NULL,
352                            ProcessHandle,
353                            NULL,
354                            &Context,
355                            &InitialTeb,
356                            FALSE);
357   if (!NT_SUCCESS(Status))
358     {
359       DPRINT("Thread creation failed (Status %x)\n", Status);
360       
361       NtFreeVirtualMemory(ProcessHandle,
362                           InitialTeb.StackAllocate,
363                           &InitialTeb.StackReserve,
364                           MEM_RELEASE);
365
366       /* FIXME: unmap the section here  */
367       /* FIXME: destroy the section here  */
368       /* FIXME: Kill the process here */
369
370       return(Status);
371     }
372   
373   return(STATUS_SUCCESS);
374 }
375
376 /* EOF */