[NTOSKRNL]
[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 = 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
1921 return PspSetQuotaLimits(ProcessHandle,
1922 1,
1923 ProcessInformation,
1924 ProcessInformationLength,
1925 PreviousMode);
1926
1927 case ProcessWorkingSetWatch:
1928 DPRINT1("WS watch not implemented\n");
1929 Status = STATUS_NOT_IMPLEMENTED;
1930 break;
1931
1932 case ProcessDeviceMap:
1933 DPRINT1("Device map not implemented\n");
1934 Status = STATUS_NOT_IMPLEMENTED;
1935 break;
1936
1937 case ProcessHandleTracing:
1938 DPRINT1("Handle tracing not implemented\n");
1939 Status = STATUS_NOT_IMPLEMENTED;
1940 break;
1941
1942 /* Anything else is invalid */
1943 default:
1944 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass);
1945 Status = STATUS_INVALID_INFO_CLASS;
1946 }
1947
1948 /* Dereference and return status */
1949 ObDereferenceObject(Process);
1950 return Status;
1951 }
1952
1953 /*
1954 * @implemented
1955 */
1956 NTSTATUS
1957 NTAPI
1958 NtSetInformationThread(IN HANDLE ThreadHandle,
1959 IN THREADINFOCLASS ThreadInformationClass,
1960 IN PVOID ThreadInformation,
1961 IN ULONG ThreadInformationLength)
1962 {
1963 PETHREAD Thread;
1964 ULONG Access;
1965 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1966 NTSTATUS Status;
1967 HANDLE TokenHandle = NULL;
1968 KPRIORITY Priority = 0;
1969 KAFFINITY Affinity = 0, CombinedAffinity;
1970 PVOID Address = NULL;
1971 PEPROCESS Process;
1972 ULONG_PTR DisableBoost = 0;
1973 ULONG_PTR IdealProcessor = 0;
1974 ULONG_PTR Break = 0;
1975 PTEB Teb;
1976 ULONG_PTR TlsIndex = 0;
1977 PVOID *ExpansionSlots;
1978 PETHREAD ProcThread;
1979 PAGED_CODE();
1980
1981 /* Verify Information Class validity */
1982 #if 0
1983 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1984 PsThreadInfoClass,
1985 RTL_NUMBER_OF(PsThreadInfoClass),
1986 ThreadInformation,
1987 ThreadInformationLength,
1988 PreviousMode);
1989 if (!NT_SUCCESS(Status)) return Status;
1990 #endif
1991
1992 /* Check what class this is */
1993 Access = THREAD_SET_INFORMATION;
1994 if (ThreadInformationClass == ThreadImpersonationToken)
1995 {
1996 /* Setting the impersonation token needs a special mask */
1997 Access = THREAD_SET_THREAD_TOKEN;
1998 }
1999
2000 /* Reference the thread */
2001 Status = ObReferenceObjectByHandle(ThreadHandle,
2002 Access,
2003 PsThreadType,
2004 PreviousMode,
2005 (PVOID*)&Thread,
2006 NULL);
2007 if (!NT_SUCCESS(Status)) return Status;
2008
2009 /* Check what kind of information class this is */
2010 switch (ThreadInformationClass)
2011 {
2012 /* Thread priority */
2013 case ThreadPriority:
2014
2015 /* Check buffer length */
2016 if (ThreadInformationLength != sizeof(KPRIORITY))
2017 {
2018 Status = STATUS_INFO_LENGTH_MISMATCH;
2019 break;
2020 }
2021
2022 /* Use SEH for capture */
2023 _SEH2_TRY
2024 {
2025 /* Get the priority */
2026 Priority = *(PLONG)ThreadInformation;
2027 }
2028 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2029 {
2030 /* Get the exception code */
2031 Status = _SEH2_GetExceptionCode();
2032 _SEH2_YIELD(break);
2033 }
2034 _SEH2_END;
2035
2036 /* Validate it */
2037 if ((Priority > HIGH_PRIORITY) ||
2038 (Priority <= LOW_PRIORITY))
2039 {
2040 /* Fail */
2041 Status = STATUS_INVALID_PARAMETER;
2042 break;
2043 }
2044
2045 /* Set the priority */
2046 KeSetPriorityThread(&Thread->Tcb, Priority);
2047 break;
2048
2049 case ThreadBasePriority:
2050
2051 /* Check buffer length */
2052 if (ThreadInformationLength != sizeof(LONG))
2053 {
2054 Status = STATUS_INFO_LENGTH_MISMATCH;
2055 break;
2056 }
2057
2058 /* Use SEH for capture */
2059 _SEH2_TRY
2060 {
2061 /* Get the priority */
2062 Priority = *(PLONG)ThreadInformation;
2063 }
2064 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2065 {
2066 /* Get the exception code */
2067 Status = _SEH2_GetExceptionCode();
2068 _SEH2_YIELD(break);
2069 }
2070 _SEH2_END;
2071
2072 /* Validate it */
2073 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
2074 (Priority < THREAD_BASE_PRIORITY_MIN))
2075 {
2076 /* These ones are OK */
2077 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
2078 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
2079 {
2080 /* Check if the process is real time */
2081 if (PsGetCurrentProcess()->PriorityClass !=
2082 PROCESS_PRIORITY_CLASS_REALTIME)
2083 {
2084 /* It isn't, fail */
2085 Status = STATUS_INVALID_PARAMETER;
2086 break;
2087 }
2088 }
2089 }
2090
2091 /* Set the base priority */
2092 KeSetBasePriorityThread(&Thread->Tcb, Priority);
2093 break;
2094
2095 case ThreadAffinityMask:
2096
2097 /* Check buffer length */
2098 if (ThreadInformationLength != sizeof(ULONG_PTR))
2099 {
2100 Status = STATUS_INFO_LENGTH_MISMATCH;
2101 break;
2102 }
2103
2104 /* Use SEH for capture */
2105 _SEH2_TRY
2106 {
2107 /* Get the priority */
2108 Affinity = *(PULONG_PTR)ThreadInformation;
2109 }
2110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2111 {
2112 /* Get the exception code */
2113 Status = _SEH2_GetExceptionCode();
2114 _SEH2_YIELD(break);
2115 }
2116 _SEH2_END;
2117
2118 /* Validate it */
2119 if (!Affinity)
2120 {
2121 /* Fail */
2122 Status = STATUS_INVALID_PARAMETER;
2123 break;
2124 }
2125
2126 /* Get the process */
2127 Process = Thread->ThreadsProcess;
2128
2129 /* Try to acquire rundown */
2130 if (ExAcquireRundownProtection(&Process->RundownProtect))
2131 {
2132 /* Lock it */
2133 KeEnterCriticalRegion();
2134 ExAcquirePushLockShared(&Process->ProcessLock);
2135
2136 /* Combine masks */
2137 CombinedAffinity = Affinity & Process->Pcb.Affinity;
2138 if (CombinedAffinity != Affinity)
2139 {
2140 /* Fail */
2141 Status = STATUS_INVALID_PARAMETER;
2142 }
2143 else
2144 {
2145 /* Set the affinity */
2146 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
2147 }
2148
2149 /* Release the lock and rundown */
2150 ExReleasePushLockShared(&Process->ProcessLock);
2151 KeLeaveCriticalRegion();
2152 ExReleaseRundownProtection(&Process->RundownProtect);
2153 }
2154 else
2155 {
2156 /* Too late */
2157 Status = STATUS_PROCESS_IS_TERMINATING;
2158 }
2159
2160 /* Return status */
2161 break;
2162
2163 case ThreadImpersonationToken:
2164
2165 /* Check buffer length */
2166 if (ThreadInformationLength != sizeof(HANDLE))
2167 {
2168 Status = STATUS_INFO_LENGTH_MISMATCH;
2169 break;
2170 }
2171
2172 /* Use SEH for capture */
2173 _SEH2_TRY
2174 {
2175 /* Save the token handle */
2176 TokenHandle = *(PHANDLE)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 /* Assign the actual token */
2187 Status = PsAssignImpersonationToken(Thread, TokenHandle);
2188 break;
2189
2190 case ThreadQuerySetWin32StartAddress:
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 Address = *(PVOID*)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 /* Set the address */
2214 Thread->Win32StartAddress = Address;
2215 break;
2216
2217 case ThreadIdealProcessor:
2218
2219 /* Check buffer length */
2220 if (ThreadInformationLength != sizeof(ULONG_PTR))
2221 {
2222 Status = STATUS_INFO_LENGTH_MISMATCH;
2223 break;
2224 }
2225
2226 /* Use SEH for capture */
2227 _SEH2_TRY
2228 {
2229 /* Get the priority */
2230 IdealProcessor = *(PULONG_PTR)ThreadInformation;
2231 }
2232 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2233 {
2234 /* Get the exception code */
2235 Status = _SEH2_GetExceptionCode();
2236 _SEH2_YIELD(break);
2237 }
2238 _SEH2_END;
2239
2240 /* Validate it */
2241 if (IdealProcessor > MAXIMUM_PROCESSORS)
2242 {
2243 /* Fail */
2244 Status = STATUS_INVALID_PARAMETER;
2245 break;
2246 }
2247
2248 /* Set the ideal */
2249 Status = KeSetIdealProcessorThread(&Thread->Tcb,
2250 (CCHAR)IdealProcessor);
2251
2252 /* Get the TEB and protect the thread */
2253 Teb = Thread->Tcb.Teb;
2254 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
2255 {
2256 /* Save the ideal processor */
2257 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
2258
2259 /* Release rundown protection */
2260 ExReleaseRundownProtection(&Thread->RundownProtect);
2261 }
2262
2263 break;
2264
2265 case ThreadPriorityBoost:
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 DisableBoost = *(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 /* Call the kernel */
2289 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
2290 break;
2291
2292 case ThreadZeroTlsCell:
2293
2294 /* Check buffer length */
2295 if (ThreadInformationLength != sizeof(ULONG_PTR))
2296 {
2297 Status = STATUS_INFO_LENGTH_MISMATCH;
2298 break;
2299 }
2300
2301 /* Use SEH for capture */
2302 _SEH2_TRY
2303 {
2304 /* Get the priority */
2305 TlsIndex = *(PULONG_PTR)ThreadInformation;
2306 }
2307 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2308 {
2309 /* Get the exception code */
2310 Status = _SEH2_GetExceptionCode();
2311 _SEH2_YIELD(break);
2312 }
2313 _SEH2_END;
2314
2315 /* This is only valid for the current thread */
2316 if (Thread != PsGetCurrentThread())
2317 {
2318 /* Fail */
2319 Status = STATUS_INVALID_PARAMETER;
2320 break;
2321 }
2322
2323 /* Get the process */
2324 Process = Thread->ThreadsProcess;
2325
2326 /* Loop the threads */
2327 ProcThread = PsGetNextProcessThread(Process, NULL);
2328 while (ProcThread)
2329 {
2330 /* Acquire rundown */
2331 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
2332 {
2333 /* Get the TEB */
2334 Teb = ProcThread->Tcb.Teb;
2335 if (Teb)
2336 {
2337 /* Check if we're in the expansion range */
2338 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
2339 {
2340 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
2341 TLS_EXPANSION_SLOTS) - 1)
2342 {
2343 /* Check if we have expansion slots */
2344 ExpansionSlots = Teb->TlsExpansionSlots;
2345 if (ExpansionSlots)
2346 {
2347 /* Clear the index */
2348 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
2349 }
2350 }
2351 }
2352 else
2353 {
2354 /* Clear the index */
2355 Teb->TlsSlots[TlsIndex] = NULL;
2356 }
2357 }
2358
2359 /* Release rundown */
2360 ExReleaseRundownProtection(&ProcThread->RundownProtect);
2361 }
2362
2363 /* Go to the next thread */
2364 ProcThread = PsGetNextProcessThread(Process, ProcThread);
2365 }
2366
2367 /* All done */
2368 break;
2369
2370 case ThreadBreakOnTermination:
2371
2372 /* Check buffer length */
2373 if (ThreadInformationLength != sizeof(ULONG))
2374 {
2375 Status = STATUS_INFO_LENGTH_MISMATCH;
2376 break;
2377 }
2378
2379 /* Enter SEH for direct buffer read */
2380 _SEH2_TRY
2381 {
2382 Break = *(PULONG)ThreadInformation;
2383 }
2384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2385 {
2386 /* Get exception code */
2387 Break = 0;
2388 Status = _SEH2_GetExceptionCode();
2389 _SEH2_YIELD(break);
2390 }
2391 _SEH2_END;
2392
2393 /* Setting 'break on termination' requires the SeDebugPrivilege */
2394 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
2395 {
2396 /* We don't hold the privilege, bail out */
2397 Status = STATUS_PRIVILEGE_NOT_HELD;
2398 break;
2399 }
2400
2401 /* Set or clear the flag */
2402 if (Break)
2403 {
2404 PspSetCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2405 }
2406 else
2407 {
2408 PspClearCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2409 }
2410 break;
2411
2412 default:
2413 /* We don't implement it yet */
2414 DPRINT1("Not implemented: %d\n", ThreadInformationClass);
2415 Status = STATUS_NOT_IMPLEMENTED;
2416 }
2417
2418 /* Dereference and return status */
2419 ObDereferenceObject(Thread);
2420 return Status;
2421 }
2422
2423 /*
2424 * @implemented
2425 */
2426 NTSTATUS
2427 NTAPI
2428 NtQueryInformationThread(IN HANDLE ThreadHandle,
2429 IN THREADINFOCLASS ThreadInformationClass,
2430 OUT PVOID ThreadInformation,
2431 IN ULONG ThreadInformationLength,
2432 OUT PULONG ReturnLength OPTIONAL)
2433 {
2434 PETHREAD Thread;
2435 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2436 NTSTATUS Status;
2437 ULONG Access;
2438 ULONG Length = 0;
2439 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
2440 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
2441 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
2442 KIRQL OldIrql;
2443 ULONG ThreadTerminated;
2444 PAGED_CODE();
2445
2446 /* Check if we were called from user mode */
2447 if (PreviousMode != KernelMode)
2448 {
2449 /* Enter SEH */
2450 _SEH2_TRY
2451 {
2452 /* Probe the buffer */
2453 ProbeForWrite(ThreadInformation,
2454 ThreadInformationLength,
2455 sizeof(ULONG));
2456
2457 /* Probe the return length if required */
2458 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
2459 }
2460 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2461 {
2462 /* Return the exception code */
2463 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2464 }
2465 _SEH2_END;
2466 }
2467
2468 /* Check what class this is */
2469 Access = THREAD_QUERY_INFORMATION;
2470
2471 /* Reference the process */
2472 Status = ObReferenceObjectByHandle(ThreadHandle,
2473 Access,
2474 PsThreadType,
2475 PreviousMode,
2476 (PVOID*)&Thread,
2477 NULL);
2478 if (!NT_SUCCESS(Status)) return Status;
2479
2480 /* Check what kind of information class this is */
2481 switch (ThreadInformationClass)
2482 {
2483 /* Basic thread information */
2484 case ThreadBasicInformation:
2485
2486 /* Set return length */
2487 Length = sizeof(THREAD_BASIC_INFORMATION);
2488
2489 if (ThreadInformationLength != Length)
2490 {
2491 Status = STATUS_INFO_LENGTH_MISMATCH;
2492 break;
2493 }
2494 /* Protect writes with SEH */
2495 _SEH2_TRY
2496 {
2497 /* Write all the information from the ETHREAD/KTHREAD */
2498 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
2499 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
2500 ThreadBasicInfo->ClientId = Thread->Cid;
2501 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
2502 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
2503 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
2504 }
2505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2506 {
2507 /* Get exception code */
2508 Status = _SEH2_GetExceptionCode();
2509 }
2510 _SEH2_END;
2511 break;
2512
2513 /* Thread time information */
2514 case ThreadTimes:
2515
2516 /* Set the return length */
2517 Length = sizeof(KERNEL_USER_TIMES);
2518
2519 if (ThreadInformationLength != Length)
2520 {
2521 Status = STATUS_INFO_LENGTH_MISMATCH;
2522 break;
2523 }
2524 /* Protect writes with SEH */
2525 _SEH2_TRY
2526 {
2527 /* Copy time information from ETHREAD/KTHREAD */
2528 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime * KeMaximumIncrement;
2529 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime * KeMaximumIncrement;
2530 ThreadTime->CreateTime = Thread->CreateTime;
2531
2532 /* Exit time is in a union and only valid on actual exit! */
2533 if (KeReadStateThread(&Thread->Tcb))
2534 {
2535 ThreadTime->ExitTime = Thread->ExitTime;
2536 }
2537 else
2538 {
2539 ThreadTime->ExitTime.QuadPart = 0;
2540 }
2541 }
2542 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2543 {
2544 /* Get exception code */
2545 Status = _SEH2_GetExceptionCode();
2546 }
2547 _SEH2_END;
2548 break;
2549
2550 case ThreadQuerySetWin32StartAddress:
2551
2552 /* Set the return length*/
2553 Length = sizeof(PVOID);
2554
2555 if (ThreadInformationLength != Length)
2556 {
2557 Status = STATUS_INFO_LENGTH_MISMATCH;
2558 break;
2559 }
2560 /* Protect write with SEH */
2561 _SEH2_TRY
2562 {
2563 /* Return the Win32 Start Address */
2564 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
2565 }
2566 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2567 {
2568 /* Get exception code */
2569 Status = _SEH2_GetExceptionCode();
2570 }
2571 _SEH2_END;
2572 break;
2573
2574 case ThreadPerformanceCount:
2575
2576 /* Set the return length*/
2577 Length = sizeof(LARGE_INTEGER);
2578
2579 if (ThreadInformationLength != Length)
2580 {
2581 Status = STATUS_INFO_LENGTH_MISMATCH;
2582 break;
2583 }
2584 /* Protect write with SEH */
2585 _SEH2_TRY
2586 {
2587 /* FIXME */
2588 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
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 ThreadAmILastThread:
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 /* Protect write with SEH */
2609 _SEH2_TRY
2610 {
2611 /* Return whether or not we are the last thread */
2612 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
2613 ThreadListHead.Flink->Flink ==
2614 &Thread->ThreadsProcess->
2615 ThreadListHead) ?
2616 TRUE : FALSE);
2617 }
2618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2619 {
2620 /* Get exception code */
2621 Status = _SEH2_GetExceptionCode();
2622 }
2623 _SEH2_END;
2624 break;
2625
2626 case ThreadIsIoPending:
2627
2628 /* Set the return length*/
2629 Length = sizeof(ULONG);
2630
2631 if (ThreadInformationLength != Length)
2632 {
2633 Status = STATUS_INFO_LENGTH_MISMATCH;
2634 break;
2635 }
2636 /* Raise the IRQL to protect the IRP list */
2637 KeRaiseIrql(APC_LEVEL, &OldIrql);
2638
2639 /* Protect write with SEH */
2640 _SEH2_TRY
2641 {
2642 /* Check if the IRP list is empty or not */
2643 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
2644 }
2645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2646 {
2647 /* Get exception code */
2648 Status = _SEH2_GetExceptionCode();
2649 }
2650 _SEH2_END;
2651
2652 /* Lower IRQL back */
2653 KeLowerIrql(OldIrql);
2654 break;
2655
2656 /* LDT and GDT information */
2657 case ThreadDescriptorTableEntry:
2658
2659 #if defined(_X86_)
2660 /* Call the worker routine */
2661 Status = PspQueryDescriptorThread(Thread,
2662 ThreadInformation,
2663 ThreadInformationLength,
2664 ReturnLength);
2665 #else
2666 /* Only implemented on x86 */
2667 Status = STATUS_NOT_IMPLEMENTED;
2668 #endif
2669 break;
2670
2671 case ThreadPriorityBoost:
2672
2673 /* Set the return length*/
2674 Length = sizeof(ULONG);
2675
2676 if (ThreadInformationLength != Length)
2677 {
2678 Status = STATUS_INFO_LENGTH_MISMATCH;
2679 break;
2680 }
2681
2682 _SEH2_TRY
2683 {
2684 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
2685 }
2686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2687 {
2688 Status = _SEH2_GetExceptionCode();
2689 }
2690 _SEH2_END;
2691 break;
2692
2693 case ThreadIsTerminated:
2694
2695 /* Set the return length*/
2696 Length = sizeof(ThreadTerminated);
2697
2698 if (ThreadInformationLength != Length)
2699 {
2700 Status = STATUS_INFO_LENGTH_MISMATCH;
2701 break;
2702 }
2703
2704 ThreadTerminated = PsIsThreadTerminating(Thread);
2705
2706 _SEH2_TRY
2707 {
2708 *(PULONG)ThreadInformation = ThreadTerminated ? 1 : 0;
2709 }
2710 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2711 {
2712 Status = _SEH2_GetExceptionCode();
2713 }
2714 _SEH2_END;
2715
2716 break;
2717
2718 /* Anything else */
2719 default:
2720
2721 /* Not yet implemented */
2722 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
2723 Status = STATUS_NOT_IMPLEMENTED;
2724 }
2725
2726 /* Protect write with SEH */
2727 _SEH2_TRY
2728 {
2729 /* Check if caller wanted return length */
2730 if (ReturnLength) *ReturnLength = Length;
2731 }
2732 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2733 {
2734 /* Get exception code */
2735 Status = _SEH2_GetExceptionCode();
2736 }
2737 _SEH2_END;
2738
2739 /* Dereference the thread, and return */
2740 ObDereferenceObject(Thread);
2741 return Status;
2742 }
2743
2744 /* EOF */