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