:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / ntdll / rtl / process.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS system libraries
5  * FILE:            lib/ntdll/rtl/process.c
6  * PURPOSE:         Process functions
7  * PROGRAMMER:      Ariadne ( ariadne@xs4all.nl)
8  * UPDATE HISTORY:
9  *                  Created 01/11/98
10  */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <napi/i386/segment.h>
16 #include <ntdll/ldr.h>
17 #include <ntdll/base.h>
18 #include <ntdll/rtl.h>
19
20 #define NDEBUG
21 #include <ntdll/ntdll.h>
22
23 /* FUNCTIONS ****************************************************************/
24
25 static NTSTATUS
26 RtlpCreateFirstThread(HANDLE ProcessHandle,
27                       ULONG StackReserve,
28                       ULONG StackCommit,
29                       LPTHREAD_START_ROUTINE lpStartAddress,
30                       PCLIENT_ID ClientId,
31                       PHANDLE ThreadHandle)
32 {
33   NTSTATUS Status;
34   OBJECT_ATTRIBUTES ObjectAttributes;
35   CONTEXT ThreadContext;
36   INITIAL_TEB InitialTeb;
37   ULONG OldPageProtection;
38   CLIENT_ID Cid;
39   ULONG InitialStack[5];
40   ULONG ResultLength;
41   
42   ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
43   ObjectAttributes.RootDirectory = NULL;
44   ObjectAttributes.ObjectName = NULL;
45   ObjectAttributes.Attributes = 0;
46   ObjectAttributes.SecurityQualityOfService = NULL;
47
48   if (StackReserve > 0x100000)
49     InitialTeb.StackReserve = StackReserve;
50   else
51     InitialTeb.StackReserve = 0x100000; /* 1MByte */
52
53   /* FIXME */
54 #if 0
55   if (StackCommit > PAGE_SIZE)
56     InitialTeb.StackCommit = StackCommit;
57   else
58     InitialTeb.StackCommit = PAGE_SIZE;
59 #endif
60   InitialTeb.StackCommit = InitialTeb.StackReserve - PAGE_SIZE;
61
62   /* add guard page size */
63   InitialTeb.StackCommit += PAGE_SIZE;
64
65   /* Reserve stack */
66   InitialTeb.StackAllocate = NULL;
67   Status = NtAllocateVirtualMemory(ProcessHandle,
68                                    &InitialTeb.StackAllocate,
69                                    0,
70                                    &InitialTeb.StackReserve,
71                                    MEM_RESERVE,
72                                    PAGE_READWRITE);
73   if (!NT_SUCCESS(Status))
74     {
75       DPRINT("Error reserving stack space!\n");
76       return(Status);
77     }
78
79   DPRINT("StackAllocate: %p ReserveSize: 0x%lX\n",
80          InitialTeb.StackAllocate, InitialTeb.StackReserve);
81
82   InitialTeb.StackBase = (PVOID)((ULONG)InitialTeb.StackAllocate + InitialTeb.StackReserve);
83   InitialTeb.StackLimit = (PVOID)((ULONG)InitialTeb.StackBase - InitialTeb.StackCommit);
84
85   DPRINT("StackBase: %p StackCommit: 0x%lX\n",
86          InitialTeb.StackBase, InitialTeb.StackCommit);
87
88   /* Commit stack */
89   Status = NtAllocateVirtualMemory(ProcessHandle,
90                                    &InitialTeb.StackLimit,
91                                    0,
92                                    &InitialTeb.StackCommit,
93                                    MEM_COMMIT,
94                                    PAGE_READWRITE);
95   if (!NT_SUCCESS(Status))
96     {
97       /* release the stack space */
98       NtFreeVirtualMemory(ProcessHandle,
99                           InitialTeb.StackAllocate,
100                           &InitialTeb.StackReserve,
101                           MEM_RELEASE);
102
103       DPRINT("Error comitting stack page(s)!\n");
104       return(Status);
105     }
106
107   DPRINT("StackLimit: %p\n", InitialTeb.StackLimit);
108
109   /* Protect guard page */
110   Status = NtProtectVirtualMemory(ProcessHandle,
111                                   InitialTeb.StackLimit,
112                                   PAGE_SIZE,
113                                   PAGE_GUARD | PAGE_READWRITE,
114                                   &OldPageProtection);
115   if (!NT_SUCCESS(Status))
116     {
117       /* release the stack space */
118       NtFreeVirtualMemory(ProcessHandle,
119                           InitialTeb.StackAllocate,
120                           &InitialTeb.StackReserve,
121                           MEM_RELEASE);
122
123       DPRINT("Error comitting guard page!\n");
124       return(Status);
125     }
126
127   memset(&ThreadContext,0,sizeof(CONTEXT));
128   ThreadContext.Eip = (ULONG)lpStartAddress;
129   ThreadContext.SegGs = USER_DS;
130   ThreadContext.SegFs = TEB_SELECTOR;
131   ThreadContext.SegEs = USER_DS;
132   ThreadContext.SegDs = USER_DS;
133   ThreadContext.SegCs = USER_CS;
134   ThreadContext.SegSs = USER_DS;
135   ThreadContext.Esp = (ULONG)InitialTeb.StackBase - 20;
136   ThreadContext.EFlags = (1<<1) + (1<<9);
137
138   DPRINT("ThreadContext.Eip %x\n",ThreadContext.Eip);
139
140   /*
141    * Write in the initial stack.
142    */
143   InitialStack[0] = 0;
144   InitialStack[1] = PEB_BASE;
145   Status = ZwWriteVirtualMemory(ProcessHandle,
146                                 (PVOID)ThreadContext.Esp,
147                                 InitialStack,
148                                 sizeof(InitialStack),
149                                 &ResultLength);
150   if (!NT_SUCCESS(Status))
151     {
152       DPRINT1("Failed to write initial stack.\n");
153       return(Status);
154     }
155
156   Status = NtCreateThread(ThreadHandle,
157                           THREAD_ALL_ACCESS,
158                           &ObjectAttributes,
159                           ProcessHandle,
160                           &Cid,
161                           &ThreadContext,
162                           &InitialTeb,
163                           FALSE);
164   if (!NT_SUCCESS(Status))
165     {
166       NtFreeVirtualMemory(ProcessHandle,
167                           InitialTeb.StackAllocate,
168                           &InitialTeb.StackReserve,
169                           MEM_RELEASE);
170       return(Status);
171     }
172
173   if (ClientId != NULL)
174     {
175       memcpy(&ClientId->UniqueThread, &Cid.UniqueThread, sizeof(ULONG));
176     }
177
178   return(STATUS_SUCCESS);
179 }
180
181 static NTSTATUS
182 RtlpMapFile(PRTL_USER_PROCESS_PARAMETERS Ppb,
183             ULONG Attributes,
184             PHANDLE Section,
185             PCHAR ImageFileName)
186 {
187    HANDLE hFile;
188    IO_STATUS_BLOCK IoStatusBlock;
189    OBJECT_ATTRIBUTES ObjectAttributes;
190    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
191    NTSTATUS Status;
192    PWCHAR s;
193    PWCHAR e;
194    ULONG i;
195    
196    hFile = NULL;
197
198    RtlDeNormalizeProcessParams (Ppb);
199
200 //   DbgPrint("ImagePathName %x\n", Ppb->ImagePathName.Buffer);
201    
202    InitializeObjectAttributes(&ObjectAttributes,
203                               &(Ppb->ImagePathName),
204                               Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
205                               NULL,
206                               SecurityDescriptor);
207
208    RtlNormalizeProcessParams (Ppb);
209    
210    /*
211     * 
212     */
213 //   DbgPrint("ImagePathName %x\n", Ppb->ImagePathName.Buffer);
214 //   DbgPrint("ImagePathName %S\n", Ppb->ImagePathName.Buffer);
215    s = wcsrchr(Ppb->ImagePathName.Buffer, '\\');
216    if (s == NULL)
217      {
218         s = Ppb->ImagePathName.Buffer;
219      }
220    else
221      {
222         s++;
223      }
224    e = wcschr(s, '.');
225    if (e != NULL)
226      {
227         *e = 0;
228      }
229    for (i = 0; i < 8; i++)
230      {
231         ImageFileName[i] = (CHAR)(s[i]);
232      }
233    if (e != NULL)
234      {
235         *e = '.';
236      }
237    
238    /*
239     * Try to open the executable
240     */
241
242    Status = NtOpenFile(&hFile,
243                         SYNCHRONIZE|FILE_EXECUTE|FILE_READ_DATA,
244                         &ObjectAttributes,
245                         &IoStatusBlock,
246                         FILE_SHARE_DELETE|FILE_SHARE_READ,
247                         FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
248
249    if (!NT_SUCCESS(Status))
250      {
251         return(Status);
252      }
253
254    Status = NtCreateSection(Section,
255                             SECTION_ALL_ACCESS,
256                             NULL,
257                             NULL,
258                             PAGE_EXECUTE,
259                             SEC_IMAGE,
260                             hFile);
261    NtClose(hFile);
262
263    if (!NT_SUCCESS(Status))
264      {
265         return(Status);
266      }
267
268    return(STATUS_SUCCESS);
269 }
270
271 static NTSTATUS KlInitPeb (HANDLE ProcessHandle,
272                            PRTL_USER_PROCESS_PARAMETERS Ppb,
273                            PVOID* ImageBaseAddress)
274 {
275    NTSTATUS Status;
276    PVOID PpbBase;
277    ULONG PpbSize;
278    ULONG BytesWritten;
279    ULONG Offset;
280    PVOID EnvPtr = NULL;
281    ULONG EnvSize = 0;
282
283    /* create the Environment */
284    if (Ppb->Environment != NULL)
285      {
286         MEMORY_BASIC_INFORMATION MemInfo;
287
288         Status = NtQueryVirtualMemory (NtCurrentProcess (),
289                                        Ppb->Environment,
290                                        MemoryBasicInformation,
291                                        &MemInfo,
292                                        sizeof(MEMORY_BASIC_INFORMATION),
293                                        NULL);
294         if (!NT_SUCCESS(Status))
295           {
296              return Status;
297           }
298         EnvSize = MemInfo.RegionSize;
299      }
300    DPRINT("EnvironmentSize %ld\n", EnvSize);
301
302    /* allocate and initialize new environment block */
303    if (EnvSize != 0)
304      {
305         Status = NtAllocateVirtualMemory(ProcessHandle,
306                                          &EnvPtr,
307                                          0,
308                                          &EnvSize,
309                                          MEM_RESERVE | MEM_COMMIT,
310                                          PAGE_READWRITE);
311         if (!NT_SUCCESS(Status))
312           {
313              return(Status);
314           }
315
316         NtWriteVirtualMemory(ProcessHandle,
317                              EnvPtr,
318                              Ppb->Environment,
319                              EnvSize,
320                              &BytesWritten);
321      }
322    DPRINT("EnvironmentPointer %p\n", EnvPtr);
323
324    /* create the PPB */
325    PpbBase = NULL;
326    PpbSize = Ppb->AllocationSize;\r
327    Status = NtAllocateVirtualMemory(ProcessHandle,
328                                     &PpbBase,
329                                     0,
330                                     &PpbSize,
331                                     MEM_RESERVE | MEM_COMMIT,
332                                     PAGE_READWRITE);
333    if (!NT_SUCCESS(Status))
334      {
335         return(Status);
336      }
337
338    DPRINT("Ppb->MaximumLength %x\n", Ppb->MaximumLength);
339
340    /* write process parameters block*/
341    RtlDeNormalizeProcessParams (Ppb);
342    NtWriteVirtualMemory(ProcessHandle,
343                         PpbBase,
344                         Ppb,
345                         Ppb->AllocationSize,\r
346                         &BytesWritten);
347    RtlNormalizeProcessParams (Ppb);
348
349    /* write pointer to environment */
350    Offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment);
351    NtWriteVirtualMemory(ProcessHandle,
352                         (PVOID)(PpbBase + Offset),
353                         &EnvPtr,
354                         sizeof(EnvPtr),
355                         &BytesWritten);
356
357    /* write pointer to process parameter block */
358    Offset = FIELD_OFFSET(PEB, ProcessParameters);
359    NtWriteVirtualMemory(ProcessHandle,
360                         (PVOID)(PEB_BASE + Offset),
361                         &PpbBase,
362                         sizeof(PpbBase),
363                         &BytesWritten);
364
365    /* Read image base address. */
366    Offset = FIELD_OFFSET(PEB, ImageBaseAddress);
367    NtReadVirtualMemory(ProcessHandle,
368                        (PVOID)(PEB_BASE + Offset),
369                        ImageBaseAddress,
370                        sizeof(PVOID),
371                        &BytesWritten);
372
373    return(STATUS_SUCCESS);
374 }
375
376
377 NTSTATUS STDCALL
378 RtlCreateUserProcess(PUNICODE_STRING ImageFileName,
379                      ULONG Attributes,
380                      PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
381                      PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
382                      PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
383                      HANDLE ParentProcess,
384                      BOOLEAN CurrentDirectory,
385                      HANDLE DebugPort,
386                      HANDLE ExceptionPort,
387                      PRTL_PROCESS_INFO ProcessInfo)
388 {
389    HANDLE hSection;
390    NTSTATUS Status;
391    LPTHREAD_START_ROUTINE lpStartAddress = NULL;
392    PROCESS_BASIC_INFORMATION ProcessBasicInfo;
393    ULONG retlen;
394    CHAR FileName[8];
395    ANSI_STRING ProcedureName;
396    SECTION_IMAGE_INFORMATION Sii;
397    ULONG ResultLength;
398    PVOID ImageBaseAddress;
399    
400    DPRINT("RtlCreateUserProcess\n");
401    
402    Status = RtlpMapFile(ProcessParameters,
403                         Attributes,
404                         &hSection,
405                         FileName);
406    if( !NT_SUCCESS( Status ) )
407      return Status;
408
409    /*
410     * Create a new process
411     */
412    if (ParentProcess == NULL)
413      ParentProcess = NtCurrentProcess();
414
415    Status = NtCreateProcess(&(ProcessInfo->ProcessHandle),
416                             PROCESS_ALL_ACCESS,
417                             NULL,
418                             ParentProcess,
419                             CurrentDirectory,
420                             hSection,
421                             DebugPort,
422                             ExceptionPort);
423    if (!NT_SUCCESS(Status))
424      {
425         NtClose(hSection);
426         return(Status);
427      }
428    
429    /*
430     * Get some information about the process
431     */
432    NtQueryInformationProcess(ProcessInfo->ProcessHandle,
433                              ProcessBasicInformation,
434                              &ProcessBasicInfo,
435                              sizeof(ProcessBasicInfo),
436                              &retlen);
437    DPRINT("ProcessBasicInfo.UniqueProcessId %d\n",
438           ProcessBasicInfo.UniqueProcessId);
439    ProcessInfo->ClientId.UniqueProcess = (HANDLE)ProcessBasicInfo.UniqueProcessId;
440                           
441    Status = NtSetInformationProcess(ProcessInfo->ProcessHandle,
442                                     ProcessImageFileName,
443                                     FileName,
444                                     8);
445
446    /*
447     * Create Process Environment Block
448     */
449    DPRINT("Creating peb\n");
450    KlInitPeb(ProcessInfo->ProcessHandle,
451              ProcessParameters,
452              &ImageBaseAddress);
453
454    Status = NtQuerySection(hSection,
455                            SectionImageInformation,
456                            &Sii,
457                            sizeof(Sii),
458                            &ResultLength);
459    if (!NT_SUCCESS(Status) || ResultLength != sizeof(Sii))
460      {
461        DPRINT("Failed to get section image information.\n");
462        NtClose(hSection);
463        return(Status);
464      }
465
466    DPRINT("Creating thread for process\n");
467    Status = RtlpCreateFirstThread(ProcessInfo->ProcessHandle,
468                                   Sii.StackReserve,
469                                   Sii.StackCommit,
470                                   ImageBaseAddress + (ULONG)Sii.EntryPoint,
471                                   &ProcessInfo->ClientId,
472                                   &ProcessInfo->ThreadHandle);
473    if (!NT_SUCCESS(Status))
474    {
475         DPRINT("Failed to create thread\n");
476         NtClose(hSection);
477         return(Status);
478    }
479    NtClose(hSection);
480    return(STATUS_SUCCESS);
481 }
482
483 /* EOF */