* Sync up to trunk head (r60691).
[reactos.git] / 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 = 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 /* We don't hold the privilege, 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 /* We don't hold the privilege, 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 /* We don't hold the privilege, bail out */
1336 Status = STATUS_PRIVILEGE_NOT_HELD;
1337 break;
1338 }
1339
1340 #if 0 // OLD AND DEPRECATED CODE!!!!
1341
1342 /* FIXME - update the session id for the process token */
1343 //Status = PsLockProcess(Process, FALSE);
1344 if (!NT_SUCCESS(Status)) break;
1345
1346 /* Write the session ID in the EPROCESS */
1347 Process->Session = UlongToPtr(SessionInfo.SessionId); // HACK!!!
1348
1349 /* Check if the process also has a PEB */
1350 if (Process->Peb)
1351 {
1352 /*
1353 * Attach to the process to make sure we're in the right
1354 * context to access the PEB structure
1355 */
1356 KeAttachProcess(&Process->Pcb);
1357
1358 /* Enter SEH for write to user-mode PEB */
1359 _SEH2_TRY
1360 {
1361 /* Write the session ID */
1362 Process->Peb->SessionId = SessionInfo.SessionId;
1363 }
1364 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1365 {
1366 /* Get exception code */
1367 Status = _SEH2_GetExceptionCode();
1368 }
1369 _SEH2_END;
1370
1371 /* Detach from the process */
1372 KeDetachProcess();
1373 }
1374
1375 /* Unlock the process */
1376 //PsUnlockProcess(Process);
1377
1378 #endif
1379
1380 /*
1381 * Since we cannot change the session ID of the given
1382 * process anymore because it is set once and for all
1383 * at process creation time and because it is stored
1384 * inside the Process->Session structure managed by MM,
1385 * we fake changing it: we just return success if the
1386 * user-defined value is the same as the session ID of
1387 * the process, and otherwise we fail.
1388 */
1389 if (SessionInfo.SessionId == PsGetProcessSessionId(Process))
1390 {
1391 Status = STATUS_SUCCESS;
1392 }
1393 else
1394 {
1395 Status = STATUS_ACCESS_DENIED;
1396 }
1397
1398 break;
1399
1400 case ProcessPriorityClass:
1401
1402 /* Check buffer length */
1403 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1404 {
1405 Status = STATUS_INFO_LENGTH_MISMATCH;
1406 break;
1407 }
1408
1409 /* Enter SEH for capture */
1410 _SEH2_TRY
1411 {
1412 /* Capture the caller's buffer */
1413 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1414 }
1415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1416 {
1417 /* Return the exception code */
1418 Status = _SEH2_GetExceptionCode();
1419 _SEH2_YIELD(break);
1420 }
1421 _SEH2_END;
1422
1423 /* Check for invalid PriorityClass value */
1424 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1425 {
1426 Status = STATUS_INVALID_PARAMETER;
1427 break;
1428 }
1429
1430 if ((PriorityClass.PriorityClass != Process->PriorityClass) &&
1431 (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME))
1432 {
1433 /* Check the privilege */
1434 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1435 ProcessHandle,
1436 PROCESS_SET_INFORMATION,
1437 PreviousMode);
1438 if (!HasPrivilege)
1439 {
1440 ObDereferenceObject(Process);
1441 DPRINT1("Privilege to change priority to realtime lacking\n");
1442 return STATUS_PRIVILEGE_NOT_HELD;
1443 }
1444 }
1445
1446 /* Check if we have a job */
1447 if (Process->Job)
1448 {
1449 DPRINT1("Jobs not yet supported\n");
1450 }
1451
1452 /* Set process priority class */
1453 Process->PriorityClass = PriorityClass.PriorityClass;
1454
1455 /* Set process priority mode (foreground or background) */
1456 PsSetProcessPriorityByClass(Process,
1457 PriorityClass.Foreground ?
1458 PsProcessPriorityForeground :
1459 PsProcessPriorityBackground);
1460 Status = STATUS_SUCCESS;
1461 break;
1462
1463 case ProcessForegroundInformation:
1464
1465 /* Check buffer length */
1466 if (ProcessInformationLength != sizeof(PROCESS_FOREGROUND_BACKGROUND))
1467 {
1468 Status = STATUS_INFO_LENGTH_MISMATCH;
1469 break;
1470 }
1471
1472 /* Enter SEH for capture */
1473 _SEH2_TRY
1474 {
1475 /* Capture the caller's buffer */
1476 Foreground = *(PPROCESS_FOREGROUND_BACKGROUND)ProcessInformation;
1477 }
1478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1479 {
1480 /* Return the exception code */
1481 Status = _SEH2_GetExceptionCode();
1482 _SEH2_YIELD(break);
1483 }
1484 _SEH2_END;
1485
1486 /* Set process priority mode (foreground or background) */
1487 PsSetProcessPriorityByClass(Process,
1488 Foreground.Foreground ?
1489 PsProcessPriorityForeground :
1490 PsProcessPriorityBackground);
1491 Status = STATUS_SUCCESS;
1492 break;
1493
1494 case ProcessBasePriority:
1495
1496 /* Validate input length */
1497 if (ProcessInformationLength != sizeof(KPRIORITY))
1498 {
1499 Status = STATUS_INFO_LENGTH_MISMATCH;
1500 break;
1501 }
1502
1503 /* Enter SEH for direct buffer read */
1504 _SEH2_TRY
1505 {
1506 BasePriority = *(KPRIORITY*)ProcessInformation;
1507 }
1508 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1509 {
1510 /* Get exception code */
1511 Break = 0;
1512 Status = _SEH2_GetExceptionCode();
1513 _SEH2_YIELD(break);
1514 }
1515 _SEH2_END;
1516
1517 /* Extract the memory priority out of there */
1518 if (BasePriority & 0x80000000)
1519 {
1520 MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
1521 BasePriority &= ~0x80000000;
1522 }
1523 else
1524 {
1525 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
1526 }
1527
1528 /* Validate the number */
1529 if ((BasePriority > HIGH_PRIORITY) || (BasePriority <= LOW_PRIORITY))
1530 {
1531 return STATUS_INVALID_PARAMETER;
1532 }
1533
1534 /* Check if the new base is higher */
1535 if (BasePriority > Process->Pcb.BasePriority)
1536 {
1537 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1538 ProcessHandle,
1539 PROCESS_SET_INFORMATION,
1540 PreviousMode);
1541 if (!HasPrivilege)
1542 {
1543 ObDereferenceObject(Process);
1544 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority, Process->Pcb.BasePriority);
1545 return STATUS_PRIVILEGE_NOT_HELD;
1546 }
1547 }
1548
1549 /* Call Ke */
1550 KeSetPriorityAndQuantumProcess(&Process->Pcb, BasePriority, 0);
1551
1552 /* Now set the memory priority */
1553 MmSetMemoryPriorityProcess(Process, MemoryPriority);
1554 Status = STATUS_SUCCESS;
1555 break;
1556
1557 case ProcessRaisePriority:
1558
1559 /* Validate input length */
1560 if (ProcessInformationLength != sizeof(ULONG))
1561 {
1562 Status = STATUS_INFO_LENGTH_MISMATCH;
1563 break;
1564 }
1565
1566 /* Enter SEH for direct buffer read */
1567 _SEH2_TRY
1568 {
1569 Boost = *(PULONG)ProcessInformation;
1570 }
1571 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1572 {
1573 /* Get exception code */
1574 Break = 0;
1575 Status = _SEH2_GetExceptionCode();
1576 _SEH2_YIELD(break);
1577 }
1578 _SEH2_END;
1579
1580 /* Make sure the process isn't dying */
1581 if (ExAcquireRundownProtection(&Process->RundownProtect))
1582 {
1583 /* Lock it */
1584 KeEnterCriticalRegion();
1585 ExAcquirePushLockShared(&Process->ProcessLock);
1586
1587 /* Loop the threads */
1588 for (Next = Process->ThreadListHead.Flink;
1589 Next != &Process->ThreadListHead;
1590 Next = Next->Flink)
1591 {
1592 /* Call Ke for the thread */
1593 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1594 KeBoostPriorityThread(&Thread->Tcb, Boost);
1595 }
1596
1597 /* Release the lock and rundown */
1598 ExReleasePushLockShared(&Process->ProcessLock);
1599 KeLeaveCriticalRegion();
1600 ExReleaseRundownProtection(&Process->RundownProtect);
1601
1602 /* Set success code */
1603 Status = STATUS_SUCCESS;
1604 }
1605 else
1606 {
1607 /* Avoid race conditions */
1608 Status = STATUS_PROCESS_IS_TERMINATING;
1609 }
1610 break;
1611
1612 case ProcessBreakOnTermination:
1613
1614 /* Check buffer length */
1615 if (ProcessInformationLength != sizeof(ULONG))
1616 {
1617 Status = STATUS_INFO_LENGTH_MISMATCH;
1618 break;
1619 }
1620
1621 /* Enter SEH for direct buffer read */
1622 _SEH2_TRY
1623 {
1624 Break = *(PULONG)ProcessInformation;
1625 }
1626 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1627 {
1628 /* Get exception code */
1629 Break = 0;
1630 Status = _SEH2_GetExceptionCode();
1631 _SEH2_YIELD(break);
1632 }
1633 _SEH2_END;
1634
1635 /* Setting 'break on termination' requires the SeDebugPrivilege */
1636 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1637 {
1638 /* We don't hold the privilege, bail out */
1639 Status = STATUS_PRIVILEGE_NOT_HELD;
1640 break;
1641 }
1642
1643 /* Set or clear the flag */
1644 if (Break)
1645 {
1646 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1647 }
1648 else
1649 {
1650 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1651 }
1652
1653 break;
1654
1655 case ProcessAffinityMask:
1656
1657 /* Check buffer length */
1658 if (ProcessInformationLength != sizeof(KAFFINITY))
1659 {
1660 Status = STATUS_INFO_LENGTH_MISMATCH;
1661 break;
1662 }
1663
1664 /* Enter SEH for direct buffer read */
1665 _SEH2_TRY
1666 {
1667 Affinity = *(PKAFFINITY)ProcessInformation;
1668 }
1669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1670 {
1671 /* Get exception code */
1672 Break = 0;
1673 Status = _SEH2_GetExceptionCode();
1674 _SEH2_YIELD(break);
1675 }
1676 _SEH2_END;
1677
1678 /* Make sure it's valid for the CPUs present */
1679 ValidAffinity = Affinity & KeActiveProcessors;
1680 if (!Affinity || (ValidAffinity != Affinity))
1681 {
1682 Status = STATUS_INVALID_PARAMETER;
1683 break;
1684 }
1685
1686 /* Check if it's within job affinity limits */
1687 if (Process->Job)
1688 {
1689 /* Not yet implemented */
1690 UNIMPLEMENTED;
1691 Status = STATUS_NOT_IMPLEMENTED;
1692 break;
1693 }
1694
1695 /* Make sure the process isn't dying */
1696 if (ExAcquireRundownProtection(&Process->RundownProtect))
1697 {
1698 /* Lock it */
1699 KeEnterCriticalRegion();
1700 ExAcquirePushLockShared(&Process->ProcessLock);
1701
1702 /* Call Ke to do the work */
1703 KeSetAffinityProcess(&Process->Pcb, ValidAffinity);
1704
1705 /* Release the lock and rundown */
1706 ExReleasePushLockShared(&Process->ProcessLock);
1707 KeLeaveCriticalRegion();
1708 ExReleaseRundownProtection(&Process->RundownProtect);
1709
1710 /* Set success code */
1711 Status = STATUS_SUCCESS;
1712 }
1713 else
1714 {
1715 /* Avoid race conditions */
1716 Status = STATUS_PROCESS_IS_TERMINATING;
1717 }
1718 break;
1719
1720 /* Priority Boosting status */
1721 case ProcessPriorityBoost:
1722
1723 /* Validate input length */
1724 if (ProcessInformationLength != sizeof(ULONG))
1725 {
1726 Status = STATUS_INFO_LENGTH_MISMATCH;
1727 break;
1728 }
1729
1730 /* Enter SEH for direct buffer read */
1731 _SEH2_TRY
1732 {
1733 DisableBoost = *(PBOOLEAN)ProcessInformation;
1734 }
1735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1736 {
1737 /* Get exception code */
1738 Break = 0;
1739 Status = _SEH2_GetExceptionCode();
1740 _SEH2_YIELD(break);
1741 }
1742 _SEH2_END;
1743
1744 /* Make sure the process isn't dying */
1745 if (ExAcquireRundownProtection(&Process->RundownProtect))
1746 {
1747 /* Lock it */
1748 KeEnterCriticalRegion();
1749 ExAcquirePushLockShared(&Process->ProcessLock);
1750
1751 /* Call Ke to do the work */
1752 KeSetDisableBoostProcess(&Process->Pcb, DisableBoost);
1753
1754 /* Loop the threads too */
1755 for (Next = Process->ThreadListHead.Flink;
1756 Next != &Process->ThreadListHead;
1757 Next = Next->Flink)
1758 {
1759 /* Call Ke for the thread */
1760 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1761 KeSetDisableBoostThread(&Thread->Tcb, DisableBoost);
1762 }
1763
1764 /* Release the lock and rundown */
1765 ExReleasePushLockShared(&Process->ProcessLock);
1766 KeLeaveCriticalRegion();
1767 ExReleaseRundownProtection(&Process->RundownProtect);
1768
1769 /* Set success code */
1770 Status = STATUS_SUCCESS;
1771 }
1772 else
1773 {
1774 /* Avoid race conditions */
1775 Status = STATUS_PROCESS_IS_TERMINATING;
1776 }
1777 break;
1778
1779 case ProcessDebugFlags:
1780
1781 /* Check buffer length */
1782 if (ProcessInformationLength != sizeof(ULONG))
1783 {
1784 Status = STATUS_INFO_LENGTH_MISMATCH;
1785 break;
1786 }
1787
1788 /* Enter SEH for direct buffer read */
1789 _SEH2_TRY
1790 {
1791 DebugFlags = *(PULONG)ProcessInformation;
1792 }
1793 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1794 {
1795 /* Get exception code */
1796 Status = _SEH2_GetExceptionCode();
1797 _SEH2_YIELD(break);
1798 }
1799 _SEH2_END;
1800
1801 /* Set the mode */
1802 if (DebugFlags & ~1)
1803 {
1804 Status = STATUS_INVALID_PARAMETER;
1805 }
1806 else
1807 {
1808 if (DebugFlags & 1)
1809 {
1810 PspClearProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1811 }
1812 else
1813 {
1814 PspSetProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1815 }
1816 }
1817
1818 /* Done */
1819 Status = STATUS_SUCCESS;
1820 break;
1821
1822 case ProcessEnableAlignmentFaultFixup:
1823
1824 /* Check buffer length */
1825 if (ProcessInformationLength != sizeof(ULONG))
1826 {
1827 Status = STATUS_INFO_LENGTH_MISMATCH;
1828 break;
1829 }
1830
1831 /* Enter SEH for direct buffer read */
1832 _SEH2_TRY
1833 {
1834 EnableFixup = *(PULONG)ProcessInformation;
1835 }
1836 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1837 {
1838 /* Get exception code */
1839 Status = _SEH2_GetExceptionCode();
1840 _SEH2_YIELD(break);
1841 }
1842 _SEH2_END;
1843
1844 /* Set the mode */
1845 if (EnableFixup)
1846 {
1847 Process->DefaultHardErrorProcessing |= SEM_NOALIGNMENTFAULTEXCEPT;
1848 }
1849 else
1850 {
1851 Process->DefaultHardErrorProcessing &= ~SEM_NOALIGNMENTFAULTEXCEPT;
1852 }
1853
1854 /* Call Ke for the update */
1855 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE);
1856 Status = STATUS_SUCCESS;
1857 break;
1858
1859 case ProcessUserModeIOPL:
1860
1861 /* Only TCB can do this */
1862 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1863 {
1864 /* We don't hold the privilege, bail out */
1865 DPRINT1("Need TCB to set IOPL\n");
1866 Status = STATUS_PRIVILEGE_NOT_HELD;
1867 break;
1868 }
1869
1870 /* Only supported on x86 */
1871 #if defined (_X86_)
1872 Ke386SetIOPL();
1873 #else
1874 Status = STATUS_NOT_IMPLEMENTED;
1875 #endif
1876 /* Done */
1877 break;
1878
1879 case ProcessExecuteFlags:
1880
1881 /* Check buffer length */
1882 if (ProcessInformationLength != sizeof(ULONG))
1883 {
1884 Status = STATUS_INFO_LENGTH_MISMATCH;
1885 break;
1886 }
1887
1888 if (ProcessHandle != NtCurrentProcess())
1889 {
1890 Status = STATUS_INVALID_PARAMETER;
1891 break;
1892 }
1893
1894 /* Enter SEH for direct buffer read */
1895 _SEH2_TRY
1896 {
1897 NoExecute = *(PULONG)ProcessInformation;
1898 }
1899 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1900 {
1901 /* Get exception code */
1902 Status = _SEH2_GetExceptionCode();
1903 _SEH2_YIELD(break);
1904 }
1905 _SEH2_END;
1906
1907 /* Call Mm for the update */
1908 Status = MmSetExecuteOptions(NoExecute);
1909 break;
1910
1911 /* We currently don't implement any of these */
1912 case ProcessLdtInformation:
1913 case ProcessLdtSize:
1914 case ProcessIoPortHandlers:
1915 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass);
1916 Status = STATUS_NOT_IMPLEMENTED;
1917 break;
1918
1919 case ProcessQuotaLimits:
1920 DPRINT1("Quota Limits not implemented\n");
1921 Status = STATUS_NOT_IMPLEMENTED;
1922 break;
1923
1924 case ProcessWorkingSetWatch:
1925 DPRINT1("WS watch not implemented\n");
1926 Status = STATUS_NOT_IMPLEMENTED;
1927 break;
1928
1929 case ProcessDeviceMap:
1930 DPRINT1("Device map not implemented\n");
1931 Status = STATUS_NOT_IMPLEMENTED;
1932 break;
1933
1934 case ProcessHandleTracing:
1935 DPRINT1("Handle tracing not implemented\n");
1936 Status = STATUS_NOT_IMPLEMENTED;
1937 break;
1938
1939 /* Anything else is invalid */
1940 default:
1941 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass);
1942 Status = STATUS_INVALID_INFO_CLASS;
1943 }
1944
1945 /* Dereference and return status */
1946 ObDereferenceObject(Process);
1947 return Status;
1948 }
1949
1950 /*
1951 * @implemented
1952 */
1953 NTSTATUS
1954 NTAPI
1955 NtSetInformationThread(IN HANDLE ThreadHandle,
1956 IN THREADINFOCLASS ThreadInformationClass,
1957 IN PVOID ThreadInformation,
1958 IN ULONG ThreadInformationLength)
1959 {
1960 PETHREAD Thread;
1961 ULONG Access;
1962 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1963 NTSTATUS Status;
1964 HANDLE TokenHandle = NULL;
1965 KPRIORITY Priority = 0;
1966 KAFFINITY Affinity = 0, CombinedAffinity;
1967 PVOID Address = NULL;
1968 PEPROCESS Process;
1969 ULONG_PTR DisableBoost = 0;
1970 ULONG_PTR IdealProcessor = 0;
1971 ULONG_PTR Break = 0;
1972 PTEB Teb;
1973 ULONG_PTR TlsIndex = 0;
1974 PVOID *ExpansionSlots;
1975 PETHREAD ProcThread;
1976 PAGED_CODE();
1977
1978 /* Verify Information Class validity */
1979 #if 0
1980 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1981 PsThreadInfoClass,
1982 RTL_NUMBER_OF(PsThreadInfoClass),
1983 ThreadInformation,
1984 ThreadInformationLength,
1985 PreviousMode);
1986 if (!NT_SUCCESS(Status)) return Status;
1987 #endif
1988
1989 /* Check what class this is */
1990 Access = THREAD_SET_INFORMATION;
1991 if (ThreadInformationClass == ThreadImpersonationToken)
1992 {
1993 /* Setting the impersonation token needs a special mask */
1994 Access = THREAD_SET_THREAD_TOKEN;
1995 }
1996
1997 /* Reference the thread */
1998 Status = ObReferenceObjectByHandle(ThreadHandle,
1999 Access,
2000 PsThreadType,
2001 PreviousMode,
2002 (PVOID*)&Thread,
2003 NULL);
2004 if (!NT_SUCCESS(Status)) return Status;
2005
2006 /* Check what kind of information class this is */
2007 switch (ThreadInformationClass)
2008 {
2009 /* Thread priority */
2010 case ThreadPriority:
2011
2012 /* Check buffer length */
2013 if (ThreadInformationLength != sizeof(KPRIORITY))
2014 {
2015 Status = STATUS_INFO_LENGTH_MISMATCH;
2016 break;
2017 }
2018
2019 /* Use SEH for capture */
2020 _SEH2_TRY
2021 {
2022 /* Get the priority */
2023 Priority = *(PLONG)ThreadInformation;
2024 }
2025 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2026 {
2027 /* Get the exception code */
2028 Status = _SEH2_GetExceptionCode();
2029 _SEH2_YIELD(break);
2030 }
2031 _SEH2_END;
2032
2033 /* Validate it */
2034 if ((Priority > HIGH_PRIORITY) ||
2035 (Priority <= LOW_PRIORITY))
2036 {
2037 /* Fail */
2038 Status = STATUS_INVALID_PARAMETER;
2039 break;
2040 }
2041
2042 /* Set the priority */
2043 KeSetPriorityThread(&Thread->Tcb, Priority);
2044 break;
2045
2046 case ThreadBasePriority:
2047
2048 /* Check buffer length */
2049 if (ThreadInformationLength != sizeof(LONG))
2050 {
2051 Status = STATUS_INFO_LENGTH_MISMATCH;
2052 break;
2053 }
2054
2055 /* Use SEH for capture */
2056 _SEH2_TRY
2057 {
2058 /* Get the priority */
2059 Priority = *(PLONG)ThreadInformation;
2060 }
2061 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2062 {
2063 /* Get the exception code */
2064 Status = _SEH2_GetExceptionCode();
2065 _SEH2_YIELD(break);
2066 }
2067 _SEH2_END;
2068
2069 /* Validate it */
2070 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
2071 (Priority < THREAD_BASE_PRIORITY_MIN))
2072 {
2073 /* These ones are OK */
2074 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
2075 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
2076 {
2077 /* Check if the process is real time */
2078 if (PsGetCurrentProcess()->PriorityClass !=
2079 PROCESS_PRIORITY_CLASS_REALTIME)
2080 {
2081 /* It isn't, fail */
2082 Status = STATUS_INVALID_PARAMETER;
2083 break;
2084 }
2085 }
2086 }
2087
2088 /* Set the base priority */
2089 KeSetBasePriorityThread(&Thread->Tcb, Priority);
2090 break;
2091
2092 case ThreadAffinityMask:
2093
2094 /* Check buffer length */
2095 if (ThreadInformationLength != sizeof(ULONG_PTR))
2096 {
2097 Status = STATUS_INFO_LENGTH_MISMATCH;
2098 break;
2099 }
2100
2101 /* Use SEH for capture */
2102 _SEH2_TRY
2103 {
2104 /* Get the priority */
2105 Affinity = *(PULONG_PTR)ThreadInformation;
2106 }
2107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2108 {
2109 /* Get the exception code */
2110 Status = _SEH2_GetExceptionCode();
2111 _SEH2_YIELD(break);
2112 }
2113 _SEH2_END;
2114
2115 /* Validate it */
2116 if (!Affinity)
2117 {
2118 /* Fail */
2119 Status = STATUS_INVALID_PARAMETER;
2120 break;
2121 }
2122
2123 /* Get the process */
2124 Process = Thread->ThreadsProcess;
2125
2126 /* Try to acquire rundown */
2127 if (ExAcquireRundownProtection(&Process->RundownProtect))
2128 {
2129 /* Lock it */
2130 KeEnterCriticalRegion();
2131 ExAcquirePushLockShared(&Process->ProcessLock);
2132
2133 /* Combine masks */
2134 CombinedAffinity = Affinity & Process->Pcb.Affinity;
2135 if (CombinedAffinity != Affinity)
2136 {
2137 /* Fail */
2138 Status = STATUS_INVALID_PARAMETER;
2139 }
2140 else
2141 {
2142 /* Set the affinity */
2143 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
2144 }
2145
2146 /* Release the lock and rundown */
2147 ExReleasePushLockShared(&Process->ProcessLock);
2148 KeLeaveCriticalRegion();
2149 ExReleaseRundownProtection(&Process->RundownProtect);
2150 }
2151 else
2152 {
2153 /* Too late */
2154 Status = STATUS_PROCESS_IS_TERMINATING;
2155 }
2156
2157 /* Return status */
2158 break;
2159
2160 case ThreadImpersonationToken:
2161
2162 /* Check buffer length */
2163 if (ThreadInformationLength != sizeof(HANDLE))
2164 {
2165 Status = STATUS_INFO_LENGTH_MISMATCH;
2166 break;
2167 }
2168
2169 /* Use SEH for capture */
2170 _SEH2_TRY
2171 {
2172 /* Save the token handle */
2173 TokenHandle = *(PHANDLE)ThreadInformation;
2174 }
2175 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2176 {
2177 /* Get the exception code */
2178 Status = _SEH2_GetExceptionCode();
2179 _SEH2_YIELD(break);
2180 }
2181 _SEH2_END;
2182
2183 /* Assign the actual token */
2184 Status = PsAssignImpersonationToken(Thread, TokenHandle);
2185 break;
2186
2187 case ThreadQuerySetWin32StartAddress:
2188
2189 /* Check buffer length */
2190 if (ThreadInformationLength != sizeof(ULONG_PTR))
2191 {
2192 Status = STATUS_INFO_LENGTH_MISMATCH;
2193 break;
2194 }
2195
2196 /* Use SEH for capture */
2197 _SEH2_TRY
2198 {
2199 /* Get the priority */
2200 Address = *(PVOID*)ThreadInformation;
2201 }
2202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2203 {
2204 /* Get the exception code */
2205 Status = _SEH2_GetExceptionCode();
2206 _SEH2_YIELD(break);
2207 }
2208 _SEH2_END;
2209
2210 /* Set the address */
2211 Thread->Win32StartAddress = Address;
2212 break;
2213
2214 case ThreadIdealProcessor:
2215
2216 /* Check buffer length */
2217 if (ThreadInformationLength != sizeof(ULONG_PTR))
2218 {
2219 Status = STATUS_INFO_LENGTH_MISMATCH;
2220 break;
2221 }
2222
2223 /* Use SEH for capture */
2224 _SEH2_TRY
2225 {
2226 /* Get the priority */
2227 IdealProcessor = *(PULONG_PTR)ThreadInformation;
2228 }
2229 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2230 {
2231 /* Get the exception code */
2232 Status = _SEH2_GetExceptionCode();
2233 _SEH2_YIELD(break);
2234 }
2235 _SEH2_END;
2236
2237 /* Validate it */
2238 if (IdealProcessor > MAXIMUM_PROCESSORS)
2239 {
2240 /* Fail */
2241 Status = STATUS_INVALID_PARAMETER;
2242 break;
2243 }
2244
2245 /* Set the ideal */
2246 Status = KeSetIdealProcessorThread(&Thread->Tcb,
2247 (CCHAR)IdealProcessor);
2248
2249 /* Get the TEB and protect the thread */
2250 Teb = Thread->Tcb.Teb;
2251 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
2252 {
2253 /* Save the ideal processor */
2254 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
2255
2256 /* Release rundown protection */
2257 ExReleaseRundownProtection(&Thread->RundownProtect);
2258 }
2259
2260 break;
2261
2262 case ThreadPriorityBoost:
2263
2264 /* Check buffer length */
2265 if (ThreadInformationLength != sizeof(ULONG_PTR))
2266 {
2267 Status = STATUS_INFO_LENGTH_MISMATCH;
2268 break;
2269 }
2270
2271 /* Use SEH for capture */
2272 _SEH2_TRY
2273 {
2274 /* Get the priority */
2275 DisableBoost = *(PULONG_PTR)ThreadInformation;
2276 }
2277 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2278 {
2279 /* Get the exception code */
2280 Status = _SEH2_GetExceptionCode();
2281 _SEH2_YIELD(break);
2282 }
2283 _SEH2_END;
2284
2285 /* Call the kernel */
2286 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
2287 break;
2288
2289 case ThreadZeroTlsCell:
2290
2291 /* Check buffer length */
2292 if (ThreadInformationLength != sizeof(ULONG_PTR))
2293 {
2294 Status = STATUS_INFO_LENGTH_MISMATCH;
2295 break;
2296 }
2297
2298 /* Use SEH for capture */
2299 _SEH2_TRY
2300 {
2301 /* Get the priority */
2302 TlsIndex = *(PULONG_PTR)ThreadInformation;
2303 }
2304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2305 {
2306 /* Get the exception code */
2307 Status = _SEH2_GetExceptionCode();
2308 _SEH2_YIELD(break);
2309 }
2310 _SEH2_END;
2311
2312 /* This is only valid for the current thread */
2313 if (Thread != PsGetCurrentThread())
2314 {
2315 /* Fail */
2316 Status = STATUS_INVALID_PARAMETER;
2317 break;
2318 }
2319
2320 /* Get the process */
2321 Process = Thread->ThreadsProcess;
2322
2323 /* Loop the threads */
2324 ProcThread = PsGetNextProcessThread(Process, NULL);
2325 while (ProcThread)
2326 {
2327 /* Acquire rundown */
2328 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
2329 {
2330 /* Get the TEB */
2331 Teb = ProcThread->Tcb.Teb;
2332 if (Teb)
2333 {
2334 /* Check if we're in the expansion range */
2335 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
2336 {
2337 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
2338 TLS_EXPANSION_SLOTS) - 1)
2339 {
2340 /* Check if we have expansion slots */
2341 ExpansionSlots = Teb->TlsExpansionSlots;
2342 if (ExpansionSlots)
2343 {
2344 /* Clear the index */
2345 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
2346 }
2347 }
2348 }
2349 else
2350 {
2351 /* Clear the index */
2352 Teb->TlsSlots[TlsIndex] = NULL;
2353 }
2354 }
2355
2356 /* Release rundown */
2357 ExReleaseRundownProtection(&ProcThread->RundownProtect);
2358 }
2359
2360 /* Go to the next thread */
2361 ProcThread = PsGetNextProcessThread(Process, ProcThread);
2362 }
2363
2364 /* All done */
2365 break;
2366
2367 case ThreadBreakOnTermination:
2368
2369 /* Check buffer length */
2370 if (ThreadInformationLength != sizeof(ULONG))
2371 {
2372 Status = STATUS_INFO_LENGTH_MISMATCH;
2373 break;
2374 }
2375
2376 /* Enter SEH for direct buffer read */
2377 _SEH2_TRY
2378 {
2379 Break = *(PULONG)ThreadInformation;
2380 }
2381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2382 {
2383 /* Get exception code */
2384 Break = 0;
2385 Status = _SEH2_GetExceptionCode();
2386 _SEH2_YIELD(break);
2387 }
2388 _SEH2_END;
2389
2390 /* Setting 'break on termination' requires the SeDebugPrivilege */
2391 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
2392 {
2393 /* We don't hold the privilege, bail out */
2394 Status = STATUS_PRIVILEGE_NOT_HELD;
2395 break;
2396 }
2397
2398 /* Set or clear the flag */
2399 if (Break)
2400 {
2401 PspSetCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2402 }
2403 else
2404 {
2405 PspClearCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2406 }
2407 break;
2408
2409 default:
2410 /* We don't implement it yet */
2411 DPRINT1("Not implemented: %d\n", ThreadInformationClass);
2412 Status = STATUS_NOT_IMPLEMENTED;
2413 }
2414
2415 /* Dereference and return status */
2416 ObDereferenceObject(Thread);
2417 return Status;
2418 }
2419
2420 /*
2421 * @implemented
2422 */
2423 NTSTATUS
2424 NTAPI
2425 NtQueryInformationThread(IN HANDLE ThreadHandle,
2426 IN THREADINFOCLASS ThreadInformationClass,
2427 OUT PVOID ThreadInformation,
2428 IN ULONG ThreadInformationLength,
2429 OUT PULONG ReturnLength OPTIONAL)
2430 {
2431 PETHREAD Thread;
2432 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2433 NTSTATUS Status;
2434 ULONG Access;
2435 ULONG Length = 0;
2436 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
2437 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
2438 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
2439 KIRQL OldIrql;
2440 ULONG ThreadTerminated;
2441 PAGED_CODE();
2442
2443 /* Check if we were called from user mode */
2444 if (PreviousMode != KernelMode)
2445 {
2446 /* Enter SEH */
2447 _SEH2_TRY
2448 {
2449 /* Probe the buffer */
2450 ProbeForWrite(ThreadInformation,
2451 ThreadInformationLength,
2452 sizeof(ULONG));
2453
2454 /* Probe the return length if required */
2455 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
2456 }
2457 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2458 {
2459 /* Return the exception code */
2460 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2461 }
2462 _SEH2_END;
2463 }
2464
2465 /* Check what class this is */
2466 Access = THREAD_QUERY_INFORMATION;
2467
2468 /* Reference the process */
2469 Status = ObReferenceObjectByHandle(ThreadHandle,
2470 Access,
2471 PsThreadType,
2472 PreviousMode,
2473 (PVOID*)&Thread,
2474 NULL);
2475 if (!NT_SUCCESS(Status)) return Status;
2476
2477 /* Check what kind of information class this is */
2478 switch (ThreadInformationClass)
2479 {
2480 /* Basic thread information */
2481 case ThreadBasicInformation:
2482
2483 /* Set return length */
2484 Length = sizeof(THREAD_BASIC_INFORMATION);
2485
2486 if (ThreadInformationLength != Length)
2487 {
2488 Status = STATUS_INFO_LENGTH_MISMATCH;
2489 break;
2490 }
2491 /* Protect writes with SEH */
2492 _SEH2_TRY
2493 {
2494 /* Write all the information from the ETHREAD/KTHREAD */
2495 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
2496 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
2497 ThreadBasicInfo->ClientId = Thread->Cid;
2498 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
2499 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
2500 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
2501 }
2502 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2503 {
2504 /* Get exception code */
2505 Status = _SEH2_GetExceptionCode();
2506 }
2507 _SEH2_END;
2508 break;
2509
2510 /* Thread time information */
2511 case ThreadTimes:
2512
2513 /* Set the return length */
2514 Length = sizeof(KERNEL_USER_TIMES);
2515
2516 if (ThreadInformationLength != Length)
2517 {
2518 Status = STATUS_INFO_LENGTH_MISMATCH;
2519 break;
2520 }
2521 /* Protect writes with SEH */
2522 _SEH2_TRY
2523 {
2524 /* Copy time information from ETHREAD/KTHREAD */
2525 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime * KeMaximumIncrement;
2526 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime * KeMaximumIncrement;
2527 ThreadTime->CreateTime = Thread->CreateTime;
2528
2529 /* Exit time is in a union and only valid on actual exit! */
2530 if (KeReadStateThread(&Thread->Tcb))
2531 {
2532 ThreadTime->ExitTime = Thread->ExitTime;
2533 }
2534 else
2535 {
2536 ThreadTime->ExitTime.QuadPart = 0;
2537 }
2538 }
2539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2540 {
2541 /* Get exception code */
2542 Status = _SEH2_GetExceptionCode();
2543 }
2544 _SEH2_END;
2545 break;
2546
2547 case ThreadQuerySetWin32StartAddress:
2548
2549 /* Set the return length*/
2550 Length = sizeof(PVOID);
2551
2552 if (ThreadInformationLength != Length)
2553 {
2554 Status = STATUS_INFO_LENGTH_MISMATCH;
2555 break;
2556 }
2557 /* Protect write with SEH */
2558 _SEH2_TRY
2559 {
2560 /* Return the Win32 Start Address */
2561 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
2562 }
2563 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2564 {
2565 /* Get exception code */
2566 Status = _SEH2_GetExceptionCode();
2567 }
2568 _SEH2_END;
2569 break;
2570
2571 case ThreadPerformanceCount:
2572
2573 /* Set the return length*/
2574 Length = sizeof(LARGE_INTEGER);
2575
2576 if (ThreadInformationLength != Length)
2577 {
2578 Status = STATUS_INFO_LENGTH_MISMATCH;
2579 break;
2580 }
2581 /* Protect write with SEH */
2582 _SEH2_TRY
2583 {
2584 /* FIXME */
2585 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
2586 }
2587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2588 {
2589 /* Get exception code */
2590 Status = _SEH2_GetExceptionCode();
2591 }
2592 _SEH2_END;
2593 break;
2594
2595 case ThreadAmILastThread:
2596
2597 /* Set the return length*/
2598 Length = sizeof(ULONG);
2599
2600 if (ThreadInformationLength != Length)
2601 {
2602 Status = STATUS_INFO_LENGTH_MISMATCH;
2603 break;
2604 }
2605 /* Protect write with SEH */
2606 _SEH2_TRY
2607 {
2608 /* Return whether or not we are the last thread */
2609 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
2610 ThreadListHead.Flink->Flink ==
2611 &Thread->ThreadsProcess->
2612 ThreadListHead) ?
2613 TRUE : FALSE);
2614 }
2615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2616 {
2617 /* Get exception code */
2618 Status = _SEH2_GetExceptionCode();
2619 }
2620 _SEH2_END;
2621 break;
2622
2623 case ThreadIsIoPending:
2624
2625 /* Set the return length*/
2626 Length = sizeof(ULONG);
2627
2628 if (ThreadInformationLength != Length)
2629 {
2630 Status = STATUS_INFO_LENGTH_MISMATCH;
2631 break;
2632 }
2633 /* Raise the IRQL to protect the IRP list */
2634 KeRaiseIrql(APC_LEVEL, &OldIrql);
2635
2636 /* Protect write with SEH */
2637 _SEH2_TRY
2638 {
2639 /* Check if the IRP list is empty or not */
2640 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
2641 }
2642 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2643 {
2644 /* Get exception code */
2645 Status = _SEH2_GetExceptionCode();
2646 }
2647 _SEH2_END;
2648
2649 /* Lower IRQL back */
2650 KeLowerIrql(OldIrql);
2651 break;
2652
2653 /* LDT and GDT information */
2654 case ThreadDescriptorTableEntry:
2655
2656 #if defined(_X86_)
2657 /* Call the worker routine */
2658 Status = PspQueryDescriptorThread(Thread,
2659 ThreadInformation,
2660 ThreadInformationLength,
2661 ReturnLength);
2662 #else
2663 /* Only implemented on x86 */
2664 Status = STATUS_NOT_IMPLEMENTED;
2665 #endif
2666 break;
2667
2668 case ThreadPriorityBoost:
2669
2670 /* Set the return length*/
2671 Length = sizeof(ULONG);
2672
2673 if (ThreadInformationLength != Length)
2674 {
2675 Status = STATUS_INFO_LENGTH_MISMATCH;
2676 break;
2677 }
2678
2679 _SEH2_TRY
2680 {
2681 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
2682 }
2683 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2684 {
2685 Status = _SEH2_GetExceptionCode();
2686 }
2687 _SEH2_END;
2688 break;
2689
2690 case ThreadIsTerminated:
2691
2692 /* Set the return length*/
2693 Length = sizeof(ThreadTerminated);
2694
2695 if (ThreadInformationLength != Length)
2696 {
2697 Status = STATUS_INFO_LENGTH_MISMATCH;
2698 break;
2699 }
2700
2701 ThreadTerminated = PsIsThreadTerminating(Thread);
2702
2703 _SEH2_TRY
2704 {
2705 *(PULONG)ThreadInformation = ThreadTerminated ? 1 : 0;
2706 }
2707 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2708 {
2709 Status = _SEH2_GetExceptionCode();
2710 }
2711 _SEH2_END;
2712
2713 break;
2714
2715 /* Anything else */
2716 default:
2717
2718 /* Not yet implemented */
2719 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
2720 Status = STATUS_NOT_IMPLEMENTED;
2721 }
2722
2723 /* Protect write with SEH */
2724 _SEH2_TRY
2725 {
2726 /* Check if caller wanted return length */
2727 if (ReturnLength) *ReturnLength = Length;
2728 }
2729 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2730 {
2731 /* Get exception code */
2732 Status = _SEH2_GetExceptionCode();
2733 }
2734 _SEH2_END;
2735
2736 /* Dereference the thread, and return */
2737 ObDereferenceObject(Thread);
2738 return Status;
2739 }
2740
2741 /* EOF */