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