1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ps/query.c 5 * PURPOSE: Process Manager: Thread/Process Query/Set Information 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Thomas Weidenmueller (w3seek@reactos.org) 8 * Eric Kohl 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 /* Debugging Level */ 18 ULONG PspTraceLevel = 0; 19 20 /* PRIVATE FUNCTIONS *********************************************************/ 21 22 NTSTATUS 23 NTAPI 24 PsReferenceProcessFilePointer(IN PEPROCESS Process, 25 OUT PFILE_OBJECT *FileObject) 26 { 27 PSECTION Section; 28 PAGED_CODE(); 29 30 /* Lock the process */ 31 if (!ExAcquireRundownProtection(&Process->RundownProtect)) 32 { 33 return STATUS_PROCESS_IS_TERMINATING; 34 } 35 36 /* Get the section */ 37 Section = Process->SectionObject; 38 if (Section) 39 { 40 /* Get the file object and reference it */ 41 *FileObject = MmGetFileObjectForSection((PVOID)Section); 42 ObReferenceObject(*FileObject); 43 } 44 45 /* Release the protection */ 46 ExReleaseRundownProtection(&Process->RundownProtect); 47 48 /* Return status */ 49 return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 50 } 51 52 /* PUBLIC FUNCTIONS **********************************************************/ 53 54 /* 55 * @implemented 56 */ 57 NTSTATUS 58 NTAPI 59 NtQueryInformationProcess(IN HANDLE ProcessHandle, 60 IN PROCESSINFOCLASS ProcessInformationClass, 61 OUT PVOID ProcessInformation, 62 IN ULONG ProcessInformationLength, 63 OUT PULONG ReturnLength OPTIONAL) 64 { 65 PEPROCESS Process; 66 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 67 NTSTATUS Status; 68 ULONG Length = 0; 69 HANDLE DebugPort = 0; 70 PPROCESS_BASIC_INFORMATION ProcessBasicInfo = 71 (PPROCESS_BASIC_INFORMATION)ProcessInformation; 72 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation; 73 ULONG UserTime, KernelTime; 74 PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation; 75 ULONG HandleCount; 76 PPROCESS_SESSION_INFORMATION SessionInfo = 77 (PPROCESS_SESSION_INFORMATION)ProcessInformation; 78 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation; 79 PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation; 80 PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation; 81 PUNICODE_STRING ImageName; 82 ULONG Cookie, ExecuteOptions = 0; 83 ULONG_PTR Wow64 = 0; 84 PROCESS_VALUES ProcessValues; 85 ULONG Flags; 86 PAGED_CODE(); 87 88 /* Check for user-mode caller */ 89 if (PreviousMode != KernelMode) 90 { 91 /* Prepare to probe parameters */ 92 _SEH2_TRY 93 { 94 /* Probe the buffer */ 95 ProbeForRead(ProcessInformation, 96 ProcessInformationLength, 97 sizeof(ULONG)); 98 99 /* Probe the return length if required */ 100 if (ReturnLength) ProbeForWriteUlong(ReturnLength); 101 } 102 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 103 { 104 /* Return the exception code */ 105 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 106 } 107 _SEH2_END; 108 } 109 110 if (((ProcessInformationClass == ProcessCookie) || 111 (ProcessInformationClass == ProcessImageInformation)) && 112 (ProcessHandle != NtCurrentProcess())) 113 { 114 /* 115 * Retrieving the process cookie is only allowed for the calling process 116 * itself! XP only allows NtCurrentProcess() as process handles even if 117 * a real handle actually represents the current process. 118 */ 119 return STATUS_INVALID_PARAMETER; 120 } 121 122 /* Check the information class */ 123 switch (ProcessInformationClass) 124 { 125 /* Basic process information */ 126 case ProcessBasicInformation: 127 128 if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION)) 129 { 130 Status = STATUS_INFO_LENGTH_MISMATCH; 131 break; 132 } 133 134 /* Set return length */ 135 Length = sizeof(PROCESS_BASIC_INFORMATION); 136 137 /* Reference the process */ 138 Status = ObReferenceObjectByHandle(ProcessHandle, 139 PROCESS_QUERY_INFORMATION, 140 PsProcessType, 141 PreviousMode, 142 (PVOID*)&Process, 143 NULL); 144 if (!NT_SUCCESS(Status)) break; 145 146 /* Protect writes with SEH */ 147 _SEH2_TRY 148 { 149 /* Write all the information from the EPROCESS/KPROCESS */ 150 ProcessBasicInfo->ExitStatus = Process->ExitStatus; 151 ProcessBasicInfo->PebBaseAddress = Process->Peb; 152 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity; 153 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process-> 154 UniqueProcessId; 155 ProcessBasicInfo->InheritedFromUniqueProcessId = 156 (ULONG_PTR)Process->InheritedFromUniqueProcessId; 157 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority; 158 159 } 160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 161 { 162 /* Get exception code */ 163 Status = _SEH2_GetExceptionCode(); 164 } 165 _SEH2_END; 166 167 /* Dereference the process */ 168 ObDereferenceObject(Process); 169 break; 170 171 /* Process quota limits */ 172 case ProcessQuotaLimits: 173 174 if (ProcessInformationLength != sizeof(QUOTA_LIMITS)) 175 { 176 Status = STATUS_INFO_LENGTH_MISMATCH; 177 break; 178 } 179 180 Length = sizeof(QUOTA_LIMITS); 181 182 /* Reference the process */ 183 Status = ObReferenceObjectByHandle(ProcessHandle, 184 PROCESS_QUERY_INFORMATION, 185 PsProcessType, 186 PreviousMode, 187 (PVOID*)&Process, 188 NULL); 189 if (!NT_SUCCESS(Status)) break; 190 191 /* Indicate success */ 192 Status = STATUS_SUCCESS; 193 194 _SEH2_TRY 195 { 196 /* Set max/min working set sizes */ 197 QuotaLimits->MaximumWorkingSetSize = 198 Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT; 199 QuotaLimits->MinimumWorkingSetSize = 200 Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT; 201 202 /* Set default time limits */ 203 QuotaLimits->TimeLimit.LowPart = MAXULONG; 204 QuotaLimits->TimeLimit.HighPart = MAXULONG; 205 206 /* Is quota block a default one? */ 207 if (Process->QuotaBlock == &PspDefaultQuotaBlock) 208 { 209 /* Set default pools and pagefile limits */ 210 QuotaLimits->PagedPoolLimit = (SIZE_T)-1; 211 QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1; 212 QuotaLimits->PagefileLimit = (SIZE_T)-1; 213 } 214 else 215 { 216 /* Get limits from non-default quota block */ 217 QuotaLimits->PagedPoolLimit = 218 Process->QuotaBlock->QuotaEntry[PagedPool].Limit; 219 QuotaLimits->NonPagedPoolLimit = 220 Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit; 221 QuotaLimits->PagefileLimit = 222 Process->QuotaBlock->QuotaEntry[2].Limit; 223 } 224 } 225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 226 { 227 /* Get exception code */ 228 Status = _SEH2_GetExceptionCode(); 229 } 230 _SEH2_END; 231 232 /* Dereference the process */ 233 ObDereferenceObject(Process); 234 break; 235 236 case ProcessIoCounters: 237 238 if (ProcessInformationLength != sizeof(IO_COUNTERS)) 239 { 240 Status = STATUS_INFO_LENGTH_MISMATCH; 241 break; 242 } 243 244 Length = sizeof(IO_COUNTERS); 245 246 /* Reference the process */ 247 Status = ObReferenceObjectByHandle(ProcessHandle, 248 PROCESS_QUERY_INFORMATION, 249 PsProcessType, 250 PreviousMode, 251 (PVOID*)&Process, 252 NULL); 253 if (!NT_SUCCESS(Status)) break; 254 255 /* Query IO counters from the process */ 256 KeQueryValuesProcess(&Process->Pcb, &ProcessValues); 257 258 _SEH2_TRY 259 { 260 RtlCopyMemory(IoCounters, &ProcessValues.IoInfo, sizeof(IO_COUNTERS)); 261 } 262 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 263 { 264 /* Ignore exception */ 265 } 266 _SEH2_END; 267 268 /* Set status to success in any case */ 269 Status = STATUS_SUCCESS; 270 271 /* Dereference the process */ 272 ObDereferenceObject(Process); 273 break; 274 275 /* Timing */ 276 case ProcessTimes: 277 278 /* Set the return length */ 279 if (ProcessInformationLength != sizeof(KERNEL_USER_TIMES)) 280 { 281 Status = STATUS_INFO_LENGTH_MISMATCH; 282 break; 283 } 284 285 Length = sizeof(KERNEL_USER_TIMES); 286 287 /* Reference the process */ 288 Status = ObReferenceObjectByHandle(ProcessHandle, 289 PROCESS_QUERY_INFORMATION, 290 PsProcessType, 291 PreviousMode, 292 (PVOID*)&Process, 293 NULL); 294 if (!NT_SUCCESS(Status)) break; 295 296 /* Protect writes with SEH */ 297 _SEH2_TRY 298 { 299 /* Copy time information from EPROCESS/KPROCESS */ 300 KernelTime = KeQueryRuntimeProcess(&Process->Pcb, &UserTime); 301 ProcessTime->CreateTime = Process->CreateTime; 302 ProcessTime->UserTime.QuadPart = (LONGLONG)UserTime * KeMaximumIncrement; 303 ProcessTime->KernelTime.QuadPart = (LONGLONG)KernelTime * KeMaximumIncrement; 304 ProcessTime->ExitTime = Process->ExitTime; 305 } 306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 307 { 308 /* Get exception code */ 309 Status = _SEH2_GetExceptionCode(); 310 } 311 _SEH2_END; 312 313 /* Dereference the process */ 314 ObDereferenceObject(Process); 315 break; 316 317 /* Process Debug Port */ 318 case ProcessDebugPort: 319 320 if (ProcessInformationLength != sizeof(HANDLE)) 321 { 322 Status = STATUS_INFO_LENGTH_MISMATCH; 323 break; 324 } 325 326 /* Set return length */ 327 Length = sizeof(HANDLE); 328 329 /* Reference the process */ 330 Status = ObReferenceObjectByHandle(ProcessHandle, 331 PROCESS_QUERY_INFORMATION, 332 PsProcessType, 333 PreviousMode, 334 (PVOID*)&Process, 335 NULL); 336 if (!NT_SUCCESS(Status)) break; 337 338 /* Protect write with SEH */ 339 _SEH2_TRY 340 { 341 /* Return whether or not we have a debug port */ 342 *(PHANDLE)ProcessInformation = (Process->DebugPort ? 343 (HANDLE)-1 : NULL); 344 } 345 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 346 { 347 /* Get exception code */ 348 Status = _SEH2_GetExceptionCode(); 349 } 350 _SEH2_END; 351 352 /* Dereference the process */ 353 ObDereferenceObject(Process); 354 break; 355 356 case ProcessHandleCount: 357 358 if (ProcessInformationLength != sizeof(ULONG)) 359 { 360 Status = STATUS_INFO_LENGTH_MISMATCH; 361 break; 362 } 363 364 /* Set the return length*/ 365 Length = sizeof(ULONG); 366 367 /* Reference the process */ 368 Status = ObReferenceObjectByHandle(ProcessHandle, 369 PROCESS_QUERY_INFORMATION, 370 PsProcessType, 371 PreviousMode, 372 (PVOID*)&Process, 373 NULL); 374 if (!NT_SUCCESS(Status)) break; 375 376 /* Count the number of handles this process has */ 377 HandleCount = ObGetProcessHandleCount(Process); 378 379 /* Protect write in SEH */ 380 _SEH2_TRY 381 { 382 /* Return the count of handles */ 383 *(PULONG)ProcessInformation = HandleCount; 384 } 385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 386 { 387 /* Get the exception code */ 388 Status = _SEH2_GetExceptionCode(); 389 } 390 _SEH2_END; 391 392 /* Dereference the process */ 393 ObDereferenceObject(Process); 394 break; 395 396 /* Session ID for the process */ 397 case ProcessSessionInformation: 398 399 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION)) 400 { 401 Status = STATUS_INFO_LENGTH_MISMATCH; 402 break; 403 } 404 405 /* Set the return length*/ 406 Length = sizeof(PROCESS_SESSION_INFORMATION); 407 408 /* Reference the process */ 409 Status = ObReferenceObjectByHandle(ProcessHandle, 410 PROCESS_QUERY_INFORMATION, 411 PsProcessType, 412 PreviousMode, 413 (PVOID*)&Process, 414 NULL); 415 if (!NT_SUCCESS(Status)) break; 416 417 /* Enter SEH for write safety */ 418 _SEH2_TRY 419 { 420 /* Write back the Session ID */ 421 SessionInfo->SessionId = PsGetProcessSessionId(Process); 422 } 423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 424 { 425 /* Get the exception code */ 426 Status = _SEH2_GetExceptionCode(); 427 } 428 _SEH2_END; 429 430 /* Dereference the process */ 431 ObDereferenceObject(Process); 432 break; 433 434 /* Virtual Memory Statistics */ 435 case ProcessVmCounters: 436 437 /* Validate the input length */ 438 if ((ProcessInformationLength != sizeof(VM_COUNTERS)) && 439 (ProcessInformationLength != sizeof(VM_COUNTERS_EX))) 440 { 441 Status = STATUS_INFO_LENGTH_MISMATCH; 442 break; 443 } 444 445 /* Reference the process */ 446 Status = ObReferenceObjectByHandle(ProcessHandle, 447 PROCESS_QUERY_INFORMATION, 448 PsProcessType, 449 PreviousMode, 450 (PVOID*)&Process, 451 NULL); 452 if (!NT_SUCCESS(Status)) break; 453 454 /* Enter SEH for write safety */ 455 _SEH2_TRY 456 { 457 /* Return data from EPROCESS */ 458 VmCounters->PeakVirtualSize = Process->PeakVirtualSize; 459 VmCounters->VirtualSize = Process->VirtualSize; 460 VmCounters->PageFaultCount = Process->Vm.PageFaultCount; 461 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize; 462 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize; 463 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[PsPagedPool]; 464 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[PsPagedPool]; 465 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[PsNonPagedPool]; 466 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[PsNonPagedPool]; 467 VmCounters->PagefileUsage = Process->QuotaUsage[PsPageFile] << PAGE_SHIFT; 468 VmCounters->PeakPagefileUsage = Process->QuotaPeak[PsPageFile] << PAGE_SHIFT; 469 //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT; 470 // 471 472 /* Set the return length */ 473 Length = ProcessInformationLength; 474 } 475 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 476 { 477 /* Get the exception code */ 478 Status = _SEH2_GetExceptionCode(); 479 } 480 _SEH2_END; 481 482 /* Dereference the process */ 483 ObDereferenceObject(Process); 484 break; 485 486 /* Hard Error Processing Mode */ 487 case ProcessDefaultHardErrorMode: 488 489 if (ProcessInformationLength != sizeof(ULONG)) 490 { 491 Status = STATUS_INFO_LENGTH_MISMATCH; 492 break; 493 } 494 495 /* Set the return length*/ 496 Length = sizeof(ULONG); 497 498 /* Reference the process */ 499 Status = ObReferenceObjectByHandle(ProcessHandle, 500 PROCESS_QUERY_INFORMATION, 501 PsProcessType, 502 PreviousMode, 503 (PVOID*)&Process, 504 NULL); 505 if (!NT_SUCCESS(Status)) break; 506 507 /* Enter SEH for writing back data */ 508 _SEH2_TRY 509 { 510 /* Write the current processing mode */ 511 *(PULONG)ProcessInformation = Process-> 512 DefaultHardErrorProcessing; 513 } 514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 515 { 516 /* Get the exception code */ 517 Status = _SEH2_GetExceptionCode(); 518 } 519 _SEH2_END; 520 521 /* Dereference the process */ 522 ObDereferenceObject(Process); 523 break; 524 525 /* Priority Boosting status */ 526 case ProcessPriorityBoost: 527 528 if (ProcessInformationLength != sizeof(ULONG)) 529 { 530 Status = STATUS_INFO_LENGTH_MISMATCH; 531 break; 532 } 533 534 /* Set the return length */ 535 Length = sizeof(ULONG); 536 537 /* Reference the process */ 538 Status = ObReferenceObjectByHandle(ProcessHandle, 539 PROCESS_QUERY_INFORMATION, 540 PsProcessType, 541 PreviousMode, 542 (PVOID*)&Process, 543 NULL); 544 if (!NT_SUCCESS(Status)) break; 545 546 /* Enter SEH for writing back data */ 547 _SEH2_TRY 548 { 549 /* Return boost status */ 550 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ? 551 TRUE : FALSE; 552 } 553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 554 { 555 /* Get the exception code */ 556 Status = _SEH2_GetExceptionCode(); 557 } 558 _SEH2_END; 559 560 /* Dereference the process */ 561 ObDereferenceObject(Process); 562 break; 563 564 /* DOS Device Map */ 565 case ProcessDeviceMap: 566 567 if (ProcessInformationLength == sizeof(PROCESS_DEVICEMAP_INFORMATION_EX)) 568 { 569 /* Protect read in SEH */ 570 _SEH2_TRY 571 { 572 PPROCESS_DEVICEMAP_INFORMATION_EX DeviceMapEx = ProcessInformation; 573 574 Flags = DeviceMapEx->Flags; 575 } 576 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 577 { 578 /* Get the exception code */ 579 Status = _SEH2_GetExceptionCode(); 580 } 581 _SEH2_END; 582 583 if (!NT_SUCCESS(Status)) 584 { 585 break; 586 } 587 588 /* Only one flag is supported and it needs LUID mappings */ 589 if ((Flags & ~PROCESS_LUID_DOSDEVICES_ONLY) != 0 || 590 !ObIsLUIDDeviceMapsEnabled()) 591 { 592 Status = STATUS_INVALID_PARAMETER; 593 break; 594 } 595 } 596 else 597 { 598 /* This has to be the size of the Query union field for x64 compatibility! */ 599 if (ProcessInformationLength != RTL_FIELD_SIZE(PROCESS_DEVICEMAP_INFORMATION, Query)) 600 { 601 Status = STATUS_INFO_LENGTH_MISMATCH; 602 break; 603 } 604 605 /* No flags for standard call */ 606 Flags = 0; 607 } 608 609 /* Set the return length */ 610 Length = ProcessInformationLength; 611 612 /* Reference the process */ 613 Status = ObReferenceObjectByHandle(ProcessHandle, 614 PROCESS_QUERY_INFORMATION, 615 PsProcessType, 616 PreviousMode, 617 (PVOID*)&Process, 618 NULL); 619 if (!NT_SUCCESS(Status)) break; 620 621 /* Query the device map information */ 622 Status = ObQueryDeviceMapInformation(Process, 623 ProcessInformation, 624 Flags); 625 626 /* Dereference the process */ 627 ObDereferenceObject(Process); 628 break; 629 630 /* Priority class */ 631 case ProcessPriorityClass: 632 633 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS)) 634 { 635 Status = STATUS_INFO_LENGTH_MISMATCH; 636 break; 637 } 638 639 /* Set the return length*/ 640 Length = sizeof(PROCESS_PRIORITY_CLASS); 641 642 /* Reference the process */ 643 Status = ObReferenceObjectByHandle(ProcessHandle, 644 PROCESS_QUERY_INFORMATION, 645 PsProcessType, 646 PreviousMode, 647 (PVOID*)&Process, 648 NULL); 649 if (!NT_SUCCESS(Status)) break; 650 651 /* Enter SEH for writing back data */ 652 _SEH2_TRY 653 { 654 /* Return current priority class */ 655 PsPriorityClass->PriorityClass = Process->PriorityClass; 656 PsPriorityClass->Foreground = FALSE; 657 } 658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 659 { 660 /* Get the exception code */ 661 Status = _SEH2_GetExceptionCode(); 662 } 663 _SEH2_END; 664 665 /* Dereference the process */ 666 ObDereferenceObject(Process); 667 break; 668 669 case ProcessImageFileName: 670 671 /* Reference the process */ 672 Status = ObReferenceObjectByHandle(ProcessHandle, 673 PROCESS_QUERY_INFORMATION, 674 PsProcessType, 675 PreviousMode, 676 (PVOID*)&Process, 677 NULL); 678 if (!NT_SUCCESS(Status)) break; 679 680 /* Get the image path */ 681 Status = SeLocateProcessImageName(Process, &ImageName); 682 if (NT_SUCCESS(Status)) 683 { 684 /* Set return length */ 685 Length = ImageName->MaximumLength + 686 sizeof(OBJECT_NAME_INFORMATION); 687 688 /* Make sure it's large enough */ 689 if (Length <= ProcessInformationLength) 690 { 691 /* Enter SEH to protect write */ 692 _SEH2_TRY 693 { 694 /* Copy it */ 695 RtlCopyMemory(ProcessInformation, 696 ImageName, 697 Length); 698 699 /* Update pointer */ 700 ((PUNICODE_STRING)ProcessInformation)->Buffer = 701 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1); 702 } 703 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 704 { 705 /* Get the exception code */ 706 Status = _SEH2_GetExceptionCode(); 707 } 708 _SEH2_END; 709 } 710 else 711 { 712 /* Buffer too small */ 713 Status = STATUS_INFO_LENGTH_MISMATCH; 714 } 715 716 /* Free the image path */ 717 ExFreePoolWithTag(ImageName, TAG_SEPA); 718 } 719 /* Dereference the process */ 720 ObDereferenceObject(Process); 721 break; 722 723 case ProcessDebugFlags: 724 725 if (ProcessInformationLength != sizeof(ULONG)) 726 { 727 Status = STATUS_INFO_LENGTH_MISMATCH; 728 break; 729 } 730 731 /* Set the return length*/ 732 Length = sizeof(ULONG); 733 734 /* Reference the process */ 735 Status = ObReferenceObjectByHandle(ProcessHandle, 736 PROCESS_QUERY_INFORMATION, 737 PsProcessType, 738 PreviousMode, 739 (PVOID*)&Process, 740 NULL); 741 if (!NT_SUCCESS(Status)) break; 742 743 /* Enter SEH for writing back data */ 744 _SEH2_TRY 745 { 746 /* Return the debug flag state */ 747 *(PULONG)ProcessInformation = Process->NoDebugInherit ? 0 : 1; 748 } 749 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 750 { 751 /* Get the exception code */ 752 Status = _SEH2_GetExceptionCode(); 753 } 754 _SEH2_END; 755 756 /* Dereference the process */ 757 ObDereferenceObject(Process); 758 break; 759 760 case ProcessBreakOnTermination: 761 762 if (ProcessInformationLength != sizeof(ULONG)) 763 { 764 Status = STATUS_INFO_LENGTH_MISMATCH; 765 break; 766 } 767 768 /* Set the return length */ 769 Length = sizeof(ULONG); 770 771 /* Reference the process */ 772 Status = ObReferenceObjectByHandle(ProcessHandle, 773 PROCESS_QUERY_INFORMATION, 774 PsProcessType, 775 PreviousMode, 776 (PVOID*)&Process, 777 NULL); 778 if (!NT_SUCCESS(Status)) break; 779 780 /* Enter SEH for writing back data */ 781 _SEH2_TRY 782 { 783 /* Return the BreakOnTermination state */ 784 *(PULONG)ProcessInformation = Process->BreakOnTermination; 785 } 786 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 787 { 788 /* Get the exception code */ 789 Status = _SEH2_GetExceptionCode(); 790 } 791 _SEH2_END; 792 793 /* Dereference the process */ 794 ObDereferenceObject(Process); 795 break; 796 797 /* Per-process security cookie */ 798 case ProcessCookie: 799 800 /* Get the current process and cookie */ 801 Process = PsGetCurrentProcess(); 802 Cookie = Process->Cookie; 803 if (!Cookie) 804 { 805 LARGE_INTEGER SystemTime; 806 ULONG NewCookie; 807 PKPRCB Prcb; 808 809 /* Generate a new cookie */ 810 KeQuerySystemTime(&SystemTime); 811 Prcb = KeGetCurrentPrcb(); 812 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ 813 SystemTime.u.LowPart ^ SystemTime.u.HighPart; 814 815 /* Set the new cookie or return the current one */ 816 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie, 817 NewCookie, 818 Cookie); 819 if (!Cookie) Cookie = NewCookie; 820 821 /* Set return length */ 822 Length = sizeof(ULONG); 823 } 824 825 /* Indicate success */ 826 Status = STATUS_SUCCESS; 827 828 /* Enter SEH to protect write */ 829 _SEH2_TRY 830 { 831 /* Write back the cookie */ 832 *(PULONG)ProcessInformation = Cookie; 833 } 834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 835 { 836 /* Get the exception code */ 837 Status = _SEH2_GetExceptionCode(); 838 } 839 _SEH2_END; 840 break; 841 842 case ProcessImageInformation: 843 844 if (ProcessInformationLength != sizeof(SECTION_IMAGE_INFORMATION)) 845 { 846 /* Break out */ 847 Status = STATUS_INFO_LENGTH_MISMATCH; 848 break; 849 } 850 851 /* Set the length required and validate it */ 852 Length = sizeof(SECTION_IMAGE_INFORMATION); 853 854 /* Enter SEH to protect write */ 855 _SEH2_TRY 856 { 857 MmGetImageInformation((PSECTION_IMAGE_INFORMATION)ProcessInformation); 858 } 859 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 860 { 861 /* Get the exception code */ 862 Status = _SEH2_GetExceptionCode(); 863 } 864 _SEH2_END; 865 866 /* Indicate success */ 867 Status = STATUS_SUCCESS; 868 break; 869 870 case ProcessDebugObjectHandle: 871 872 if (ProcessInformationLength != sizeof(HANDLE)) 873 { 874 Status = STATUS_INFO_LENGTH_MISMATCH; 875 break; 876 } 877 878 /* Set the return length */ 879 Length = sizeof(HANDLE); 880 881 /* Reference the process */ 882 Status = ObReferenceObjectByHandle(ProcessHandle, 883 PROCESS_QUERY_INFORMATION, 884 PsProcessType, 885 PreviousMode, 886 (PVOID*)&Process, 887 NULL); 888 if (!NT_SUCCESS(Status)) break; 889 890 /* Get the debug port */ 891 Status = DbgkOpenProcessDebugPort(Process, PreviousMode, &DebugPort); 892 893 /* Let go of the process */ 894 ObDereferenceObject(Process); 895 896 /* Protect write in SEH */ 897 _SEH2_TRY 898 { 899 /* Return debug port's handle */ 900 *(PHANDLE)ProcessInformation = DebugPort; 901 } 902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 903 { 904 /* Get the exception code */ 905 Status = _SEH2_GetExceptionCode(); 906 } 907 _SEH2_END; 908 break; 909 910 case ProcessHandleTracing: 911 DPRINT1("Handle tracing Not implemented: %lx\n", ProcessInformationClass); 912 Status = STATUS_NOT_IMPLEMENTED; 913 break; 914 915 case ProcessLUIDDeviceMapsEnabled: 916 917 if (ProcessInformationLength != sizeof(ULONG)) 918 { 919 Status = STATUS_INFO_LENGTH_MISMATCH; 920 break; 921 } 922 923 /* Set the return length */ 924 Length = sizeof(ULONG); 925 926 /* Indicate success */ 927 Status = STATUS_SUCCESS; 928 929 /* Protect write in SEH */ 930 _SEH2_TRY 931 { 932 /* Query Ob */ 933 *(PULONG)ProcessInformation = ObIsLUIDDeviceMapsEnabled(); 934 } 935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 936 { 937 /* Get the exception code */ 938 Status = _SEH2_GetExceptionCode(); 939 } 940 _SEH2_END; 941 break; 942 943 case ProcessWx86Information: 944 945 if (ProcessInformationLength != sizeof(ULONG)) 946 { 947 Status = STATUS_INFO_LENGTH_MISMATCH; 948 break; 949 } 950 951 /* Set the return length */ 952 Length = sizeof(ULONG); 953 954 /* Reference the process */ 955 Status = ObReferenceObjectByHandle(ProcessHandle, 956 PROCESS_QUERY_INFORMATION, 957 PsProcessType, 958 PreviousMode, 959 (PVOID*)&Process, 960 NULL); 961 if (!NT_SUCCESS(Status)) break; 962 963 /* Protect write in SEH */ 964 _SEH2_TRY 965 { 966 /* Return if the flag is set */ 967 *(PULONG)ProcessInformation = (ULONG)Process->VdmAllowed; 968 } 969 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 970 { 971 /* Get the exception code */ 972 Status = _SEH2_GetExceptionCode(); 973 } 974 _SEH2_END; 975 976 /* Dereference the process */ 977 ObDereferenceObject(Process); 978 break; 979 980 case ProcessWow64Information: 981 982 if (ProcessInformationLength != sizeof(ULONG_PTR)) 983 { 984 Status = STATUS_INFO_LENGTH_MISMATCH; 985 break; 986 } 987 988 /* Set return length */ 989 Length = sizeof(ULONG_PTR); 990 991 /* Reference the process */ 992 Status = ObReferenceObjectByHandle(ProcessHandle, 993 PROCESS_QUERY_INFORMATION, 994 PsProcessType, 995 PreviousMode, 996 (PVOID*)&Process, 997 NULL); 998 if (!NT_SUCCESS(Status)) break; 999 1000 /* Make sure the process isn't dying */ 1001 if (ExAcquireRundownProtection(&Process->RundownProtect)) 1002 { 1003 /* Get the WOW64 process structure */ 1004 #ifdef _WIN64 1005 Wow64 = (ULONG_PTR)Process->Wow64Process; 1006 #else 1007 Wow64 = 0; 1008 #endif 1009 /* Release the lock */ 1010 ExReleaseRundownProtection(&Process->RundownProtect); 1011 } 1012 1013 /* Protect write with SEH */ 1014 _SEH2_TRY 1015 { 1016 /* Return whether or not we have a debug port */ 1017 *(PULONG_PTR)ProcessInformation = Wow64; 1018 } 1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1020 { 1021 /* Get exception code */ 1022 Status = _SEH2_GetExceptionCode(); 1023 } 1024 _SEH2_END; 1025 1026 /* Dereference the process */ 1027 ObDereferenceObject(Process); 1028 break; 1029 1030 case ProcessExecuteFlags: 1031 1032 if (ProcessInformationLength != sizeof(ULONG)) 1033 { 1034 Status = STATUS_INFO_LENGTH_MISMATCH; 1035 break; 1036 } 1037 1038 /* Set return length */ 1039 Length = sizeof(ULONG); 1040 1041 if (ProcessHandle != NtCurrentProcess()) 1042 { 1043 return STATUS_INVALID_PARAMETER; 1044 } 1045 1046 /* Get the options */ 1047 Status = MmGetExecuteOptions(&ExecuteOptions); 1048 if (NT_SUCCESS(Status)) 1049 { 1050 /* Protect write with SEH */ 1051 _SEH2_TRY 1052 { 1053 /* Return them */ 1054 *(PULONG)ProcessInformation = ExecuteOptions; 1055 } 1056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1057 { 1058 /* Get exception code */ 1059 Status = _SEH2_GetExceptionCode(); 1060 } 1061 _SEH2_END; 1062 } 1063 break; 1064 1065 case ProcessLdtInformation: 1066 DPRINT1("VDM/16-bit not implemented: %lx\n", ProcessInformationClass); 1067 Status = STATUS_NOT_IMPLEMENTED; 1068 break; 1069 1070 case ProcessWorkingSetWatch: 1071 DPRINT1("WS Watch Not implemented: %lx\n", ProcessInformationClass); 1072 Status = STATUS_NOT_IMPLEMENTED; 1073 break; 1074 1075 case ProcessPooledUsageAndLimits: 1076 DPRINT1("Pool limits Not implemented: %lx\n", ProcessInformationClass); 1077 Status = STATUS_NOT_IMPLEMENTED; 1078 break; 1079 1080 /* Not supported by Server 2003 */ 1081 default: 1082 DPRINT1("Unsupported info class: %lx\n", ProcessInformationClass); 1083 Status = STATUS_INVALID_INFO_CLASS; 1084 } 1085 1086 /* Protect write with SEH */ 1087 _SEH2_TRY 1088 { 1089 /* Check if caller wanted return length */ 1090 if ((ReturnLength) && (Length)) *ReturnLength = Length; 1091 } 1092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1093 { 1094 /* Get exception code */ 1095 Status = _SEH2_GetExceptionCode(); 1096 } 1097 _SEH2_END; 1098 1099 return Status; 1100 } 1101 1102 /* 1103 * @implemented 1104 */ 1105 NTSTATUS 1106 NTAPI 1107 NtSetInformationProcess(IN HANDLE ProcessHandle, 1108 IN PROCESSINFOCLASS ProcessInformationClass, 1109 IN PVOID ProcessInformation, 1110 IN ULONG ProcessInformationLength) 1111 { 1112 PEPROCESS Process; 1113 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1114 ACCESS_MASK Access; 1115 NTSTATUS Status; 1116 HANDLE PortHandle = NULL; 1117 HANDLE TokenHandle = NULL; 1118 HANDLE DirectoryHandle = NULL; 1119 PROCESS_SESSION_INFORMATION SessionInfo = {0}; 1120 PROCESS_PRIORITY_CLASS PriorityClass = {0}; 1121 PROCESS_FOREGROUND_BACKGROUND Foreground = {0}; 1122 PVOID ExceptionPort; 1123 ULONG Break; 1124 KAFFINITY ValidAffinity, Affinity = 0; 1125 KPRIORITY BasePriority = 0; 1126 UCHAR MemoryPriority = 0; 1127 BOOLEAN DisableBoost = 0; 1128 ULONG DefaultHardErrorMode = 0; 1129 ULONG DebugFlags = 0, EnableFixup = 0, Boost = 0; 1130 ULONG NoExecute = 0, VdmPower = 0; 1131 BOOLEAN HasPrivilege; 1132 PLIST_ENTRY Next; 1133 PETHREAD Thread; 1134 PAGED_CODE(); 1135 1136 /* Verify Information Class validity */ 1137 #if 0 1138 Status = DefaultSetInfoBufferCheck(ProcessInformationClass, 1139 PsProcessInfoClass, 1140 RTL_NUMBER_OF(PsProcessInfoClass), 1141 ProcessInformation, 1142 ProcessInformationLength, 1143 PreviousMode); 1144 if (!NT_SUCCESS(Status)) return Status; 1145 #endif 1146 1147 /* Check what class this is */ 1148 Access = PROCESS_SET_INFORMATION; 1149 if (ProcessInformationClass == ProcessSessionInformation) 1150 { 1151 /* Setting the Session ID needs a special mask */ 1152 Access |= PROCESS_SET_SESSIONID; 1153 } 1154 else if (ProcessInformationClass == ProcessExceptionPort) 1155 { 1156 /* Setting the exception port needs a special mask */ 1157 Access |= PROCESS_SUSPEND_RESUME; 1158 } 1159 1160 /* Reference the process */ 1161 Status = ObReferenceObjectByHandle(ProcessHandle, 1162 Access, 1163 PsProcessType, 1164 PreviousMode, 1165 (PVOID*)&Process, 1166 NULL); 1167 if (!NT_SUCCESS(Status)) return Status; 1168 1169 /* Check what kind of information class this is */ 1170 switch (ProcessInformationClass) 1171 { 1172 case ProcessWx86Information: 1173 1174 /* Check buffer length */ 1175 if (ProcessInformationLength != sizeof(HANDLE)) 1176 { 1177 Status = STATUS_INFO_LENGTH_MISMATCH; 1178 break; 1179 } 1180 1181 /* Use SEH for capture */ 1182 _SEH2_TRY 1183 { 1184 /* Capture the boolean */ 1185 VdmPower = *(PULONG)ProcessInformation; 1186 } 1187 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1188 { 1189 /* Get the exception code */ 1190 Status = _SEH2_GetExceptionCode(); 1191 _SEH2_YIELD(break); 1192 } 1193 _SEH2_END; 1194 1195 /* Getting VDM powers requires the SeTcbPrivilege */ 1196 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1197 { 1198 /* We don't hold the privilege, bail out */ 1199 Status = STATUS_PRIVILEGE_NOT_HELD; 1200 DPRINT1("Need TCB privilege\n"); 1201 break; 1202 } 1203 1204 /* Set or clear the flag */ 1205 if (VdmPower) 1206 { 1207 PspSetProcessFlag(Process, PSF_VDM_ALLOWED_BIT); 1208 } 1209 else 1210 { 1211 PspClearProcessFlag(Process, PSF_VDM_ALLOWED_BIT); 1212 } 1213 break; 1214 1215 /* Error/Exception Port */ 1216 case ProcessExceptionPort: 1217 1218 /* Check buffer length */ 1219 if (ProcessInformationLength != sizeof(HANDLE)) 1220 { 1221 Status = STATUS_INFO_LENGTH_MISMATCH; 1222 break; 1223 } 1224 1225 /* Use SEH for capture */ 1226 _SEH2_TRY 1227 { 1228 /* Capture the handle */ 1229 PortHandle = *(PHANDLE)ProcessInformation; 1230 } 1231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1232 { 1233 /* Get the exception code */ 1234 Status = _SEH2_GetExceptionCode(); 1235 _SEH2_YIELD(break); 1236 } 1237 _SEH2_END; 1238 1239 /* Setting the error port requires the SeTcbPrivilege */ 1240 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1241 { 1242 /* We don't hold the privilege, bail out */ 1243 Status = STATUS_PRIVILEGE_NOT_HELD; 1244 break; 1245 } 1246 1247 /* Get the LPC Port */ 1248 Status = ObReferenceObjectByHandle(PortHandle, 1249 0, 1250 LpcPortObjectType, 1251 PreviousMode, 1252 (PVOID)&ExceptionPort, 1253 NULL); 1254 if (!NT_SUCCESS(Status)) break; 1255 1256 /* Change the pointer */ 1257 if (InterlockedCompareExchangePointer(&Process->ExceptionPort, 1258 ExceptionPort, 1259 NULL)) 1260 { 1261 /* We already had one, fail */ 1262 ObDereferenceObject(ExceptionPort); 1263 Status = STATUS_PORT_ALREADY_SET; 1264 } 1265 break; 1266 1267 /* Security Token */ 1268 case ProcessAccessToken: 1269 1270 /* Check buffer length */ 1271 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN)) 1272 { 1273 Status = STATUS_INFO_LENGTH_MISMATCH; 1274 break; 1275 } 1276 1277 /* Use SEH for capture */ 1278 _SEH2_TRY 1279 { 1280 /* Save the token handle */ 1281 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)-> 1282 Token; 1283 } 1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1285 { 1286 /* Get the exception code */ 1287 Status = _SEH2_GetExceptionCode(); 1288 _SEH2_YIELD(break); 1289 } 1290 _SEH2_END; 1291 1292 /* Assign the actual token */ 1293 Status = PspSetPrimaryToken(Process, TokenHandle, NULL); 1294 break; 1295 1296 /* Hard error processing */ 1297 case ProcessDefaultHardErrorMode: 1298 1299 /* Check buffer length */ 1300 if (ProcessInformationLength != sizeof(ULONG)) 1301 { 1302 Status = STATUS_INFO_LENGTH_MISMATCH; 1303 break; 1304 } 1305 1306 /* Enter SEH for direct buffer read */ 1307 _SEH2_TRY 1308 { 1309 DefaultHardErrorMode = *(PULONG)ProcessInformation; 1310 } 1311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1312 { 1313 /* Get exception code */ 1314 Status = _SEH2_GetExceptionCode(); 1315 _SEH2_YIELD(break); 1316 } 1317 _SEH2_END; 1318 1319 /* Set the mode */ 1320 Process->DefaultHardErrorProcessing = DefaultHardErrorMode; 1321 1322 /* Call Ke for the update */ 1323 if (DefaultHardErrorMode & SEM_NOALIGNMENTFAULTEXCEPT) 1324 { 1325 KeSetAutoAlignmentProcess(&Process->Pcb, TRUE); 1326 } 1327 else 1328 { 1329 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE); 1330 } 1331 Status = STATUS_SUCCESS; 1332 break; 1333 1334 /* Session ID */ 1335 case ProcessSessionInformation: 1336 1337 /* Check buffer length */ 1338 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION)) 1339 { 1340 Status = STATUS_INFO_LENGTH_MISMATCH; 1341 break; 1342 } 1343 1344 /* Enter SEH for capture */ 1345 _SEH2_TRY 1346 { 1347 /* Capture the caller's buffer */ 1348 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation; 1349 } 1350 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1351 { 1352 /* Get the exception code */ 1353 Status = _SEH2_GetExceptionCode(); 1354 _SEH2_YIELD(break); 1355 } 1356 _SEH2_END; 1357 1358 /* Setting the session id requires the SeTcbPrivilege */ 1359 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1360 { 1361 /* We don't hold the privilege, bail out */ 1362 Status = STATUS_PRIVILEGE_NOT_HELD; 1363 break; 1364 } 1365 1366 #if 0 // OLD AND DEPRECATED CODE!!!! 1367 1368 /* FIXME - update the session id for the process token */ 1369 //Status = PsLockProcess(Process, FALSE); 1370 if (!NT_SUCCESS(Status)) break; 1371 1372 /* Write the session ID in the EPROCESS */ 1373 Process->Session = UlongToPtr(SessionInfo.SessionId); // HACK!!! 1374 1375 /* Check if the process also has a PEB */ 1376 if (Process->Peb) 1377 { 1378 /* 1379 * Attach to the process to make sure we're in the right 1380 * context to access the PEB structure 1381 */ 1382 KeAttachProcess(&Process->Pcb); 1383 1384 /* Enter SEH for write to user-mode PEB */ 1385 _SEH2_TRY 1386 { 1387 /* Write the session ID */ 1388 Process->Peb->SessionId = SessionInfo.SessionId; 1389 } 1390 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1391 { 1392 /* Get exception code */ 1393 Status = _SEH2_GetExceptionCode(); 1394 } 1395 _SEH2_END; 1396 1397 /* Detach from the process */ 1398 KeDetachProcess(); 1399 } 1400 1401 /* Unlock the process */ 1402 //PsUnlockProcess(Process); 1403 1404 #endif 1405 1406 /* 1407 * Since we cannot change the session ID of the given 1408 * process anymore because it is set once and for all 1409 * at process creation time and because it is stored 1410 * inside the Process->Session structure managed by MM, 1411 * we fake changing it: we just return success if the 1412 * user-defined value is the same as the session ID of 1413 * the process, and otherwise we fail. 1414 */ 1415 if (SessionInfo.SessionId == PsGetProcessSessionId(Process)) 1416 { 1417 Status = STATUS_SUCCESS; 1418 } 1419 else 1420 { 1421 Status = STATUS_ACCESS_DENIED; 1422 } 1423 1424 break; 1425 1426 case ProcessPriorityClass: 1427 1428 /* Check buffer length */ 1429 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS)) 1430 { 1431 Status = STATUS_INFO_LENGTH_MISMATCH; 1432 break; 1433 } 1434 1435 /* Enter SEH for capture */ 1436 _SEH2_TRY 1437 { 1438 /* Capture the caller's buffer */ 1439 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation; 1440 } 1441 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1442 { 1443 /* Return the exception code */ 1444 Status = _SEH2_GetExceptionCode(); 1445 _SEH2_YIELD(break); 1446 } 1447 _SEH2_END; 1448 1449 /* Check for invalid PriorityClass value */ 1450 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL) 1451 { 1452 Status = STATUS_INVALID_PARAMETER; 1453 break; 1454 } 1455 1456 if ((PriorityClass.PriorityClass != Process->PriorityClass) && 1457 (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME)) 1458 { 1459 /* Check the privilege */ 1460 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege, 1461 ProcessHandle, 1462 PROCESS_SET_INFORMATION, 1463 PreviousMode); 1464 if (!HasPrivilege) 1465 { 1466 ObDereferenceObject(Process); 1467 DPRINT1("Privilege to change priority to realtime lacking\n"); 1468 return STATUS_PRIVILEGE_NOT_HELD; 1469 } 1470 } 1471 1472 /* Check if we have a job */ 1473 if (Process->Job) 1474 { 1475 DPRINT1("Jobs not yet supported\n"); 1476 } 1477 1478 /* Set process priority class */ 1479 Process->PriorityClass = PriorityClass.PriorityClass; 1480 1481 /* Set process priority mode (foreground or background) */ 1482 PsSetProcessPriorityByClass(Process, 1483 PriorityClass.Foreground ? 1484 PsProcessPriorityForeground : 1485 PsProcessPriorityBackground); 1486 Status = STATUS_SUCCESS; 1487 break; 1488 1489 case ProcessForegroundInformation: 1490 1491 /* Check buffer length */ 1492 if (ProcessInformationLength != sizeof(PROCESS_FOREGROUND_BACKGROUND)) 1493 { 1494 Status = STATUS_INFO_LENGTH_MISMATCH; 1495 break; 1496 } 1497 1498 /* Enter SEH for capture */ 1499 _SEH2_TRY 1500 { 1501 /* Capture the caller's buffer */ 1502 Foreground = *(PPROCESS_FOREGROUND_BACKGROUND)ProcessInformation; 1503 } 1504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1505 { 1506 /* Return the exception code */ 1507 Status = _SEH2_GetExceptionCode(); 1508 _SEH2_YIELD(break); 1509 } 1510 _SEH2_END; 1511 1512 /* Set process priority mode (foreground or background) */ 1513 PsSetProcessPriorityByClass(Process, 1514 Foreground.Foreground ? 1515 PsProcessPriorityForeground : 1516 PsProcessPriorityBackground); 1517 Status = STATUS_SUCCESS; 1518 break; 1519 1520 case ProcessBasePriority: 1521 1522 /* Validate input length */ 1523 if (ProcessInformationLength != sizeof(KPRIORITY)) 1524 { 1525 Status = STATUS_INFO_LENGTH_MISMATCH; 1526 break; 1527 } 1528 1529 /* Enter SEH for direct buffer read */ 1530 _SEH2_TRY 1531 { 1532 BasePriority = *(KPRIORITY*)ProcessInformation; 1533 } 1534 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1535 { 1536 /* Get exception code */ 1537 Break = 0; 1538 Status = _SEH2_GetExceptionCode(); 1539 _SEH2_YIELD(break); 1540 } 1541 _SEH2_END; 1542 1543 /* Extract the memory priority out of there */ 1544 if (BasePriority & 0x80000000) 1545 { 1546 MemoryPriority = MEMORY_PRIORITY_FOREGROUND; 1547 BasePriority &= ~0x80000000; 1548 } 1549 else 1550 { 1551 MemoryPriority = MEMORY_PRIORITY_BACKGROUND; 1552 } 1553 1554 /* Validate the number */ 1555 if ((BasePriority > HIGH_PRIORITY) || (BasePriority <= LOW_PRIORITY)) 1556 { 1557 ObDereferenceObject(Process); 1558 return STATUS_INVALID_PARAMETER; 1559 } 1560 1561 /* Check if the new base is higher */ 1562 if (BasePriority > Process->Pcb.BasePriority) 1563 { 1564 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege, 1565 ProcessHandle, 1566 PROCESS_SET_INFORMATION, 1567 PreviousMode); 1568 if (!HasPrivilege) 1569 { 1570 ObDereferenceObject(Process); 1571 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority, Process->Pcb.BasePriority); 1572 return STATUS_PRIVILEGE_NOT_HELD; 1573 } 1574 } 1575 1576 /* Call Ke */ 1577 KeSetPriorityAndQuantumProcess(&Process->Pcb, BasePriority, 0); 1578 1579 /* Now set the memory priority */ 1580 MmSetMemoryPriorityProcess(Process, MemoryPriority); 1581 Status = STATUS_SUCCESS; 1582 break; 1583 1584 case ProcessRaisePriority: 1585 1586 /* Validate input length */ 1587 if (ProcessInformationLength != sizeof(ULONG)) 1588 { 1589 Status = STATUS_INFO_LENGTH_MISMATCH; 1590 break; 1591 } 1592 1593 /* Enter SEH for direct buffer read */ 1594 _SEH2_TRY 1595 { 1596 Boost = *(PULONG)ProcessInformation; 1597 } 1598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1599 { 1600 /* Get exception code */ 1601 Break = 0; 1602 Status = _SEH2_GetExceptionCode(); 1603 _SEH2_YIELD(break); 1604 } 1605 _SEH2_END; 1606 1607 /* Make sure the process isn't dying */ 1608 if (ExAcquireRundownProtection(&Process->RundownProtect)) 1609 { 1610 /* Lock it */ 1611 KeEnterCriticalRegion(); 1612 ExAcquirePushLockShared(&Process->ProcessLock); 1613 1614 /* Loop the threads */ 1615 for (Next = Process->ThreadListHead.Flink; 1616 Next != &Process->ThreadListHead; 1617 Next = Next->Flink) 1618 { 1619 /* Call Ke for the thread */ 1620 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry); 1621 KeBoostPriorityThread(&Thread->Tcb, Boost); 1622 } 1623 1624 /* Release the lock and rundown */ 1625 ExReleasePushLockShared(&Process->ProcessLock); 1626 KeLeaveCriticalRegion(); 1627 ExReleaseRundownProtection(&Process->RundownProtect); 1628 1629 /* Set success code */ 1630 Status = STATUS_SUCCESS; 1631 } 1632 else 1633 { 1634 /* Avoid race conditions */ 1635 Status = STATUS_PROCESS_IS_TERMINATING; 1636 } 1637 break; 1638 1639 case ProcessBreakOnTermination: 1640 1641 /* Check buffer length */ 1642 if (ProcessInformationLength != sizeof(ULONG)) 1643 { 1644 Status = STATUS_INFO_LENGTH_MISMATCH; 1645 break; 1646 } 1647 1648 /* Enter SEH for direct buffer read */ 1649 _SEH2_TRY 1650 { 1651 Break = *(PULONG)ProcessInformation; 1652 } 1653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1654 { 1655 /* Get exception code */ 1656 Break = 0; 1657 Status = _SEH2_GetExceptionCode(); 1658 _SEH2_YIELD(break); 1659 } 1660 _SEH2_END; 1661 1662 /* Setting 'break on termination' requires the SeDebugPrivilege */ 1663 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) 1664 { 1665 /* We don't hold the privilege, bail out */ 1666 Status = STATUS_PRIVILEGE_NOT_HELD; 1667 break; 1668 } 1669 1670 /* Set or clear the flag */ 1671 if (Break) 1672 { 1673 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT); 1674 } 1675 else 1676 { 1677 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT); 1678 } 1679 1680 break; 1681 1682 case ProcessAffinityMask: 1683 1684 /* Check buffer length */ 1685 if (ProcessInformationLength != sizeof(KAFFINITY)) 1686 { 1687 Status = STATUS_INFO_LENGTH_MISMATCH; 1688 break; 1689 } 1690 1691 /* Enter SEH for direct buffer read */ 1692 _SEH2_TRY 1693 { 1694 Affinity = *(PKAFFINITY)ProcessInformation; 1695 } 1696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1697 { 1698 /* Get exception code */ 1699 Break = 0; 1700 Status = _SEH2_GetExceptionCode(); 1701 _SEH2_YIELD(break); 1702 } 1703 _SEH2_END; 1704 1705 /* Make sure it's valid for the CPUs present */ 1706 ValidAffinity = Affinity & KeActiveProcessors; 1707 if (!Affinity || (ValidAffinity != Affinity)) 1708 { 1709 Status = STATUS_INVALID_PARAMETER; 1710 break; 1711 } 1712 1713 /* Check if it's within job affinity limits */ 1714 if (Process->Job) 1715 { 1716 /* Not yet implemented */ 1717 UNIMPLEMENTED; 1718 Status = STATUS_NOT_IMPLEMENTED; 1719 break; 1720 } 1721 1722 /* Make sure the process isn't dying */ 1723 if (ExAcquireRundownProtection(&Process->RundownProtect)) 1724 { 1725 /* Lock it */ 1726 KeEnterCriticalRegion(); 1727 ExAcquirePushLockShared(&Process->ProcessLock); 1728 1729 /* Call Ke to do the work */ 1730 KeSetAffinityProcess(&Process->Pcb, ValidAffinity); 1731 1732 /* Release the lock and rundown */ 1733 ExReleasePushLockShared(&Process->ProcessLock); 1734 KeLeaveCriticalRegion(); 1735 ExReleaseRundownProtection(&Process->RundownProtect); 1736 1737 /* Set success code */ 1738 Status = STATUS_SUCCESS; 1739 } 1740 else 1741 { 1742 /* Avoid race conditions */ 1743 Status = STATUS_PROCESS_IS_TERMINATING; 1744 } 1745 break; 1746 1747 /* Priority Boosting status */ 1748 case ProcessPriorityBoost: 1749 1750 /* Validate input length */ 1751 if (ProcessInformationLength != sizeof(ULONG)) 1752 { 1753 Status = STATUS_INFO_LENGTH_MISMATCH; 1754 break; 1755 } 1756 1757 /* Enter SEH for direct buffer read */ 1758 _SEH2_TRY 1759 { 1760 DisableBoost = *(PBOOLEAN)ProcessInformation; 1761 } 1762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1763 { 1764 /* Get exception code */ 1765 Break = 0; 1766 Status = _SEH2_GetExceptionCode(); 1767 _SEH2_YIELD(break); 1768 } 1769 _SEH2_END; 1770 1771 /* Make sure the process isn't dying */ 1772 if (ExAcquireRundownProtection(&Process->RundownProtect)) 1773 { 1774 /* Lock it */ 1775 KeEnterCriticalRegion(); 1776 ExAcquirePushLockShared(&Process->ProcessLock); 1777 1778 /* Call Ke to do the work */ 1779 KeSetDisableBoostProcess(&Process->Pcb, DisableBoost); 1780 1781 /* Loop the threads too */ 1782 for (Next = Process->ThreadListHead.Flink; 1783 Next != &Process->ThreadListHead; 1784 Next = Next->Flink) 1785 { 1786 /* Call Ke for the thread */ 1787 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry); 1788 KeSetDisableBoostThread(&Thread->Tcb, DisableBoost); 1789 } 1790 1791 /* Release the lock and rundown */ 1792 ExReleasePushLockShared(&Process->ProcessLock); 1793 KeLeaveCriticalRegion(); 1794 ExReleaseRundownProtection(&Process->RundownProtect); 1795 1796 /* Set success code */ 1797 Status = STATUS_SUCCESS; 1798 } 1799 else 1800 { 1801 /* Avoid race conditions */ 1802 Status = STATUS_PROCESS_IS_TERMINATING; 1803 } 1804 break; 1805 1806 case ProcessDebugFlags: 1807 1808 /* Check buffer length */ 1809 if (ProcessInformationLength != sizeof(ULONG)) 1810 { 1811 Status = STATUS_INFO_LENGTH_MISMATCH; 1812 break; 1813 } 1814 1815 /* Enter SEH for direct buffer read */ 1816 _SEH2_TRY 1817 { 1818 DebugFlags = *(PULONG)ProcessInformation; 1819 } 1820 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1821 { 1822 /* Get exception code */ 1823 Status = _SEH2_GetExceptionCode(); 1824 _SEH2_YIELD(break); 1825 } 1826 _SEH2_END; 1827 1828 /* Set the mode */ 1829 if (DebugFlags & ~1) 1830 { 1831 Status = STATUS_INVALID_PARAMETER; 1832 } 1833 else 1834 { 1835 if (DebugFlags & 1) 1836 { 1837 PspClearProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT); 1838 } 1839 else 1840 { 1841 PspSetProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT); 1842 } 1843 } 1844 1845 /* Done */ 1846 Status = STATUS_SUCCESS; 1847 break; 1848 1849 case ProcessEnableAlignmentFaultFixup: 1850 1851 /* Check buffer length */ 1852 if (ProcessInformationLength != sizeof(ULONG)) 1853 { 1854 Status = STATUS_INFO_LENGTH_MISMATCH; 1855 break; 1856 } 1857 1858 /* Enter SEH for direct buffer read */ 1859 _SEH2_TRY 1860 { 1861 EnableFixup = *(PULONG)ProcessInformation; 1862 } 1863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1864 { 1865 /* Get exception code */ 1866 Status = _SEH2_GetExceptionCode(); 1867 _SEH2_YIELD(break); 1868 } 1869 _SEH2_END; 1870 1871 /* Set the mode */ 1872 if (EnableFixup) 1873 { 1874 Process->DefaultHardErrorProcessing |= SEM_NOALIGNMENTFAULTEXCEPT; 1875 } 1876 else 1877 { 1878 Process->DefaultHardErrorProcessing &= ~SEM_NOALIGNMENTFAULTEXCEPT; 1879 } 1880 1881 /* Call Ke for the update */ 1882 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE); 1883 Status = STATUS_SUCCESS; 1884 break; 1885 1886 case ProcessUserModeIOPL: 1887 1888 /* Only TCB can do this */ 1889 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1890 { 1891 /* We don't hold the privilege, bail out */ 1892 DPRINT1("Need TCB to set IOPL\n"); 1893 Status = STATUS_PRIVILEGE_NOT_HELD; 1894 break; 1895 } 1896 1897 /* Only supported on x86 */ 1898 #if defined (_X86_) 1899 Ke386SetIOPL(); 1900 #elif defined(_M_AMD64) 1901 /* On x64 this function isn't implemented. 1902 On Windows 2003 it returns success. 1903 On Vista+ it returns STATUS_NOT_IMPLEMENTED. */ 1904 if ((ExGetPreviousMode() != KernelMode) && 1905 (RtlRosGetAppcompatVersion() > _WIN32_WINNT_WS03)) 1906 { 1907 Status = STATUS_NOT_IMPLEMENTED; 1908 } 1909 #else 1910 Status = STATUS_NOT_IMPLEMENTED; 1911 #endif 1912 /* Done */ 1913 break; 1914 1915 case ProcessExecuteFlags: 1916 1917 /* Check buffer length */ 1918 if (ProcessInformationLength != sizeof(ULONG)) 1919 { 1920 Status = STATUS_INFO_LENGTH_MISMATCH; 1921 break; 1922 } 1923 1924 if (ProcessHandle != NtCurrentProcess()) 1925 { 1926 Status = STATUS_INVALID_PARAMETER; 1927 break; 1928 } 1929 1930 /* Enter SEH for direct buffer read */ 1931 _SEH2_TRY 1932 { 1933 NoExecute = *(PULONG)ProcessInformation; 1934 } 1935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1936 { 1937 /* Get exception code */ 1938 Status = _SEH2_GetExceptionCode(); 1939 _SEH2_YIELD(break); 1940 } 1941 _SEH2_END; 1942 1943 /* Call Mm for the update */ 1944 Status = MmSetExecuteOptions(NoExecute); 1945 break; 1946 1947 case ProcessDeviceMap: 1948 1949 /* Check buffer length */ 1950 if (ProcessInformationLength != sizeof(HANDLE)) 1951 { 1952 Status = STATUS_INFO_LENGTH_MISMATCH; 1953 break; 1954 } 1955 1956 /* Use SEH for capture */ 1957 _SEH2_TRY 1958 { 1959 /* Capture the handle */ 1960 DirectoryHandle = *(PHANDLE)ProcessInformation; 1961 } 1962 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1963 { 1964 /* Get the exception code */ 1965 Status = _SEH2_GetExceptionCode(); 1966 _SEH2_YIELD(break); 1967 } 1968 _SEH2_END; 1969 1970 /* Call Ob to set the device map */ 1971 Status = ObSetDeviceMap(Process, DirectoryHandle); 1972 break; 1973 1974 1975 /* We currently don't implement any of these */ 1976 case ProcessLdtInformation: 1977 case ProcessLdtSize: 1978 case ProcessIoPortHandlers: 1979 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass); 1980 Status = STATUS_NOT_IMPLEMENTED; 1981 break; 1982 1983 case ProcessQuotaLimits: 1984 1985 Status = PspSetQuotaLimits(Process, 1986 1, 1987 ProcessInformation, 1988 ProcessInformationLength, 1989 PreviousMode); 1990 break; 1991 1992 case ProcessWorkingSetWatch: 1993 DPRINT1("WS watch not implemented\n"); 1994 Status = STATUS_NOT_IMPLEMENTED; 1995 break; 1996 1997 case ProcessHandleTracing: 1998 DPRINT1("Handle tracing not implemented\n"); 1999 Status = STATUS_NOT_IMPLEMENTED; 2000 break; 2001 2002 /* Anything else is invalid */ 2003 default: 2004 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass); 2005 Status = STATUS_INVALID_INFO_CLASS; 2006 } 2007 2008 /* Dereference and return status */ 2009 ObDereferenceObject(Process); 2010 return Status; 2011 } 2012 2013 /* 2014 * @implemented 2015 */ 2016 NTSTATUS 2017 NTAPI 2018 NtSetInformationThread(IN HANDLE ThreadHandle, 2019 IN THREADINFOCLASS ThreadInformationClass, 2020 IN PVOID ThreadInformation, 2021 IN ULONG ThreadInformationLength) 2022 { 2023 PETHREAD Thread; 2024 ULONG Access; 2025 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2026 NTSTATUS Status; 2027 HANDLE TokenHandle = NULL; 2028 KPRIORITY Priority = 0; 2029 KAFFINITY Affinity = 0, CombinedAffinity; 2030 PVOID Address = NULL; 2031 PEPROCESS Process; 2032 ULONG_PTR DisableBoost = 0; 2033 ULONG_PTR IdealProcessor = 0; 2034 ULONG_PTR Break = 0; 2035 PTEB Teb; 2036 ULONG_PTR TlsIndex = 0; 2037 PVOID *ExpansionSlots; 2038 PETHREAD ProcThread; 2039 PAGED_CODE(); 2040 2041 /* Verify Information Class validity */ 2042 #if 0 2043 Status = DefaultSetInfoBufferCheck(ThreadInformationClass, 2044 PsThreadInfoClass, 2045 RTL_NUMBER_OF(PsThreadInfoClass), 2046 ThreadInformation, 2047 ThreadInformationLength, 2048 PreviousMode); 2049 if (!NT_SUCCESS(Status)) return Status; 2050 #endif 2051 2052 /* Check what class this is */ 2053 Access = THREAD_SET_INFORMATION; 2054 if (ThreadInformationClass == ThreadImpersonationToken) 2055 { 2056 /* Setting the impersonation token needs a special mask */ 2057 Access = THREAD_SET_THREAD_TOKEN; 2058 } 2059 2060 /* Reference the thread */ 2061 Status = ObReferenceObjectByHandle(ThreadHandle, 2062 Access, 2063 PsThreadType, 2064 PreviousMode, 2065 (PVOID*)&Thread, 2066 NULL); 2067 if (!NT_SUCCESS(Status)) return Status; 2068 2069 /* Check what kind of information class this is */ 2070 switch (ThreadInformationClass) 2071 { 2072 /* Thread priority */ 2073 case ThreadPriority: 2074 2075 /* Check buffer length */ 2076 if (ThreadInformationLength != sizeof(KPRIORITY)) 2077 { 2078 Status = STATUS_INFO_LENGTH_MISMATCH; 2079 break; 2080 } 2081 2082 /* Use SEH for capture */ 2083 _SEH2_TRY 2084 { 2085 /* Get the priority */ 2086 Priority = *(PLONG)ThreadInformation; 2087 } 2088 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2089 { 2090 /* Get the exception code */ 2091 Status = _SEH2_GetExceptionCode(); 2092 _SEH2_YIELD(break); 2093 } 2094 _SEH2_END; 2095 2096 /* Validate it */ 2097 if ((Priority > HIGH_PRIORITY) || 2098 (Priority <= LOW_PRIORITY)) 2099 { 2100 /* Fail */ 2101 Status = STATUS_INVALID_PARAMETER; 2102 break; 2103 } 2104 2105 /* Set the priority */ 2106 KeSetPriorityThread(&Thread->Tcb, Priority); 2107 break; 2108 2109 case ThreadBasePriority: 2110 2111 /* Check buffer length */ 2112 if (ThreadInformationLength != sizeof(LONG)) 2113 { 2114 Status = STATUS_INFO_LENGTH_MISMATCH; 2115 break; 2116 } 2117 2118 /* Use SEH for capture */ 2119 _SEH2_TRY 2120 { 2121 /* Get the priority */ 2122 Priority = *(PLONG)ThreadInformation; 2123 } 2124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2125 { 2126 /* Get the exception code */ 2127 Status = _SEH2_GetExceptionCode(); 2128 _SEH2_YIELD(break); 2129 } 2130 _SEH2_END; 2131 2132 /* Validate it */ 2133 if ((Priority > THREAD_BASE_PRIORITY_MAX) || 2134 (Priority < THREAD_BASE_PRIORITY_MIN)) 2135 { 2136 /* These ones are OK */ 2137 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) && 2138 (Priority != THREAD_BASE_PRIORITY_IDLE - 1)) 2139 { 2140 /* Check if the process is real time */ 2141 if (PsGetCurrentProcess()->PriorityClass != 2142 PROCESS_PRIORITY_CLASS_REALTIME) 2143 { 2144 /* It isn't, fail */ 2145 Status = STATUS_INVALID_PARAMETER; 2146 break; 2147 } 2148 } 2149 } 2150 2151 /* Set the base priority */ 2152 KeSetBasePriorityThread(&Thread->Tcb, Priority); 2153 break; 2154 2155 case ThreadAffinityMask: 2156 2157 /* Check buffer length */ 2158 if (ThreadInformationLength != sizeof(ULONG_PTR)) 2159 { 2160 Status = STATUS_INFO_LENGTH_MISMATCH; 2161 break; 2162 } 2163 2164 /* Use SEH for capture */ 2165 _SEH2_TRY 2166 { 2167 /* Get the priority */ 2168 Affinity = *(PULONG_PTR)ThreadInformation; 2169 } 2170 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2171 { 2172 /* Get the exception code */ 2173 Status = _SEH2_GetExceptionCode(); 2174 _SEH2_YIELD(break); 2175 } 2176 _SEH2_END; 2177 2178 /* Validate it */ 2179 if (!Affinity) 2180 { 2181 /* Fail */ 2182 Status = STATUS_INVALID_PARAMETER; 2183 break; 2184 } 2185 2186 /* Get the process */ 2187 Process = Thread->ThreadsProcess; 2188 2189 /* Try to acquire rundown */ 2190 if (ExAcquireRundownProtection(&Process->RundownProtect)) 2191 { 2192 /* Lock it */ 2193 KeEnterCriticalRegion(); 2194 ExAcquirePushLockShared(&Process->ProcessLock); 2195 2196 /* Combine masks */ 2197 CombinedAffinity = Affinity & Process->Pcb.Affinity; 2198 if (CombinedAffinity != Affinity) 2199 { 2200 /* Fail */ 2201 Status = STATUS_INVALID_PARAMETER; 2202 } 2203 else 2204 { 2205 /* Set the affinity */ 2206 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity); 2207 } 2208 2209 /* Release the lock and rundown */ 2210 ExReleasePushLockShared(&Process->ProcessLock); 2211 KeLeaveCriticalRegion(); 2212 ExReleaseRundownProtection(&Process->RundownProtect); 2213 } 2214 else 2215 { 2216 /* Too late */ 2217 Status = STATUS_PROCESS_IS_TERMINATING; 2218 } 2219 2220 /* Return status */ 2221 break; 2222 2223 case ThreadImpersonationToken: 2224 2225 /* Check buffer length */ 2226 if (ThreadInformationLength != sizeof(HANDLE)) 2227 { 2228 Status = STATUS_INFO_LENGTH_MISMATCH; 2229 break; 2230 } 2231 2232 /* Use SEH for capture */ 2233 _SEH2_TRY 2234 { 2235 /* Save the token handle */ 2236 TokenHandle = *(PHANDLE)ThreadInformation; 2237 } 2238 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2239 { 2240 /* Get the exception code */ 2241 Status = _SEH2_GetExceptionCode(); 2242 _SEH2_YIELD(break); 2243 } 2244 _SEH2_END; 2245 2246 /* Assign the actual token */ 2247 Status = PsAssignImpersonationToken(Thread, TokenHandle); 2248 break; 2249 2250 case ThreadQuerySetWin32StartAddress: 2251 2252 /* Check buffer length */ 2253 if (ThreadInformationLength != sizeof(ULONG_PTR)) 2254 { 2255 Status = STATUS_INFO_LENGTH_MISMATCH; 2256 break; 2257 } 2258 2259 /* Use SEH for capture */ 2260 _SEH2_TRY 2261 { 2262 /* Get the priority */ 2263 Address = *(PVOID*)ThreadInformation; 2264 } 2265 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2266 { 2267 /* Get the exception code */ 2268 Status = _SEH2_GetExceptionCode(); 2269 _SEH2_YIELD(break); 2270 } 2271 _SEH2_END; 2272 2273 /* Set the address */ 2274 Thread->Win32StartAddress = Address; 2275 break; 2276 2277 case ThreadIdealProcessor: 2278 2279 /* Check buffer length */ 2280 if (ThreadInformationLength != sizeof(ULONG_PTR)) 2281 { 2282 Status = STATUS_INFO_LENGTH_MISMATCH; 2283 break; 2284 } 2285 2286 /* Use SEH for capture */ 2287 _SEH2_TRY 2288 { 2289 /* Get the priority */ 2290 IdealProcessor = *(PULONG_PTR)ThreadInformation; 2291 } 2292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2293 { 2294 /* Get the exception code */ 2295 Status = _SEH2_GetExceptionCode(); 2296 _SEH2_YIELD(break); 2297 } 2298 _SEH2_END; 2299 2300 /* Validate it */ 2301 if (IdealProcessor > MAXIMUM_PROCESSORS) 2302 { 2303 /* Fail */ 2304 Status = STATUS_INVALID_PARAMETER; 2305 break; 2306 } 2307 2308 /* Set the ideal */ 2309 Status = KeSetIdealProcessorThread(&Thread->Tcb, 2310 (CCHAR)IdealProcessor); 2311 2312 /* Get the TEB and protect the thread */ 2313 Teb = Thread->Tcb.Teb; 2314 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect))) 2315 { 2316 /* Save the ideal processor */ 2317 Teb->IdealProcessor = Thread->Tcb.IdealProcessor; 2318 2319 /* Release rundown protection */ 2320 ExReleaseRundownProtection(&Thread->RundownProtect); 2321 } 2322 2323 break; 2324 2325 case ThreadPriorityBoost: 2326 2327 /* Check buffer length */ 2328 if (ThreadInformationLength != sizeof(ULONG_PTR)) 2329 { 2330 Status = STATUS_INFO_LENGTH_MISMATCH; 2331 break; 2332 } 2333 2334 /* Use SEH for capture */ 2335 _SEH2_TRY 2336 { 2337 /* Get the priority */ 2338 DisableBoost = *(PULONG_PTR)ThreadInformation; 2339 } 2340 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2341 { 2342 /* Get the exception code */ 2343 Status = _SEH2_GetExceptionCode(); 2344 _SEH2_YIELD(break); 2345 } 2346 _SEH2_END; 2347 2348 /* Call the kernel */ 2349 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost); 2350 break; 2351 2352 case ThreadZeroTlsCell: 2353 2354 /* Check buffer length */ 2355 if (ThreadInformationLength != sizeof(ULONG_PTR)) 2356 { 2357 Status = STATUS_INFO_LENGTH_MISMATCH; 2358 break; 2359 } 2360 2361 /* Use SEH for capture */ 2362 _SEH2_TRY 2363 { 2364 /* Get the priority */ 2365 TlsIndex = *(PULONG_PTR)ThreadInformation; 2366 } 2367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2368 { 2369 /* Get the exception code */ 2370 Status = _SEH2_GetExceptionCode(); 2371 _SEH2_YIELD(break); 2372 } 2373 _SEH2_END; 2374 2375 /* This is only valid for the current thread */ 2376 if (Thread != PsGetCurrentThread()) 2377 { 2378 /* Fail */ 2379 Status = STATUS_INVALID_PARAMETER; 2380 break; 2381 } 2382 2383 /* Get the process */ 2384 Process = Thread->ThreadsProcess; 2385 2386 /* Loop the threads */ 2387 ProcThread = PsGetNextProcessThread(Process, NULL); 2388 while (ProcThread) 2389 { 2390 /* Acquire rundown */ 2391 if (ExAcquireRundownProtection(&ProcThread->RundownProtect)) 2392 { 2393 /* Get the TEB */ 2394 Teb = ProcThread->Tcb.Teb; 2395 if (Teb) 2396 { 2397 /* Check if we're in the expansion range */ 2398 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1) 2399 { 2400 if (TlsIndex < (TLS_MINIMUM_AVAILABLE + 2401 TLS_EXPANSION_SLOTS) - 1) 2402 { 2403 /* Check if we have expansion slots */ 2404 ExpansionSlots = Teb->TlsExpansionSlots; 2405 if (ExpansionSlots) 2406 { 2407 /* Clear the index */ 2408 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0; 2409 } 2410 } 2411 } 2412 else 2413 { 2414 /* Clear the index */ 2415 Teb->TlsSlots[TlsIndex] = NULL; 2416 } 2417 } 2418 2419 /* Release rundown */ 2420 ExReleaseRundownProtection(&ProcThread->RundownProtect); 2421 } 2422 2423 /* Go to the next thread */ 2424 ProcThread = PsGetNextProcessThread(Process, ProcThread); 2425 } 2426 2427 /* All done */ 2428 break; 2429 2430 case ThreadBreakOnTermination: 2431 2432 /* Check buffer length */ 2433 if (ThreadInformationLength != sizeof(ULONG)) 2434 { 2435 Status = STATUS_INFO_LENGTH_MISMATCH; 2436 break; 2437 } 2438 2439 /* Enter SEH for direct buffer read */ 2440 _SEH2_TRY 2441 { 2442 Break = *(PULONG)ThreadInformation; 2443 } 2444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2445 { 2446 /* Get exception code */ 2447 Break = 0; 2448 Status = _SEH2_GetExceptionCode(); 2449 _SEH2_YIELD(break); 2450 } 2451 _SEH2_END; 2452 2453 /* Setting 'break on termination' requires the SeDebugPrivilege */ 2454 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode)) 2455 { 2456 /* We don't hold the privilege, bail out */ 2457 Status = STATUS_PRIVILEGE_NOT_HELD; 2458 break; 2459 } 2460 2461 /* Set or clear the flag */ 2462 if (Break) 2463 { 2464 PspSetCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT); 2465 } 2466 else 2467 { 2468 PspClearCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT); 2469 } 2470 break; 2471 2472 case ThreadHideFromDebugger: 2473 2474 /* Check buffer length */ 2475 if (ThreadInformationLength != 0) 2476 { 2477 Status = STATUS_INFO_LENGTH_MISMATCH; 2478 break; 2479 } 2480 2481 /* Set the flag */ 2482 PspSetCrossThreadFlag(Thread, CT_HIDE_FROM_DEBUGGER_BIT); 2483 break; 2484 2485 default: 2486 /* We don't implement it yet */ 2487 DPRINT1("Not implemented: %d\n", ThreadInformationClass); 2488 Status = STATUS_NOT_IMPLEMENTED; 2489 } 2490 2491 /* Dereference and return status */ 2492 ObDereferenceObject(Thread); 2493 return Status; 2494 } 2495 2496 /* 2497 * @implemented 2498 */ 2499 NTSTATUS 2500 NTAPI 2501 NtQueryInformationThread(IN HANDLE ThreadHandle, 2502 IN THREADINFOCLASS ThreadInformationClass, 2503 OUT PVOID ThreadInformation, 2504 IN ULONG ThreadInformationLength, 2505 OUT PULONG ReturnLength OPTIONAL) 2506 { 2507 PETHREAD Thread; 2508 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 2509 NTSTATUS Status; 2510 ULONG Access; 2511 ULONG Length = 0; 2512 PTHREAD_BASIC_INFORMATION ThreadBasicInfo = 2513 (PTHREAD_BASIC_INFORMATION)ThreadInformation; 2514 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation; 2515 KIRQL OldIrql; 2516 ULONG ThreadTerminated; 2517 PAGED_CODE(); 2518 2519 /* Check if we were called from user mode */ 2520 if (PreviousMode != KernelMode) 2521 { 2522 /* Enter SEH */ 2523 _SEH2_TRY 2524 { 2525 /* Probe the buffer */ 2526 ProbeForWrite(ThreadInformation, 2527 ThreadInformationLength, 2528 sizeof(ULONG)); 2529 2530 /* Probe the return length if required */ 2531 if (ReturnLength) ProbeForWriteUlong(ReturnLength); 2532 } 2533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2534 { 2535 /* Return the exception code */ 2536 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 2537 } 2538 _SEH2_END; 2539 } 2540 2541 /* Check what class this is */ 2542 Access = THREAD_QUERY_INFORMATION; 2543 2544 /* Reference the process */ 2545 Status = ObReferenceObjectByHandle(ThreadHandle, 2546 Access, 2547 PsThreadType, 2548 PreviousMode, 2549 (PVOID*)&Thread, 2550 NULL); 2551 if (!NT_SUCCESS(Status)) return Status; 2552 2553 /* Check what kind of information class this is */ 2554 switch (ThreadInformationClass) 2555 { 2556 /* Basic thread information */ 2557 case ThreadBasicInformation: 2558 2559 /* Set return length */ 2560 Length = sizeof(THREAD_BASIC_INFORMATION); 2561 2562 if (ThreadInformationLength != Length) 2563 { 2564 Status = STATUS_INFO_LENGTH_MISMATCH; 2565 break; 2566 } 2567 /* Protect writes with SEH */ 2568 _SEH2_TRY 2569 { 2570 /* Write all the information from the ETHREAD/KTHREAD */ 2571 ThreadBasicInfo->ExitStatus = Thread->ExitStatus; 2572 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb; 2573 ThreadBasicInfo->ClientId = Thread->Cid; 2574 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity; 2575 ThreadBasicInfo->Priority = Thread->Tcb.Priority; 2576 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb); 2577 } 2578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2579 { 2580 /* Get exception code */ 2581 Status = _SEH2_GetExceptionCode(); 2582 } 2583 _SEH2_END; 2584 break; 2585 2586 /* Thread time information */ 2587 case ThreadTimes: 2588 2589 /* Set the return length */ 2590 Length = sizeof(KERNEL_USER_TIMES); 2591 2592 if (ThreadInformationLength != Length) 2593 { 2594 Status = STATUS_INFO_LENGTH_MISMATCH; 2595 break; 2596 } 2597 /* Protect writes with SEH */ 2598 _SEH2_TRY 2599 { 2600 /* Copy time information from ETHREAD/KTHREAD */ 2601 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime * KeMaximumIncrement; 2602 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime * KeMaximumIncrement; 2603 ThreadTime->CreateTime = Thread->CreateTime; 2604 2605 /* Exit time is in a union and only valid on actual exit! */ 2606 if (KeReadStateThread(&Thread->Tcb)) 2607 { 2608 ThreadTime->ExitTime = Thread->ExitTime; 2609 } 2610 else 2611 { 2612 ThreadTime->ExitTime.QuadPart = 0; 2613 } 2614 } 2615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2616 { 2617 /* Get exception code */ 2618 Status = _SEH2_GetExceptionCode(); 2619 } 2620 _SEH2_END; 2621 break; 2622 2623 case ThreadQuerySetWin32StartAddress: 2624 2625 /* Set the return length*/ 2626 Length = sizeof(PVOID); 2627 2628 if (ThreadInformationLength != Length) 2629 { 2630 Status = STATUS_INFO_LENGTH_MISMATCH; 2631 break; 2632 } 2633 /* Protect write with SEH */ 2634 _SEH2_TRY 2635 { 2636 /* Return the Win32 Start Address */ 2637 *(PVOID*)ThreadInformation = Thread->Win32StartAddress; 2638 } 2639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2640 { 2641 /* Get exception code */ 2642 Status = _SEH2_GetExceptionCode(); 2643 } 2644 _SEH2_END; 2645 break; 2646 2647 case ThreadPerformanceCount: 2648 2649 /* Set the return length*/ 2650 Length = sizeof(LARGE_INTEGER); 2651 2652 if (ThreadInformationLength != Length) 2653 { 2654 Status = STATUS_INFO_LENGTH_MISMATCH; 2655 break; 2656 } 2657 /* Protect write with SEH */ 2658 _SEH2_TRY 2659 { 2660 /* FIXME */ 2661 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0; 2662 } 2663 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2664 { 2665 /* Get exception code */ 2666 Status = _SEH2_GetExceptionCode(); 2667 } 2668 _SEH2_END; 2669 break; 2670 2671 case ThreadAmILastThread: 2672 2673 /* Set the return length*/ 2674 Length = sizeof(ULONG); 2675 2676 if (ThreadInformationLength != Length) 2677 { 2678 Status = STATUS_INFO_LENGTH_MISMATCH; 2679 break; 2680 } 2681 /* Protect write with SEH */ 2682 _SEH2_TRY 2683 { 2684 /* Return whether or not we are the last thread */ 2685 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess-> 2686 ThreadListHead.Flink->Flink == 2687 &Thread->ThreadsProcess-> 2688 ThreadListHead) ? 2689 TRUE : FALSE); 2690 } 2691 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2692 { 2693 /* Get exception code */ 2694 Status = _SEH2_GetExceptionCode(); 2695 } 2696 _SEH2_END; 2697 break; 2698 2699 case ThreadIsIoPending: 2700 2701 /* Set the return length*/ 2702 Length = sizeof(ULONG); 2703 2704 if (ThreadInformationLength != Length) 2705 { 2706 Status = STATUS_INFO_LENGTH_MISMATCH; 2707 break; 2708 } 2709 /* Raise the IRQL to protect the IRP list */ 2710 KeRaiseIrql(APC_LEVEL, &OldIrql); 2711 2712 /* Protect write with SEH */ 2713 _SEH2_TRY 2714 { 2715 /* Check if the IRP list is empty or not */ 2716 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList); 2717 } 2718 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2719 { 2720 /* Get exception code */ 2721 Status = _SEH2_GetExceptionCode(); 2722 } 2723 _SEH2_END; 2724 2725 /* Lower IRQL back */ 2726 KeLowerIrql(OldIrql); 2727 break; 2728 2729 /* LDT and GDT information */ 2730 case ThreadDescriptorTableEntry: 2731 2732 #if defined(_X86_) 2733 /* Call the worker routine */ 2734 Status = PspQueryDescriptorThread(Thread, 2735 ThreadInformation, 2736 ThreadInformationLength, 2737 ReturnLength); 2738 #else 2739 /* Only implemented on x86 */ 2740 Status = STATUS_NOT_IMPLEMENTED; 2741 #endif 2742 break; 2743 2744 case ThreadPriorityBoost: 2745 2746 /* Set the return length*/ 2747 Length = sizeof(ULONG); 2748 2749 if (ThreadInformationLength != Length) 2750 { 2751 Status = STATUS_INFO_LENGTH_MISMATCH; 2752 break; 2753 } 2754 2755 _SEH2_TRY 2756 { 2757 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0; 2758 } 2759 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2760 { 2761 Status = _SEH2_GetExceptionCode(); 2762 } 2763 _SEH2_END; 2764 break; 2765 2766 case ThreadIsTerminated: 2767 2768 /* Set the return length*/ 2769 Length = sizeof(ThreadTerminated); 2770 2771 if (ThreadInformationLength != Length) 2772 { 2773 Status = STATUS_INFO_LENGTH_MISMATCH; 2774 break; 2775 } 2776 2777 ThreadTerminated = PsIsThreadTerminating(Thread); 2778 2779 _SEH2_TRY 2780 { 2781 *(PULONG)ThreadInformation = ThreadTerminated ? 1 : 0; 2782 } 2783 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2784 { 2785 Status = _SEH2_GetExceptionCode(); 2786 } 2787 _SEH2_END; 2788 2789 break; 2790 2791 /* Anything else */ 2792 default: 2793 2794 /* Not yet implemented */ 2795 DPRINT1("Not implemented: %lx\n", ThreadInformationClass); 2796 Status = STATUS_NOT_IMPLEMENTED; 2797 } 2798 2799 /* Protect write with SEH */ 2800 _SEH2_TRY 2801 { 2802 /* Check if caller wanted return length */ 2803 if (ReturnLength) *ReturnLength = Length; 2804 } 2805 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2806 { 2807 /* Get exception code */ 2808 Status = _SEH2_GetExceptionCode(); 2809 } 2810 _SEH2_END; 2811 2812 /* Dereference the thread, and return */ 2813 ObDereferenceObject(Thread); 2814 return Status; 2815 } 2816 2817 /* EOF */ 2818