[FORMATTING]
[reactos.git] / reactos / 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\n");
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\n");
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 = 0;
79 DPRINT("RtlpInitEnvironment (hProcess: %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;
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 ZwWriteVirtualMemory(ProcessHandle,
152 BaseAddress,
153 ProcessParameters,
154 ProcessParameters->Length,
155 NULL);
156
157 /* Write pointer to Parameter Block */
158 ZwWriteVirtualMemory(ProcessHandle,
159 &Peb->ProcessParameters,
160 &BaseAddress,
161 sizeof(BaseAddress),
162 NULL);
163
164 /* Return */
165 return STATUS_SUCCESS;
166 }
167
168 /*
169 * @implemented
170 *
171 * Creates a process and its initial thread.
172 *
173 * NOTES:
174 * - The first thread is created suspended, so it needs a manual resume!!!
175 * - If ParentProcess is NULL, current process is used
176 * - ProcessParameters must be normalized
177 * - Attributes are object attribute flags used when opening the ImageFileName.
178 * Valid flags are OBJ_INHERIT and OBJ_CASE_INSENSITIVE.
179 *
180 * -Gunnar
181 */
182 NTSTATUS
183 NTAPI
184 RtlCreateUserProcess(IN PUNICODE_STRING ImageFileName,
185 IN ULONG Attributes,
186 IN OUT PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
187 IN PSECURITY_DESCRIPTOR ProcessSecurityDescriptor OPTIONAL,
188 IN PSECURITY_DESCRIPTOR ThreadSecurityDescriptor OPTIONAL,
189 IN HANDLE ParentProcess OPTIONAL,
190 IN BOOLEAN InheritHandles,
191 IN HANDLE DebugPort OPTIONAL,
192 IN HANDLE ExceptionPort OPTIONAL,
193 OUT PRTL_USER_PROCESS_INFORMATION ProcessInfo)
194 {
195 NTSTATUS Status;
196 HANDLE hSection;
197 PROCESS_BASIC_INFORMATION ProcessBasicInfo;
198 OBJECT_ATTRIBUTES ObjectAttributes;
199 UNICODE_STRING DebugString = RTL_CONSTANT_STRING(L"\\WindowsSS");
200 DPRINT("RtlCreateUserProcess: %wZ\n", ImageFileName);
201
202 /* Map and Load the File */
203 Status = RtlpMapFile(ImageFileName,
204 Attributes,
205 &hSection);
206 if(!NT_SUCCESS(Status))
207 {
208 DPRINT1("Could not map process image\n");
209 return Status;
210 }
211
212 /* Clean out the CurDir Handle if we won't use it */
213 if (!InheritHandles) ProcessParameters->CurrentDirectory.Handle = NULL;
214
215 /* Use us as parent if none other specified */
216 if (!ParentProcess) ParentProcess = NtCurrentProcess();
217
218 /* Initialize the Object Attributes */
219 InitializeObjectAttributes(&ObjectAttributes,
220 NULL,
221 0,
222 NULL,
223 ProcessSecurityDescriptor);
224
225 /*
226 * If FLG_ENABLE_CSRDEBUG is used, then CSRSS is created under the
227 * watch of WindowsSS
228 */
229 if ((RtlGetNtGlobalFlags() & FLG_ENABLE_CSRDEBUG) &&
230 (wcsstr(ImageFileName->Buffer, L"csrss")))
231 {
232 ObjectAttributes.ObjectName = &DebugString;
233 }
234
235 /* Create Kernel Process Object */
236 Status = ZwCreateProcess(&ProcessInfo->ProcessHandle,
237 PROCESS_ALL_ACCESS,
238 &ObjectAttributes,
239 ParentProcess,
240 InheritHandles,
241 hSection,
242 DebugPort,
243 ExceptionPort);
244 if (!NT_SUCCESS(Status))
245 {
246 DPRINT1("Could not create Kernel Process Object\n");
247 ZwClose(hSection);
248 return Status;
249 }
250
251 /* Get some information on the image */
252 Status = ZwQuerySection(hSection,
253 SectionImageInformation,
254 &ProcessInfo->ImageInformation,
255 sizeof(SECTION_IMAGE_INFORMATION),
256 NULL);
257 if (!NT_SUCCESS(Status))
258 {
259 DPRINT1("Could not query Section Info\n");
260 ZwClose(ProcessInfo->ProcessHandle);
261 ZwClose(hSection);
262 return Status;
263 }
264
265 /* Get some information about the process */
266 ZwQueryInformationProcess(ProcessInfo->ProcessHandle,
267 ProcessBasicInformation,
268 &ProcessBasicInfo,
269 sizeof(ProcessBasicInfo),
270 NULL);
271 if (!NT_SUCCESS(Status))
272 {
273 DPRINT1("Could not query Process Info\n");
274 ZwClose(ProcessInfo->ProcessHandle);
275 ZwClose(hSection);
276 return Status;
277 }
278
279 /* Create Process Environment */
280 RtlpInitEnvironment(ProcessInfo->ProcessHandle,
281 ProcessBasicInfo.PebBaseAddress,
282 ProcessParameters);
283
284 /* Create the first Thread */
285 Status = RtlCreateUserThread(ProcessInfo->ProcessHandle,
286 ThreadSecurityDescriptor,
287 TRUE,
288 ProcessInfo->ImageInformation.ZeroBits,
289 ProcessInfo->ImageInformation.MaximumStackSize,
290 ProcessInfo->ImageInformation.CommittedStackSize,
291 ProcessInfo->ImageInformation.TransferAddress,
292 ProcessBasicInfo.PebBaseAddress,
293 &ProcessInfo->ThreadHandle,
294 &ProcessInfo->ClientId);
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1("Could not Create Thread\n");
298 ZwClose(ProcessInfo->ProcessHandle);
299 ZwClose(hSection); /* Don't try to optimize this on top! */
300 return Status;
301 }
302
303 /* Close the Section Handle and return */
304 ZwClose(hSection);
305 return STATUS_SUCCESS;
306 }
307
308 /*
309 * @implemented
310 */
311 PVOID
312 NTAPI
313 RtlEncodePointer(IN PVOID Pointer)
314 {
315 ULONG Cookie;
316 NTSTATUS Status;
317
318 Status = ZwQueryInformationProcess(NtCurrentProcess(),
319 ProcessCookie,
320 &Cookie,
321 sizeof(Cookie),
322 NULL);
323 if(!NT_SUCCESS(Status))
324 {
325 DPRINT1("Failed to receive the process cookie! Status: 0x%lx\n", Status);
326 return Pointer;
327 }
328
329 return (PVOID)((ULONG_PTR)Pointer ^ Cookie);
330 }
331
332 /*
333 * @implemented
334 */
335 PVOID
336 NTAPI
337 RtlDecodePointer(IN PVOID Pointer)
338 {
339 return RtlEncodePointer(Pointer);
340 }
341
342 /*
343 * @unimplemented
344 */
345 PVOID
346 NTAPI
347 RtlEncodeSystemPointer(IN PVOID Pointer)
348 {
349 UNIMPLEMENTED;
350 return NULL;
351 }
352
353 /*
354 * @implemented
355 *
356 * NOTES:
357 * Implementation based on the documentation from:
358 * http://www.geoffchappell.com/studies/windows/win32/ntdll/api/rtl/peb/setprocessiscritical.htm
359 */
360 NTSTATUS
361 NTAPI
362 RtlSetProcessIsCritical(IN BOOLEAN NewValue,
363 OUT PBOOLEAN OldValue OPTIONAL,
364 IN BOOLEAN NeedBreaks)
365 {
366 ULONG BreakOnTermination = FALSE;
367
368 if (OldValue)
369 *OldValue = FALSE;
370
371 /* Fail, if the critical breaks flag is required but is not set */
372 if (NeedBreaks == TRUE &&
373 !(NtCurrentPeb()->NtGlobalFlag & FLG_ENABLE_SYSTEM_CRIT_BREAKS))
374 return STATUS_UNSUCCESSFUL;
375
376 if (OldValue)
377 {
378 /* Query and return the old break on termination flag for the process */
379 ZwQueryInformationProcess(NtCurrentProcess(),
380 ProcessBreakOnTermination,
381 &BreakOnTermination,
382 sizeof(ULONG),
383 NULL);
384 *OldValue = (BOOLEAN)BreakOnTermination;
385 }
386
387 /* Set the break on termination flag for the process */
388 BreakOnTermination = NewValue;
389 return ZwSetInformationProcess(NtCurrentProcess(),
390 ProcessBreakOnTermination,
391 &BreakOnTermination,
392 sizeof(ULONG));
393 }
394
395 ULONG
396 NTAPI
397 RtlGetCurrentProcessorNumber(VOID)
398 {
399 /* Forward to kernel */
400 return NtGetCurrentProcessorNumber();
401 }