Reverted latest changes.
[reactos.git] / reactos / lib / ntdll / rtl / process.c
1 /* $Id: process.c,v 1.30 2002/09/08 10:23:06 chorns Exp $
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 > PAGESIZE)
56 InitialTeb.StackCommit = StackCommit;
57 else
58 InitialTeb.StackCommit = PAGESIZE;
59 #endif
60 InitialTeb.StackCommit = InitialTeb.StackReserve - PAGESIZE;
61
62 /* add guard page size */
63 InitialTeb.StackCommit += PAGESIZE;
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 PAGESIZE,
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->MaximumLength;
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->MaximumLength,
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 */