xref: /reactos/sdk/lib/rtl/process.c (revision 3f976713)
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 PVOID
438 NTAPI
439 RtlDecodeSystemPointer(IN PVOID Pointer)
440 {
441     return RtlEncodeSystemPointer(Pointer);
442 }
443 
444 /*
445  * @implemented
446  *
447  * NOTES:
448  *   Implementation based on the documentation from:
449  *   http://www.geoffchappell.com/studies/windows/win32/ntdll/api/rtl/peb/setprocessiscritical.htm
450  */
451 NTSTATUS
452 __cdecl
453 RtlSetProcessIsCritical(IN BOOLEAN NewValue,
454                         OUT PBOOLEAN OldValue OPTIONAL,
455                         IN BOOLEAN NeedBreaks)
456 {
457     ULONG BreakOnTermination;
458 
459     /* Initialize to FALSE */
460     if (OldValue) *OldValue = FALSE;
461 
462     /* Fail, if the critical breaks flag is required but is not set */
463     if ((NeedBreaks) &&
464         !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS))
465     {
466         return STATUS_UNSUCCESSFUL;
467     }
468 
469     /* Check if the caller wants the old value */
470     if (OldValue)
471     {
472         /* Query and return the old break on termination flag for the process */
473         ZwQueryInformationProcess(NtCurrentProcess(),
474                                   ProcessBreakOnTermination,
475                                   &BreakOnTermination,
476                                   sizeof(ULONG),
477                                   NULL);
478         *OldValue = (BOOLEAN)BreakOnTermination;
479     }
480 
481     /* Set the break on termination flag for the process */
482     BreakOnTermination = NewValue;
483     return ZwSetInformationProcess(NtCurrentProcess(),
484                                    ProcessBreakOnTermination,
485                                    &BreakOnTermination,
486                                    sizeof(ULONG));
487 }
488 
489 ULONG
490 NTAPI
491 RtlGetCurrentProcessorNumber(VOID)
492 {
493     /* Forward to kernel */
494     return NtGetCurrentProcessorNumber();
495 }
496 
497 _IRQL_requires_max_(APC_LEVEL)
498 ULONG
499 NTAPI
500 RtlRosGetAppcompatVersion(VOID)
501 {
502     /* Get the current PEB */
503     PPEB Peb = RtlGetCurrentPeb();
504     if (Peb == NULL)
505     {
506         /* Default to Server 2003 */
507         return _WIN32_WINNT_WS03;
508     }
509 
510     /* Calculate OS version from PEB fields */
511     return (Peb->OSMajorVersion << 8) | Peb->OSMinorVersion;
512 }
513