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