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