c636285b6667191f550553643f7741bec35f0371
[reactos.git] / reactos / sdk / lib / rtl / process.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/rtl/process.c
5 * PURPOSE: Process functions
6 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
7 * Ariadne (ariadne@xs4all.nl)
8 * Eric Kohl
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <rtl.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* INTERNAL FUNCTIONS *******************************************************/
19
20 NTSTATUS
21 NTAPI
22 RtlpMapFile(PUNICODE_STRING ImageFileName,
23 ULONG Attributes,
24 PHANDLE Section)
25 {
26 OBJECT_ATTRIBUTES ObjectAttributes;
27 NTSTATUS Status;
28 HANDLE hFile = NULL;
29 IO_STATUS_BLOCK IoStatusBlock;
30
31 /* Open the Image File */
32 InitializeObjectAttributes(&ObjectAttributes,
33 ImageFileName,
34 Attributes & (OBJ_CASE_INSENSITIVE | OBJ_INHERIT),
35 NULL,
36 NULL);
37 Status = ZwOpenFile(&hFile,
38 SYNCHRONIZE | FILE_EXECUTE | FILE_READ_DATA,
39 &ObjectAttributes,
40 &IoStatusBlock,
41 FILE_SHARE_DELETE | FILE_SHARE_READ,
42 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
43 if (!NT_SUCCESS(Status))
44 {
45 DPRINT1("Failed to read image file from disk, Status = 0x%08X\n", Status);
46 return Status;
47 }
48
49 /* Now create a section for this image */
50 Status = ZwCreateSection(Section,
51 SECTION_ALL_ACCESS,
52 NULL,
53 NULL,
54 PAGE_EXECUTE,
55 SEC_IMAGE,
56 hFile);
57 if (!NT_SUCCESS(Status))
58 {
59 DPRINT1("Failed to create section for image file, Status = 0x%08X\n", Status);
60 }
61
62 ZwClose(hFile);
63 return Status;
64 }
65
66 /* FUNCTIONS ****************************************************************/
67
68 NTSTATUS
69 NTAPI
70 RtlpInitEnvironment(HANDLE ProcessHandle,
71 PPEB Peb,
72 PRTL_USER_PROCESS_PARAMETERS ProcessParameters)
73 {
74 NTSTATUS Status;
75 PVOID BaseAddress = NULL;
76 SIZE_T EnviroSize;
77 SIZE_T Size;
78 PWCHAR Environment = NULL;
79 DPRINT("RtlpInitEnvironment(ProcessHandle: %p, Peb: %p Params: %p)\n",
80 ProcessHandle, Peb, ProcessParameters);
81
82 /* Give the caller 1MB if he requested it */
83 if (ProcessParameters->Flags & RTL_USER_PROCESS_PARAMETERS_RESERVE_1MB)
84 {
85 /* Give 1MB starting at 0x4 */
86 BaseAddress = (PVOID)4;
87 EnviroSize = (1024 * 1024) - 256;
88 Status = ZwAllocateVirtualMemory(ProcessHandle,
89 &BaseAddress,
90 0,
91 &EnviroSize,
92 MEM_RESERVE,
93 PAGE_READWRITE);
94 if (!NT_SUCCESS(Status))
95 {
96 DPRINT1("Failed to reserve 1MB of space \n");
97 return Status;
98 }
99 }
100
101 /* Find the end of the Enviroment Block */
102 if ((Environment = (PWCHAR)ProcessParameters->Environment))
103 {
104 while (*Environment++) while (*Environment++);
105
106 /* Calculate the size of the block */
107 EnviroSize = (ULONG)((ULONG_PTR)Environment -
108 (ULONG_PTR)ProcessParameters->Environment);
109
110 /* Allocate and Initialize new Environment Block */
111 Size = EnviroSize;
112 Status = ZwAllocateVirtualMemory(ProcessHandle,
113 &BaseAddress,
114 0,
115 &Size,
116 MEM_RESERVE | MEM_COMMIT,
117 PAGE_READWRITE);
118 if (!NT_SUCCESS(Status))
119 {
120 DPRINT1("Failed to allocate Environment Block\n");
121 return Status;
122 }
123
124 /* Write the Environment Block */
125 ZwWriteVirtualMemory(ProcessHandle,
126 BaseAddress,
127 ProcessParameters->Environment,
128 EnviroSize,
129 NULL);
130
131 /* Save pointer */
132 ProcessParameters->Environment = BaseAddress;
133 }
134
135 /* Now allocate space for the Parameter Block */
136 BaseAddress = NULL;
137 Size = ProcessParameters->MaximumLength;
138 Status = ZwAllocateVirtualMemory(ProcessHandle,
139 &BaseAddress,
140 0,
141 &Size,
142 MEM_COMMIT,
143 PAGE_READWRITE);
144 if (!NT_SUCCESS(Status))
145 {
146 DPRINT1("Failed to allocate Parameter Block\n");
147 return Status;
148 }
149
150 /* Write the Parameter Block */
151 Status = ZwWriteVirtualMemory(ProcessHandle,
152 BaseAddress,
153 ProcessParameters,
154 ProcessParameters->Length,
155 NULL);
156 if (!NT_SUCCESS(Status))
157 {
158 DPRINT1("Failed to write the Parameter Block\n");
159 return Status;
160 }
161
162 /* Write pointer to Parameter Block */
163 Status = ZwWriteVirtualMemory(ProcessHandle,
164 &Peb->ProcessParameters,
165 &BaseAddress,
166 sizeof(BaseAddress),
167 NULL);
168 if (!NT_SUCCESS(Status))
169 {
170 DPRINT1("Failed to write pointer to Parameter Block\n");
171 return Status;
172 }
173
174 /* Return */
175 return STATUS_SUCCESS;
176 }
177
178 /*
179 * @implemented
180 *
181 * Creates a process and its initial thread.
182 *
183 * NOTES:
184 * - The first thread is created suspended, so it needs a manual resume!!!
185 * - If ParentProcess is NULL, current process is used
186 * - ProcessParameters must be normalized
187 * - Attributes are object attribute flags used when opening the ImageFileName.
188 * Valid flags are OBJ_INHERIT and OBJ_CASE_INSENSITIVE.
189 *
190 * -Gunnar
191 */
192 NTSTATUS
193 NTAPI
194 RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
195 IN ULONG Attributes,
196 IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
197 IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
198 IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
199 IN HANDLE ParentProcess OPTIONAL,
200 IN BOOLEAN InheritHandles,
201 IN HANDLE DebugPort OPTIONAL,
202 IN HANDLE ExceptionPort OPTIONAL,
203 OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
204 {
205 NTSTATUS Status;
206 HANDLE hSection;
207 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
208 OBJECT_ATTRIBUTES ObjectAttributes;
209 UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
210 DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
211
212 /* Map and Load the File */
213 Status = RtlpMapFile(ImageFileName,
214 Attributes,
215 &hSection);
216 if (!NT_SUCCESS(Status))
217 {
218 DPRINT1("Could not map process image\n");
219 return Status;
220 }
221
222 /* Clean out the current directory handle if we won't use it */
223 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
224
225 /* Use us as parent if none other specified */
226 if (!ParentProcess) ParentProcess = NtCurrentProcess();
227
228 /* Initialize the Object Attributes */
229 InitializeObjectAttributes(&ObjectAttributes,
230 NULL,
231 0,
232 NULL,
233 ProcessSecurityDescriptor);
234
235 /*
236 * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
237 * watch of WindowsSS
238 */
239 if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) &&
240 (wcsstr(ImageFileName->Buffer, L"csrss")))
241 {
242 ObjectAttributes.ObjectName = &DebugString;
243 }
244
245 /* Create Kernel Process Object */
246 Status = ZwCreateProcess(&ProcessInfo->ProcessHandle,
247 PROCESS_ALL_ACCESS,
248 &ObjectAttributes,
249 ParentProcess,
250 InheritHandles,
251 hSection,
252 DebugPort,
253 ExceptionPort);
254 if (!NT_SUCCESS(Status))
255 {
256 DPRINT1("Could not create Kernel Process Object\n");
257 ZwClose(hSection);
258 return Status;
259 }
260
261 /* Get some information on the image */
262 Status = ZwQuerySection(hSection,
263 SectionImageInformation,
264 &ProcessInfo->ImageInformation,
265 sizeof(SECTION_IMAGE_INFORMATION),
266 NULL);
267 if (!NT_SUCCESS(Status))
268 {
269 DPRINT1("Could not query Section Info\n");
270 ZwClose(ProcessInfo->ProcessHandle);
271 ZwClose(hSection);
272 return Status;
273 }
274
275 /* Get some information about the process */
276 Status = ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
277 ProcessBasicInformation,
278 &ProcessBasicInfo,
279 sizeof(ProcessBasicInfo),
280 NULL);
281 if (!NT_SUCCESS(Status))
282 {
283 DPRINT1("Could not query Process Info\n");
284 ZwClose(ProcessInfo->ProcessHandle);
285 ZwClose(hSection);
286 return Status;
287 }
288
289 /* Duplicate the standard handles */
290 Status = STATUS_SUCCESS;
291 _SEH2_TRY
292 {
293 if (ProcessParameters->StandardInput)
294 {
295 Status = ZwDuplicateObject(ParentProcess,
296 ProcessParameters->StandardInput,
297 ProcessInfo->ProcessHandle,
298 &ProcessParameters->StandardInput,
299 0,
300 0,
301 DUPLICATE_SAME_ACCESS |
302 DUPLICATE_SAME_ATTRIBUTES);
303 if (!NT_SUCCESS(Status))
304 {
305 _SEH2_LEAVE;
306 }
307 }
308
309 if (ProcessParameters->StandardOutput)
310 {
311 Status = ZwDuplicateObject(ParentProcess,
312 ProcessParameters->StandardOutput,
313 ProcessInfo->ProcessHandle,
314 &ProcessParameters->StandardOutput,
315 0,
316 0,
317 DUPLICATE_SAME_ACCESS |
318 DUPLICATE_SAME_ATTRIBUTES);
319 if (!NT_SUCCESS(Status))
320 {
321 _SEH2_LEAVE;
322 }
323 }
324
325 if (ProcessParameters->StandardError)
326 {
327 Status = ZwDuplicateObject(ParentProcess,
328 ProcessParameters->StandardError,
329 ProcessInfo->ProcessHandle,
330 &ProcessParameters->StandardError,
331 0,
332 0,
333 DUPLICATE_SAME_ACCESS |
334 DUPLICATE_SAME_ATTRIBUTES);
335 if (!NT_SUCCESS(Status))
336 {
337 _SEH2_LEAVE;
338 }
339 }
340 }
341 _SEH2_FINALLY
342 {
343 if (!NT_SUCCESS(Status))
344 {
345 ZwClose(ProcessInfo->ProcessHandle);
346 ZwClose(hSection);
347 }
348 }
349 _SEH2_END;
350
351 if (!NT_SUCCESS(Status))
352 return Status;
353
354 /* Create Process Environment */
355 Status = RtlpInitEnvironment(ProcessInfo->ProcessHandle,
356 ProcessBasicInfo.PebBaseAddress,
357 ProcessParameters);
358 if (!NT_SUCCESS(Status))
359 {
360 DPRINT1("Could not Create Process Environment\n");
361 ZwClose(ProcessInfo->ProcessHandle);
362 ZwClose(hSection);
363 return Status;
364 }
365
366 /* Create the first Thread */
367 Status = RtlCreateUserThread(ProcessInfo->ProcessHandle,
368 ThreadSecurityDescriptor,
369 TRUE,
370 ProcessInfo->ImageInformation.ZeroBits,
371 ProcessInfo->ImageInformation.MaximumStackSize,
372 ProcessInfo->ImageInformation.CommittedStackSize,
373 ProcessInfo->ImageInformation.TransferAddress,
374 ProcessBasicInfo.PebBaseAddress,
375 &ProcessInfo->ThreadHandle,
376 &ProcessInfo->ClientId);
377 if (!NT_SUCCESS(Status))
378 {
379 DPRINT1("Could not Create Thread\n");
380 ZwClose(ProcessInfo->ProcessHandle);
381 ZwClose(hSection); /* Don't try to optimize this on top! */
382 return Status;
383 }
384
385 /* Close the Section Handle and return */
386 ZwClose(hSection);
387 return STATUS_SUCCESS;
388 }
389
390 /*
391 * @implemented
392 */
393 PVOID
394 NTAPI
395 RtlEncodePointer(IN PVOID Pointer)
396 {
397 ULONG Cookie;
398 NTSTATUS Status;
399
400 Status = ZwQueryInformationProcess(NtCurrentProcess(),
401 ProcessCookie,
402 &Cookie,
403 sizeof(Cookie),
404 NULL);
405 if(!NT_SUCCESS(Status))
406 {
407 DPRINT1("Failed to receive the process cookie! Status: 0x%lx\n", Status);
408 return Pointer;
409 }
410
411 return (PVOID)((ULONG_PTR)Pointer ^ Cookie);
412 }
413
414 /*
415 * @implemented
416 */
417 PVOID
418 NTAPI
419 RtlDecodePointer(IN PVOID Pointer)
420 {
421 return RtlEncodePointer(Pointer);
422 }
423
424 /*
425 * @implemented
426 */
427 PVOID
428 NTAPI
429 RtlEncodeSystemPointer(IN PVOID Pointer)
430 {
431 return (PVOID)((ULONG_PTR)Pointer ^ SharedUserData->Cookie);
432 }
433
434 /*
435 * @implemented
436 *
437 * NOTES:
438 * Implementation based on the documentation from:
439 * http://www.geoffchappell.com/studies/windows/win32/ntdll/api/rtl/peb/setprocessiscritical.htm
440 */
441 NTSTATUS
442 __cdecl
443 RtlSetProcessIsCritical(IN BOOLEAN NewValue,
444 OUT PBOOLEAN OldValue OPTIONAL,
445 IN BOOLEAN NeedBreaks)
446 {
447 ULONG BreakOnTermination;
448
449 /* Initialize to FALSE */
450 if (OldValue) *OldValue = FALSE;
451
452 /* Fail, if the critical breaks flag is required but is not set */
453 if ((NeedBreaks) &&
454 !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS))
455 {
456 return STATUS_UNSUCCESSFUL;
457 }
458
459 /* Check if the caller wants the old value */
460 if (OldValue)
461 {
462 /* Query and return the old break on termination flag for the process */
463 ZwQueryInformationProcess(NtCurrentProcess(),
464 ProcessBreakOnTermination,
465 &BreakOnTermination,
466 sizeof(ULONG),
467 NULL);
468 *OldValue = (BOOLEAN)BreakOnTermination;
469 }
470
471 /* Set the break on termination flag for the process */
472 BreakOnTermination = NewValue;
473 return ZwSetInformationProcess(NtCurrentProcess(),
474 ProcessBreakOnTermination,
475 &BreakOnTermination,
476 sizeof(ULONG));
477 }
478
479 ULONG
480 NTAPI
481 RtlGetCurrentProcessorNumber(VOID)
482 {
483 /* Forward to kernel */
484 return NtGetCurrentProcessorNumber();
485 }