Merge trunk head (r41474)
[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 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
18
19 /* Debugging Level */
20 ULONG PspTraceLevel = 0;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 PsReferenceProcessFilePointer(IN PEPROCESS Process,
27 OUT PFILE_OBJECT *FileObject)
28 {
29 PSECTION Section;
30 PAGED_CODE();
31
32 /* Lock the process */
33 ExAcquireRundownProtection(&Process->RundownProtect);
34
35 /* Get the section */
36 Section = Process->SectionObject;
37 if (Section)
38 {
39 /* Get the file object and reference it */
40 *FileObject = MmGetFileObjectForSection((PVOID)Section);
41 ObReferenceObject(*FileObject);
42 }
43
44 /* Release the protection */
45 ExReleaseRundownProtection(&Process->RundownProtect);
46
47 /* Return status */
48 return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
49 }
50
51 /* PUBLIC FUNCTIONS **********************************************************/
52
53 /*
54 * @implemented
55 */
56 NTSTATUS
57 NTAPI
58 NtQueryInformationProcess(IN HANDLE ProcessHandle,
59 IN PROCESSINFOCLASS ProcessInformationClass,
60 OUT PVOID ProcessInformation,
61 IN ULONG ProcessInformationLength,
62 OUT PULONG ReturnLength OPTIONAL)
63 {
64 PEPROCESS Process;
65 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
66 NTSTATUS Status = STATUS_SUCCESS;
67 ULONG Length = 0;
68 PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
69 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
70 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
71 PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
72 ULONG HandleCount;
73 PPROCESS_SESSION_INFORMATION SessionInfo =
74 (PPROCESS_SESSION_INFORMATION)ProcessInformation;
75 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
76 PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
77 PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
78 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
79 PUNICODE_STRING ImageName;
80 ULONG Cookie;
81 PAGED_CODE();
82
83 /* Check for user-mode caller */
84 if (PreviousMode != KernelMode)
85 {
86 /* Prepare to probe parameters */
87 _SEH2_TRY
88 {
89 ProbeForWrite(ProcessInformation,
90 ProcessInformationLength,
91 sizeof(ULONG));
92 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
93 }
94 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
95 {
96 /* Get the error code */
97 Status = _SEH2_GetExceptionCode();
98 }
99 _SEH2_END;
100 if(!NT_SUCCESS(Status)) return Status;
101 }
102
103 if((ProcessInformationClass == ProcessCookie) &&
104 (ProcessHandle != NtCurrentProcess()))
105 {
106 /*
107 * Retreiving the process cookie is only allowed for the calling process
108 * itself! XP only allowes NtCurrentProcess() as process handles even if
109 * a real handle actually represents the current process.
110 */
111 return STATUS_INVALID_PARAMETER;
112 }
113
114 /* Check the information class */
115 switch (ProcessInformationClass)
116 {
117 /* Basic process information */
118 case ProcessBasicInformation:
119
120 /* Set return length */
121 Length = sizeof(PROCESS_BASIC_INFORMATION);
122
123 if (ProcessInformationLength != Length)
124 {
125 Status = STATUS_INFO_LENGTH_MISMATCH;
126 break;
127 }
128
129 /* Reference the process */
130 Status = ObReferenceObjectByHandle(ProcessHandle,
131 PROCESS_QUERY_INFORMATION,
132 PsProcessType,
133 PreviousMode,
134 (PVOID*)&Process,
135 NULL);
136 if (!NT_SUCCESS(Status)) break;
137
138 /* Protect writes with SEH */
139 _SEH2_TRY
140 {
141 /* Write all the information from the EPROCESS/KPROCESS */
142 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
143 ProcessBasicInfo->PebBaseAddress = Process->Peb;
144 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
145 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
146 UniqueProcessId;
147 ProcessBasicInfo->InheritedFromUniqueProcessId =
148 (ULONG_PTR)Process->InheritedFromUniqueProcessId;
149 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
150
151 }
152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
153 {
154 /* Get exception code */
155 Status = _SEH2_GetExceptionCode();
156 }
157 _SEH2_END;
158
159 /* Dereference the process */
160 ObDereferenceObject(Process);
161 break;
162
163 /* Process quota limits */
164 case ProcessQuotaLimits:
165
166 Length = sizeof(QUOTA_LIMITS);
167 if (ProcessInformationLength != Length)
168 {
169 Status = STATUS_INFO_LENGTH_MISMATCH;
170 break;
171 }
172
173 /* Reference the process */
174 Status = ObReferenceObjectByHandle(ProcessHandle,
175 PROCESS_QUERY_INFORMATION,
176 PsProcessType,
177 PreviousMode,
178 (PVOID*)&Process,
179 NULL);
180 if (!NT_SUCCESS(Status)) break;
181
182 /* Indicate success */
183 Status = STATUS_SUCCESS;
184
185 _SEH2_TRY
186 {
187 /* Set max/min working set sizes */
188 QuotaLimits->MaximumWorkingSetSize =
189 Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
190 QuotaLimits->MinimumWorkingSetSize =
191 Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
192
193 /* Set default time limits */
194 QuotaLimits->TimeLimit.LowPart = (ULONG)-1;
195 QuotaLimits->TimeLimit.HighPart = (ULONG)-1;
196
197 /* Is quota block a default one? */
198 if (Process->QuotaBlock == &PspDefaultQuotaBlock)
199 {
200 /* Set default pools and pagefile limits */
201 QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
202 QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
203 QuotaLimits->PagefileLimit = (SIZE_T)-1;
204 }
205 else
206 {
207 /* Get limits from non-default quota block */
208 QuotaLimits->PagedPoolLimit =
209 Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
210 QuotaLimits->NonPagedPoolLimit =
211 Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
212 QuotaLimits->PagefileLimit =
213 Process->QuotaBlock->QuotaEntry[2].Limit;
214 }
215 }
216 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
217 {
218 /* Get exception code */
219 Status = _SEH2_GetExceptionCode();
220 }
221 _SEH2_END;
222
223 /* Dereference the process */
224 ObDereferenceObject(Process);
225 break;
226
227 case ProcessIoCounters:
228
229 Length = sizeof(IO_COUNTERS);
230 if (ProcessInformationLength != Length)
231 {
232 Status = STATUS_INFO_LENGTH_MISMATCH;
233 break;
234 }
235
236 /* Reference the process */
237 Status = ObReferenceObjectByHandle(ProcessHandle,
238 PROCESS_QUERY_INFORMATION,
239 PsProcessType,
240 PreviousMode,
241 (PVOID*)&Process,
242 NULL);
243 if (!NT_SUCCESS(Status)) break;
244
245 _SEH2_TRY
246 {
247 IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
248 IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
249 IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
250 IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
251 IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
252 IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
253 }
254 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
255 {
256 /* Ignore exception */
257 }
258 _SEH2_END;
259
260 /* Set status to success in any case */
261 Status = STATUS_SUCCESS;
262
263 /* Dereference the process */
264 ObDereferenceObject(Process);
265 break;
266
267 /* Timing */
268 case ProcessTimes:
269
270 /* Set the return length */
271 Length = sizeof(KERNEL_USER_TIMES);
272
273 if (ProcessInformationLength != Length)
274 {
275 Status = STATUS_INFO_LENGTH_MISMATCH;
276 break;
277 }
278
279 /* Reference the process */
280 Status = ObReferenceObjectByHandle(ProcessHandle,
281 PROCESS_QUERY_INFORMATION,
282 PsProcessType,
283 PreviousMode,
284 (PVOID*)&Process,
285 NULL);
286 if (!NT_SUCCESS(Status)) break;
287
288 /* Protect writes with SEH */
289 _SEH2_TRY
290 {
291 /* Copy time information from EPROCESS/KPROCESS */
292 ProcessTime->CreateTime = Process->CreateTime;
293 ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
294 100000LL;
295 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
296 100000LL;
297 ProcessTime->ExitTime = Process->ExitTime;
298 }
299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
300 {
301 /* Get exception code */
302 Status = _SEH2_GetExceptionCode();
303 }
304 _SEH2_END;
305
306 /* Dereference the process */
307 ObDereferenceObject(Process);
308 break;
309
310 /* Process Debug Port */
311 case ProcessDebugPort:
312
313 /* Set return length */
314 Length = sizeof(HANDLE);
315
316 if (ProcessInformationLength != Length)
317 {
318 Status = STATUS_INFO_LENGTH_MISMATCH;
319 break;
320 }
321
322 /* Reference the process */
323 Status = ObReferenceObjectByHandle(ProcessHandle,
324 PROCESS_QUERY_INFORMATION,
325 PsProcessType,
326 PreviousMode,
327 (PVOID*)&Process,
328 NULL);
329 if (!NT_SUCCESS(Status)) break;
330
331 /* Protect write with SEH */
332 _SEH2_TRY
333 {
334 /* Return whether or not we have a debug port */
335 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
336 (HANDLE)-1 : NULL);
337 }
338 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
339 {
340 /* Get exception code */
341 Status = _SEH2_GetExceptionCode();
342 }
343 _SEH2_END;
344
345 /* Dereference the process */
346 ObDereferenceObject(Process);
347 break;
348
349 /* LDT, WS and VDM Information: not implemented */
350 case ProcessLdtInformation:
351 case ProcessWorkingSetWatch:
352 case ProcessWx86Information:
353
354 /* Reference the process */
355 Status = ObReferenceObjectByHandle(ProcessHandle,
356 PROCESS_QUERY_INFORMATION,
357 PsProcessType,
358 PreviousMode,
359 (PVOID*)&Process,
360 NULL);
361 if (!NT_SUCCESS(Status)) break;
362
363 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
364
365 /* Dereference the process */
366 ObDereferenceObject(Process);
367 Status = STATUS_NOT_IMPLEMENTED;
368 break;
369
370 case ProcessHandleCount:
371
372 /* Set the return length*/
373 Length = sizeof(ULONG);
374
375 if (ProcessInformationLength != Length)
376 {
377 Status = STATUS_INFO_LENGTH_MISMATCH;
378 break;
379 }
380
381 /* Reference the process */
382 Status = ObReferenceObjectByHandle(ProcessHandle,
383 PROCESS_QUERY_INFORMATION,
384 PsProcessType,
385 PreviousMode,
386 (PVOID*)&Process,
387 NULL);
388 if (!NT_SUCCESS(Status)) break;
389
390 /* Count the number of handles this process has */
391 HandleCount = ObGetProcessHandleCount(Process);
392
393 /* Protect write in SEH */
394 _SEH2_TRY
395 {
396 /* Return the count of handles */
397 *(PULONG)ProcessInformation = HandleCount;
398 }
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
400 {
401 /* Get the exception code */
402 Status = _SEH2_GetExceptionCode();
403 }
404 _SEH2_END;
405
406 /* Dereference the process */
407 ObDereferenceObject(Process);
408 break;
409
410 /* Session ID for the process */
411 case ProcessSessionInformation:
412
413 /* Set the return length*/
414 Length = sizeof(PROCESS_SESSION_INFORMATION);
415
416 if (ProcessInformationLength != Length)
417 {
418 Status = STATUS_INFO_LENGTH_MISMATCH;
419 break;
420 }
421
422 /* Reference the process */
423 Status = ObReferenceObjectByHandle(ProcessHandle,
424 PROCESS_QUERY_INFORMATION,
425 PsProcessType,
426 PreviousMode,
427 (PVOID*)&Process,
428 NULL);
429 if (!NT_SUCCESS(Status)) break;
430
431 /* Enter SEH for write safety */
432 _SEH2_TRY
433 {
434 /* Write back the Session ID */
435 SessionInfo->SessionId = PtrToUlong(Process->Session);
436 }
437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
438 {
439 /* Get the exception code */
440 Status = _SEH2_GetExceptionCode();
441 }
442 _SEH2_END;
443
444 /* Dereference the process */
445 ObDereferenceObject(Process);
446 break;
447
448 /* WOW64: Not implemented */
449 case ProcessWow64Information:
450
451 /* Set the return length */
452 Length = sizeof(ULONG_PTR);
453
454 if (ProcessInformationLength != Length)
455 {
456 Status = STATUS_INFO_LENGTH_MISMATCH;
457 break;
458 }
459
460 /* Reference the process */
461 Status = ObReferenceObjectByHandle(ProcessHandle,
462 PROCESS_QUERY_INFORMATION,
463 PsProcessType,
464 PreviousMode,
465 (PVOID*)&Process,
466 NULL);
467 if (!NT_SUCCESS(Status)) break;
468
469 DPRINT1("Not implemented: ProcessWow64Information\n");
470
471 /* Dereference the process */
472 ObDereferenceObject(Process);
473 Status = STATUS_NOT_IMPLEMENTED;
474 break;
475
476 /* Virtual Memory Statistics */
477 case ProcessVmCounters:
478
479 /* Set the return length */
480 Length = sizeof(VM_COUNTERS);
481
482 if (ProcessInformationLength != Length)
483 {
484 Status = STATUS_INFO_LENGTH_MISMATCH;
485 break;
486 }
487
488 /* Reference the process */
489 Status = ObReferenceObjectByHandle(ProcessHandle,
490 PROCESS_QUERY_INFORMATION,
491 PsProcessType,
492 PreviousMode,
493 (PVOID*)&Process,
494 NULL);
495 if (!NT_SUCCESS(Status)) break;
496
497 /* Enter SEH for write safety */
498 _SEH2_TRY
499 {
500 /* Return data from EPROCESS */
501 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
502 VmCounters->VirtualSize = Process->VirtualSize;
503 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
504 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
505 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
506 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
507 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
508 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
509 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
510 VmCounters->PagefileUsage = Process->QuotaUsage[2];
511 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
512
513 }
514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
515 {
516 /* Get the exception code */
517 Status = _SEH2_GetExceptionCode();
518 }
519 _SEH2_END;
520
521 /* Dereference the process */
522 ObDereferenceObject(Process);
523 break;
524
525 /* Hard Error Processing Mode */
526 case ProcessDefaultHardErrorMode:
527
528 /* Set the return length*/
529 Length = sizeof(ULONG);
530
531 if (ProcessInformationLength != Length)
532 {
533 Status = STATUS_INFO_LENGTH_MISMATCH;
534 break;
535 }
536
537 /* Reference the process */
538 Status = ObReferenceObjectByHandle(ProcessHandle,
539 PROCESS_QUERY_INFORMATION,
540 PsProcessType,
541 PreviousMode,
542 (PVOID*)&Process,
543 NULL);
544 if (!NT_SUCCESS(Status)) break;
545
546 /* Enter SEH for writing back data */
547 _SEH2_TRY
548 {
549 /* Write the current processing mode */
550 *(PULONG)ProcessInformation = Process->
551 DefaultHardErrorProcessing;
552 }
553 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
554 {
555 /* Get the exception code */
556 Status = _SEH2_GetExceptionCode();
557 }
558 _SEH2_END;
559
560 /* Dereference the process */
561 ObDereferenceObject(Process);
562 break;
563
564 /* Priority Boosting status */
565 case ProcessPriorityBoost:
566
567 /* Set the return length*/
568 Length = sizeof(ULONG);
569
570 if (ProcessInformationLength != Length)
571 {
572 Status = STATUS_INFO_LENGTH_MISMATCH;
573 break;
574 }
575
576 /* Reference the process */
577 Status = ObReferenceObjectByHandle(ProcessHandle,
578 PROCESS_QUERY_INFORMATION,
579 PsProcessType,
580 PreviousMode,
581 (PVOID*)&Process,
582 NULL);
583 if (!NT_SUCCESS(Status)) break;
584
585 /* Enter SEH for writing back data */
586 _SEH2_TRY
587 {
588 /* Return boost status */
589 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
590 TRUE : FALSE;
591 }
592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
593 {
594 /* Get the exception code */
595 Status = _SEH2_GetExceptionCode();
596 }
597 _SEH2_END;
598
599 /* Dereference the process */
600 ObDereferenceObject(Process);
601 break;
602
603 /* DOS Device Map */
604 case ProcessDeviceMap:
605
606 /* Set the return length*/
607 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
608
609 if (ProcessInformationLength != Length)
610 {
611 Status = STATUS_INFO_LENGTH_MISMATCH;
612 break;
613 }
614
615 /* Reference the process */
616 Status = ObReferenceObjectByHandle(ProcessHandle,
617 PROCESS_QUERY_INFORMATION,
618 PsProcessType,
619 PreviousMode,
620 (PVOID*)&Process,
621 NULL);
622 if (!NT_SUCCESS(Status)) break;
623
624 /* Query the device map information */
625 ObQueryDeviceMapInformation(Process, &DeviceMap);
626
627 /* Enter SEH for writing back data */
628 _SEH2_TRY
629 {
630 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
631 }
632 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
633 {
634 /* Get the exception code */
635 Status = _SEH2_GetExceptionCode();
636 }
637 _SEH2_END;
638
639 /* Dereference the process */
640 ObDereferenceObject(Process);
641 break;
642
643 /* Priority class */
644 case ProcessPriorityClass:
645
646 /* Set the return length*/
647 Length = sizeof(PROCESS_PRIORITY_CLASS);
648
649 if (ProcessInformationLength != Length)
650 {
651 Status = STATUS_INFO_LENGTH_MISMATCH;
652 break;
653 }
654
655 /* Reference the process */
656 Status = ObReferenceObjectByHandle(ProcessHandle,
657 PROCESS_QUERY_INFORMATION,
658 PsProcessType,
659 PreviousMode,
660 (PVOID*)&Process,
661 NULL);
662 if (!NT_SUCCESS(Status)) break;
663
664 /* Enter SEH for writing back data */
665 _SEH2_TRY
666 {
667 /* Return current priority class */
668 PsPriorityClass->PriorityClass = Process->PriorityClass;
669 PsPriorityClass->Foreground = FALSE;
670 }
671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
672 {
673 /* Get the exception code */
674 Status = _SEH2_GetExceptionCode();
675 }
676 _SEH2_END;
677
678 /* Dereference the process */
679 ObDereferenceObject(Process);
680 break;
681
682 case ProcessImageFileName:
683
684 /* Reference the process */
685 Status = ObReferenceObjectByHandle(ProcessHandle,
686 PROCESS_QUERY_INFORMATION,
687 PsProcessType,
688 PreviousMode,
689 (PVOID*)&Process,
690 NULL);
691 if (!NT_SUCCESS(Status)) break;
692
693 /* Get the image path */
694 Status = SeLocateProcessImageName(Process, &ImageName);
695 if (NT_SUCCESS(Status))
696 {
697 /* Set return length */
698 Length = ImageName->MaximumLength +
699 sizeof(OBJECT_NAME_INFORMATION);
700
701 /* Make sure it's large enough */
702 if (Length <= ProcessInformationLength)
703 {
704 /* Enter SEH to protect write */
705 _SEH2_TRY
706 {
707 /* Copy it */
708 RtlCopyMemory(ProcessInformation,
709 ImageName,
710 Length);
711
712 /* Update pointer */
713 ((PUNICODE_STRING)ProcessInformation)->Buffer =
714 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
715 }
716 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
717 {
718 /* Get the exception code */
719 Status = _SEH2_GetExceptionCode();
720 }
721 _SEH2_END;
722 }
723 else
724 {
725 /* Buffer too small */
726 Status = STATUS_INFO_LENGTH_MISMATCH;
727 }
728
729 /* Free the image path */
730 ExFreePool(ImageName);
731 }
732 /* Dereference the process */
733 ObDereferenceObject(Process);
734 break;
735
736 /* Per-process security cookie */
737 case ProcessCookie:
738
739 /* Get the current process and cookie */
740 Process = PsGetCurrentProcess();
741 Cookie = Process->Cookie;
742 if (!Cookie)
743 {
744 LARGE_INTEGER SystemTime;
745 ULONG NewCookie;
746 PKPRCB Prcb;
747
748 /* Generate a new cookie */
749 KeQuerySystemTime(&SystemTime);
750 Prcb = KeGetCurrentPrcb();
751 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
752 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
753
754 /* Set the new cookie or return the current one */
755 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
756 NewCookie,
757 Cookie);
758 if (!Cookie) Cookie = NewCookie;
759
760 /* Set return length */
761 Length = sizeof(ULONG);
762 }
763
764 /* Enter SEH to protect write */
765 _SEH2_TRY
766 {
767 /* Write back the cookie */
768 *(PULONG)ProcessInformation = Cookie;
769 }
770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
771 {
772 /* Get the exception code */
773 Status = _SEH2_GetExceptionCode();
774 }
775 _SEH2_END;
776 break;
777
778 /* Not yet implemented, or unknown */
779 case ProcessBasePriority:
780 case ProcessRaisePriority:
781 case ProcessExceptionPort:
782 case ProcessAccessToken:
783 case ProcessLdtSize:
784 case ProcessIoPortHandlers:
785 case ProcessUserModeIOPL:
786 case ProcessEnableAlignmentFaultFixup:
787 case ProcessAffinityMask:
788 case ProcessForegroundInformation:
789 default:
790 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
791 Status = STATUS_INVALID_INFO_CLASS;
792 }
793
794 /* Protect write with SEH */
795 _SEH2_TRY
796 {
797 /* Check if caller wanted return length */
798 if (ReturnLength) *ReturnLength = Length;
799 }
800 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
801 {
802 /* Get exception code */
803 Status = _SEH2_GetExceptionCode();
804 }
805 _SEH2_END;
806
807 return Status;
808 }
809
810 /*
811 * @implemented
812 */
813 NTSTATUS
814 NTAPI
815 NtSetInformationProcess(IN HANDLE ProcessHandle,
816 IN PROCESSINFOCLASS ProcessInformationClass,
817 IN PVOID ProcessInformation,
818 IN ULONG ProcessInformationLength)
819 {
820 PEPROCESS Process;
821 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
822 ACCESS_MASK Access;
823 NTSTATUS Status;
824 HANDLE PortHandle = NULL;
825 HANDLE TokenHandle = NULL;
826 PROCESS_SESSION_INFORMATION SessionInfo = {0};
827 PROCESS_PRIORITY_CLASS PriorityClass = {0};
828 PVOID ExceptionPort;
829 PAGED_CODE();
830
831 /* Verify Information Class validity */
832 #if 0
833 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
834 PsProcessInfoClass,
835 RTL_NUMBER_OF(PsProcessInfoClass),
836 ProcessInformation,
837 ProcessInformationLength,
838 PreviousMode);
839 if (!NT_SUCCESS(Status)) return Status;
840 #endif
841
842 /* Check what class this is */
843 Access = PROCESS_SET_INFORMATION;
844 if (ProcessInformationClass == ProcessSessionInformation)
845 {
846 /* Setting the Session ID needs a special mask */
847 Access |= PROCESS_SET_SESSIONID;
848 }
849 else if (ProcessInformationClass == ProcessExceptionPort)
850 {
851 /* Setting the exception port needs a special mask */
852 Access |= PROCESS_SUSPEND_RESUME;
853 }
854
855 /* Reference the process */
856 Status = ObReferenceObjectByHandle(ProcessHandle,
857 Access,
858 PsProcessType,
859 PreviousMode,
860 (PVOID*)&Process,
861 NULL);
862 if (!NT_SUCCESS(Status)) return Status;
863
864 /* Check what kind of information class this is */
865 switch (ProcessInformationClass)
866 {
867 /* Error/Exception Port */
868 case ProcessExceptionPort:
869
870 /* Check buffer length */
871 if (ProcessInformationLength != sizeof(HANDLE))
872 {
873 Status = STATUS_INFO_LENGTH_MISMATCH;
874 break;
875 }
876
877 /* Use SEH for capture */
878 _SEH2_TRY
879 {
880 /* Capture the handle */
881 PortHandle = *(PHANDLE)ProcessInformation;
882 }
883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
884 {
885 /* Get the exception code */
886 Status = _SEH2_GetExceptionCode();
887 }
888 _SEH2_END;
889 if (!NT_SUCCESS(Status)) break;
890
891 /* Get the LPC Port */
892 Status = ObReferenceObjectByHandle(PortHandle,
893 0,
894 LpcPortObjectType,
895 PreviousMode,
896 (PVOID)&ExceptionPort,
897 NULL);
898 if (!NT_SUCCESS(Status)) break;
899
900 /* Change the pointer */
901 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
902 ExceptionPort,
903 NULL))
904 {
905 /* We already had one, fail */
906 ObDereferenceObject(ExceptionPort);
907 Status = STATUS_PORT_ALREADY_SET;
908 }
909 break;
910
911 /* Security Token */
912 case ProcessAccessToken:
913
914 /* Check buffer length */
915 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
916 {
917 Status = STATUS_INFO_LENGTH_MISMATCH;
918 break;
919 }
920
921 /* Use SEH for capture */
922 _SEH2_TRY
923 {
924 /* Save the token handle */
925 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
926 Token;
927 }
928 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
929 {
930 /* Get the exception code */
931 Status = _SEH2_GetExceptionCode();
932 }
933 _SEH2_END;
934 if (!NT_SUCCESS(Status)) break;
935
936 /* Assign the actual token */
937 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
938 break;
939
940 /* Hard error processing */
941 case ProcessDefaultHardErrorMode:
942
943 /* Check buffer length */
944 if (ProcessInformationLength != sizeof(ULONG))
945 {
946 Status = STATUS_INFO_LENGTH_MISMATCH;
947 break;
948 }
949
950 /* Enter SEH for direct buffer read */
951 _SEH2_TRY
952 {
953 /* Update the current mode abd return the previous one */
954 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
955 *(PLONG)ProcessInformation);
956 }
957 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
958 {
959 /* Get exception code */
960 Status = _SEH2_GetExceptionCode();
961 }
962 _SEH2_END;
963 break;
964
965 /* Session ID */
966 case ProcessSessionInformation:
967
968 /* Check buffer length */
969 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
970 {
971 Status = STATUS_INFO_LENGTH_MISMATCH;
972 break;
973 }
974
975 /* Enter SEH for capture */
976 _SEH2_TRY
977 {
978 /* Capture the caller's buffer */
979 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
980 }
981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
982 {
983 /* Get the exception code */
984 Status = _SEH2_GetExceptionCode();
985 }
986 _SEH2_END;
987 if (!NT_SUCCESS(Status)) break;
988
989 /* Setting the session id requires the SeTcbPrivilege */
990 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
991 {
992 /* Can't set the session ID, bail out. */
993 Status = STATUS_PRIVILEGE_NOT_HELD;
994 break;
995 }
996
997 /* FIXME - update the session id for the process token */
998 //Status = PsLockProcess(Process, FALSE);
999 if (!NT_SUCCESS(Status)) break;
1000
1001 /* Write the session ID in the EPROCESS */
1002 Process->Session = SessionInfo.SessionId;
1003
1004 /* Check if the process also has a PEB */
1005 if (Process->Peb)
1006 {
1007 /*
1008 * Attach to the process to make sure we're in the right
1009 * context to access the PEB structure
1010 */
1011 KeAttachProcess(&Process->Pcb);
1012
1013 /* Enter SEH for write to user-mode PEB */
1014 _SEH2_TRY
1015 {
1016 /* Write the session ID */
1017 Process->Peb->SessionId = SessionInfo.SessionId;
1018 }
1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1020 {
1021 /* Get exception code */
1022 Status = _SEH2_GetExceptionCode();
1023 }
1024 _SEH2_END;
1025
1026 /* Detach from the process */
1027 KeDetachProcess();
1028 }
1029
1030 /* Unlock the process */
1031 //PsUnlockProcess(Process);
1032 break;
1033
1034 case ProcessPriorityClass:
1035
1036 /* Check buffer length */
1037 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1038 {
1039 Status = STATUS_INFO_LENGTH_MISMATCH;
1040 break;
1041 }
1042
1043 /* Enter SEH for capture */
1044 _SEH2_TRY
1045 {
1046 /* Capture the caller's buffer */
1047 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1048 }
1049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1050 {
1051 /* Get the exception code */
1052 Status = _SEH2_GetExceptionCode();
1053 }
1054 _SEH2_END;
1055 if (!NT_SUCCESS(Status)) break;
1056
1057 /* Check for invalid PriorityClass value */
1058 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1059 {
1060 Status = STATUS_INVALID_PARAMETER;
1061 break;
1062 }
1063
1064 /* TODO: Check privileges */
1065
1066 /* Check if we have a job */
1067 if (Process->Job)
1068 {
1069 DPRINT1("Jobs not yet supported\n");
1070 }
1071
1072 /* Set process priority class */
1073 Process->PriorityClass = PriorityClass.PriorityClass;
1074
1075 /* Set process priority mode (foreground or background) */
1076 PsSetProcessPriorityByClass(Process,
1077 !PriorityClass.Foreground ? PsProcessPriorityBackground :
1078 PsProcessPriorityForeground);
1079
1080 Status = STATUS_SUCCESS;
1081 break;
1082
1083 case ProcessQuotaLimits:
1084
1085 /* Check buffer length */
1086 if (ProcessInformationLength != sizeof(QUOTA_LIMITS))
1087 {
1088 Status = STATUS_INFO_LENGTH_MISMATCH;
1089 break;
1090 }
1091
1092 DPRINT1("Not implemented: ProcessQuotaLimits\n");
1093 Status = STATUS_NOT_IMPLEMENTED;
1094 break;
1095
1096 case ProcessBasePriority:
1097
1098 /* Check buffer length */
1099 if (ProcessInformationLength != sizeof(KPRIORITY))
1100 {
1101 Status = STATUS_INFO_LENGTH_MISMATCH;
1102 break;
1103 }
1104
1105 DPRINT1("Not implemented: ProcessBasePriority\n");
1106 Status = STATUS_NOT_IMPLEMENTED;
1107 break;
1108
1109 case ProcessRaisePriority:
1110
1111 /* Check buffer length */
1112 if (ProcessInformationLength != sizeof(ULONG))
1113 {
1114 Status = STATUS_INFO_LENGTH_MISMATCH;
1115 break;
1116 }
1117
1118 DPRINT1("Not implemented: ProcessRaisePriority\n");
1119 Status = STATUS_NOT_IMPLEMENTED;
1120 break;
1121
1122 case ProcessWx86Information:
1123
1124 /* Check buffer length */
1125 if (ProcessInformationLength != sizeof(HANDLE))
1126 {
1127 Status = STATUS_INFO_LENGTH_MISMATCH;
1128 break;
1129 }
1130
1131 DPRINT1("Not implemented: ProcessWx86Information\n");
1132 Status = STATUS_NOT_IMPLEMENTED;
1133 break;
1134
1135 case ProcessDebugPort:
1136
1137 /* Check buffer length */
1138 if (ProcessInformationLength != sizeof(HANDLE))
1139 {
1140 Status = STATUS_INFO_LENGTH_MISMATCH;
1141 break;
1142 }
1143
1144 DPRINT1("Not implemented: ProcessDebugPort\n");
1145 Status = STATUS_NOT_IMPLEMENTED;
1146 break;
1147
1148 /* We currently don't implement any of these */
1149 case ProcessLdtInformation:
1150 case ProcessLdtSize:
1151 case ProcessIoPortHandlers:
1152 case ProcessWorkingSetWatch:
1153 case ProcessUserModeIOPL:
1154 case ProcessEnableAlignmentFaultFixup:
1155 case ProcessAffinityMask:
1156 DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
1157 Status = STATUS_NOT_IMPLEMENTED;
1158 break;
1159
1160 /* Supposedly these are invalid...!? verify! */
1161 case ProcessBasicInformation:
1162 case ProcessIoCounters:
1163 case ProcessTimes:
1164 case ProcessPooledUsageAndLimits:
1165 case ProcessHandleCount:
1166 case ProcessWow64Information:
1167 default:
1168 DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
1169 Status = STATUS_INVALID_INFO_CLASS;
1170 }
1171
1172 /* Dereference and return status */
1173 ObDereferenceObject(Process);
1174 return Status;
1175 }
1176
1177 /*
1178 * @implemented
1179 */
1180 NTSTATUS
1181 NTAPI
1182 NtSetInformationThread(IN HANDLE ThreadHandle,
1183 IN THREADINFOCLASS ThreadInformationClass,
1184 IN PVOID ThreadInformation,
1185 IN ULONG ThreadInformationLength)
1186 {
1187 PETHREAD Thread;
1188 ULONG Access;
1189 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1190 NTSTATUS Status;
1191 HANDLE TokenHandle = NULL;
1192 KPRIORITY Priority = 0;
1193 KAFFINITY Affinity = 0, CombinedAffinity;
1194 PVOID Address = NULL;
1195 PEPROCESS Process;
1196 ULONG DisableBoost = 0;
1197 ULONG IdealProcessor = 0;
1198 PTEB Teb;
1199 ULONG TlsIndex = 0;
1200 PVOID *ExpansionSlots;
1201 PETHREAD ProcThread;
1202 PAGED_CODE();
1203
1204 /* Verify Information Class validity */
1205 #if 0
1206 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1207 PsThreadInfoClass,
1208 RTL_NUMBER_OF(PsThreadInfoClass),
1209 ThreadInformation,
1210 ThreadInformationLength,
1211 PreviousMode);
1212 if (!NT_SUCCESS(Status)) return Status;
1213 #endif
1214
1215 /* Check what class this is */
1216 Access = THREAD_SET_INFORMATION;
1217 if (ThreadInformationClass == ThreadImpersonationToken)
1218 {
1219 /* Setting the impersonation token needs a special mask */
1220 Access = THREAD_SET_THREAD_TOKEN;
1221 }
1222
1223 /* Reference the process */
1224 Status = ObReferenceObjectByHandle(ThreadHandle,
1225 Access,
1226 PsThreadType,
1227 PreviousMode,
1228 (PVOID*)&Thread,
1229 NULL);
1230 if (!NT_SUCCESS(Status)) return Status;
1231
1232 /* Check what kind of information class this is */
1233 switch (ThreadInformationClass)
1234 {
1235 /* Thread priority */
1236 case ThreadPriority:
1237
1238 /* Check buffer length */
1239 if (ThreadInformationLength != sizeof(KPRIORITY))
1240 {
1241 Status = STATUS_INFO_LENGTH_MISMATCH;
1242 break;
1243 }
1244
1245 /* Use SEH for capture */
1246 _SEH2_TRY
1247 {
1248 /* Get the priority */
1249 Priority = *(PLONG)ThreadInformation;
1250 }
1251 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1252 {
1253 /* Get the exception code */
1254 Status = _SEH2_GetExceptionCode();
1255 }
1256 _SEH2_END;
1257 if (!NT_SUCCESS(Status)) break;
1258
1259 /* Validate it */
1260 if ((Priority > HIGH_PRIORITY) ||
1261 (Priority <= LOW_PRIORITY))
1262 {
1263 /* Fail */
1264 Status = STATUS_INVALID_PARAMETER;
1265 break;
1266 }
1267
1268 /* Set the priority */
1269 KeSetPriorityThread(&Thread->Tcb, Priority);
1270 break;
1271
1272 case ThreadBasePriority:
1273
1274 /* Check buffer length */
1275 if (ThreadInformationLength != sizeof(LONG))
1276 {
1277 Status = STATUS_INFO_LENGTH_MISMATCH;
1278 break;
1279 }
1280
1281 /* Use SEH for capture */
1282 _SEH2_TRY
1283 {
1284 /* Get the priority */
1285 Priority = *(PLONG)ThreadInformation;
1286 }
1287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1288 {
1289 /* Get the exception code */
1290 Status = _SEH2_GetExceptionCode();
1291 }
1292 _SEH2_END;
1293 if (!NT_SUCCESS(Status)) break;
1294
1295 /* Validate it */
1296 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
1297 (Priority < THREAD_BASE_PRIORITY_MIN))
1298 {
1299 /* These ones are OK */
1300 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
1301 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
1302 {
1303 /* Check if the process is real time */
1304 if (PsGetCurrentProcess()->PriorityClass !=
1305 PROCESS_PRIORITY_CLASS_REALTIME)
1306 {
1307 /* It isn't, fail */
1308 Status = STATUS_INVALID_PARAMETER;
1309 break;
1310 }
1311 }
1312 }
1313
1314 /* Set the base priority */
1315 KeSetBasePriorityThread(&Thread->Tcb, Priority);
1316 break;
1317
1318 case ThreadAffinityMask:
1319
1320 /* Check buffer length */
1321 if (ThreadInformationLength != sizeof(ULONG_PTR))
1322 {
1323 Status = STATUS_INFO_LENGTH_MISMATCH;
1324 break;
1325 }
1326
1327 /* Use SEH for capture */
1328 _SEH2_TRY
1329 {
1330 /* Get the priority */
1331 Affinity = *(PULONG_PTR)ThreadInformation;
1332 }
1333 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1334 {
1335 /* Get the exception code */
1336 Status = _SEH2_GetExceptionCode();
1337 }
1338 _SEH2_END;
1339 if (!NT_SUCCESS(Status)) break;
1340
1341 /* Validate it */
1342 if (!Affinity)
1343 {
1344 /* Fail */
1345 Status = STATUS_INVALID_PARAMETER;
1346 break;
1347 }
1348
1349 /* Get the process */
1350 Process = Thread->ThreadsProcess;
1351
1352 /* Try to acquire rundown */
1353 if (ExAcquireRundownProtection(&Process->RundownProtect))
1354 {
1355 /* Lock it */
1356 KeEnterCriticalRegion();
1357 ExAcquirePushLockShared(&Process->ProcessLock);
1358
1359 /* Combine masks */
1360 CombinedAffinity = Affinity & Process->Pcb.Affinity;
1361 if (CombinedAffinity != Affinity)
1362 {
1363 /* Fail */
1364 Status = STATUS_INVALID_PARAMETER;
1365 }
1366 else
1367 {
1368 /* Set the affinity */
1369 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
1370 }
1371
1372 /* Release the lock and rundown */
1373 ExReleasePushLockShared(&Process->ProcessLock);
1374 KeLeaveCriticalRegion();
1375 ExReleaseRundownProtection(&Process->RundownProtect);
1376 }
1377 else
1378 {
1379 /* Too late */
1380 Status = STATUS_PROCESS_IS_TERMINATING;
1381 }
1382
1383 /* Return status */
1384 break;
1385
1386 case ThreadImpersonationToken:
1387
1388 /* Check buffer length */
1389 if (ThreadInformationLength != sizeof(HANDLE))
1390 {
1391 Status = STATUS_INFO_LENGTH_MISMATCH;
1392 break;
1393 }
1394
1395 /* Use SEH for capture */
1396 _SEH2_TRY
1397 {
1398 /* Save the token handle */
1399 TokenHandle = *(PHANDLE)ThreadInformation;
1400 }
1401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1402 {
1403 /* Get the exception code */
1404 Status = _SEH2_GetExceptionCode();
1405 }
1406 _SEH2_END;
1407 if (!NT_SUCCESS(Status)) break;
1408
1409 /* Assign the actual token */
1410 Status = PsAssignImpersonationToken(Thread, TokenHandle);
1411 break;
1412
1413 case ThreadQuerySetWin32StartAddress:
1414
1415 /* Check buffer length */
1416 if (ThreadInformationLength != sizeof(ULONG_PTR))
1417 {
1418 Status = STATUS_INFO_LENGTH_MISMATCH;
1419 break;
1420 }
1421
1422 /* Use SEH for capture */
1423 _SEH2_TRY
1424 {
1425 /* Get the priority */
1426 Address = *(PVOID*)ThreadInformation;
1427 }
1428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1429 {
1430 /* Get the exception code */
1431 Status = _SEH2_GetExceptionCode();
1432 }
1433 _SEH2_END;
1434 if (!NT_SUCCESS(Status)) break;
1435
1436 /* Set the address */
1437 Thread->Win32StartAddress = Address;
1438 break;
1439
1440 case ThreadIdealProcessor:
1441
1442 /* Check buffer length */
1443 if (ThreadInformationLength != sizeof(ULONG_PTR))
1444 {
1445 Status = STATUS_INFO_LENGTH_MISMATCH;
1446 break;
1447 }
1448
1449 /* Use SEH for capture */
1450 _SEH2_TRY
1451 {
1452 /* Get the priority */
1453 IdealProcessor = *(PULONG_PTR)ThreadInformation;
1454 }
1455 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1456 {
1457 /* Get the exception code */
1458 Status = _SEH2_GetExceptionCode();
1459 }
1460 _SEH2_END;
1461 if (!NT_SUCCESS(Status)) break;
1462
1463 /* Validate it */
1464 if (IdealProcessor > MAXIMUM_PROCESSORS)
1465 {
1466 /* Fail */
1467 Status = STATUS_INVALID_PARAMETER;
1468 break;
1469 }
1470
1471 /* Set the ideal */
1472 Status = KeSetIdealProcessorThread(&Thread->Tcb,
1473 (CCHAR)IdealProcessor);
1474
1475 /* Get the TEB and protect the thread */
1476 Teb = Thread->Tcb.Teb;
1477 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
1478 {
1479 /* Save the ideal processor */
1480 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
1481
1482 /* Release rundown protection */
1483 ExReleaseRundownProtection(&Thread->RundownProtect);
1484 }
1485
1486 break;
1487
1488 case ThreadPriorityBoost:
1489
1490 /* Check buffer length */
1491 if (ThreadInformationLength != sizeof(ULONG_PTR))
1492 {
1493 Status = STATUS_INFO_LENGTH_MISMATCH;
1494 break;
1495 }
1496
1497 /* Use SEH for capture */
1498 _SEH2_TRY
1499 {
1500 /* Get the priority */
1501 DisableBoost = *(PULONG_PTR)ThreadInformation;
1502 }
1503 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1504 {
1505 /* Get the exception code */
1506 Status = _SEH2_GetExceptionCode();
1507 }
1508 _SEH2_END;
1509 if (!NT_SUCCESS(Status)) break;
1510
1511 /* Call the kernel */
1512 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
1513 break;
1514
1515 case ThreadZeroTlsCell:
1516
1517 /* Check buffer length */
1518 if (ThreadInformationLength != sizeof(ULONG_PTR))
1519 {
1520 Status = STATUS_INFO_LENGTH_MISMATCH;
1521 break;
1522 }
1523
1524 /* Use SEH for capture */
1525 _SEH2_TRY
1526 {
1527 /* Get the priority */
1528 TlsIndex = *(PULONG_PTR)ThreadInformation;
1529 }
1530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1531 {
1532 /* Get the exception code */
1533 Status = _SEH2_GetExceptionCode();
1534 }
1535 _SEH2_END;
1536 if (!NT_SUCCESS(Status)) break;
1537
1538 /* This is only valid for the current thread */
1539 if (Thread != PsGetCurrentThread())
1540 {
1541 /* Fail */
1542 Status = STATUS_INVALID_PARAMETER;
1543 break;
1544 }
1545
1546 /* Get the process */
1547 Process = Thread->ThreadsProcess;
1548
1549 /* Loop the threads */
1550 ProcThread = PsGetNextProcessThread(Process, NULL);
1551 while (ProcThread)
1552 {
1553 /* Acquire rundown */
1554 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
1555 {
1556 /* Get the TEB */
1557 Teb = ProcThread->Tcb.Teb;
1558 if (Teb)
1559 {
1560 /* Check if we're in the expansion range */
1561 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
1562 {
1563 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
1564 TLS_EXPANSION_SLOTS) - 1)
1565 {
1566 /* Check if we have expansion slots */
1567 ExpansionSlots = Teb->TlsExpansionSlots;
1568 if (ExpansionSlots)
1569 {
1570 /* Clear the index */
1571 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
1572 }
1573 }
1574 }
1575 else
1576 {
1577 /* Clear the index */
1578 Teb->TlsSlots[TlsIndex] = NULL;
1579 }
1580 }
1581
1582 /* Release rundown */
1583 ExReleaseRundownProtection(&ProcThread->RundownProtect);
1584 }
1585
1586 /* Go to the next thread */
1587 ProcThread = PsGetNextProcessThread(Process, ProcThread);
1588 }
1589
1590 /* All done */
1591 break;
1592
1593 default:
1594 /* We don't implement it yet */
1595 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1596 Status = STATUS_NOT_IMPLEMENTED;
1597 }
1598
1599 /* Dereference and return status */
1600 ObDereferenceObject(Thread);
1601 return Status;
1602 }
1603
1604 /*
1605 * @implemented
1606 */
1607 NTSTATUS
1608 NTAPI
1609 NtQueryInformationThread(IN HANDLE ThreadHandle,
1610 IN THREADINFOCLASS ThreadInformationClass,
1611 OUT PVOID ThreadInformation,
1612 IN ULONG ThreadInformationLength,
1613 OUT PULONG ReturnLength OPTIONAL)
1614 {
1615 PETHREAD Thread;
1616 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1617 NTSTATUS Status = STATUS_SUCCESS;
1618 ULONG Access;
1619 ULONG Length = 0;
1620 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
1621 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
1622 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
1623 KIRQL OldIrql;
1624 PAGED_CODE();
1625
1626 if (PreviousMode != KernelMode)
1627 {
1628 _SEH2_TRY
1629 {
1630 ProbeForWrite(ThreadInformation,
1631 ThreadInformationLength,
1632 sizeof(ULONG));
1633
1634 if (ReturnLength)
1635 {
1636 ProbeForWriteUlong(ReturnLength);
1637 }
1638 }
1639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1640 {
1641 Status = _SEH2_GetExceptionCode();
1642 }
1643 _SEH2_END;
1644
1645 if (!NT_SUCCESS(Status)) return Status;
1646 }
1647
1648 /* Check what class this is */
1649 Access = THREAD_QUERY_INFORMATION;
1650
1651 /* Reference the process */
1652 Status = ObReferenceObjectByHandle(ThreadHandle,
1653 Access,
1654 PsThreadType,
1655 PreviousMode,
1656 (PVOID*)&Thread,
1657 NULL);
1658 if (!NT_SUCCESS(Status)) return Status;
1659
1660 /* Check what kind of information class this is */
1661 switch (ThreadInformationClass)
1662 {
1663 /* Basic thread information */
1664 case ThreadBasicInformation:
1665
1666 /* Set return length */
1667 Length = sizeof(THREAD_BASIC_INFORMATION);
1668
1669 if (ThreadInformationLength != Length)
1670 {
1671 Status = STATUS_INFO_LENGTH_MISMATCH;
1672 break;
1673 }
1674 /* Protect writes with SEH */
1675 _SEH2_TRY
1676 {
1677 /* Write all the information from the ETHREAD/KTHREAD */
1678 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
1679 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1680 ThreadBasicInfo->ClientId = Thread->Cid;
1681 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
1682 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
1683 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1684 }
1685 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1686 {
1687 /* Get exception code */
1688 Status = _SEH2_GetExceptionCode();
1689 }
1690 _SEH2_END;
1691 break;
1692
1693 /* Thread time information */
1694 case ThreadTimes:
1695
1696 /* Set the return length */
1697 Length = sizeof(KERNEL_USER_TIMES);
1698
1699 if (ThreadInformationLength != Length)
1700 {
1701 Status = STATUS_INFO_LENGTH_MISMATCH;
1702 break;
1703 }
1704 /* Protect writes with SEH */
1705 _SEH2_TRY
1706 {
1707 /* Copy time information from ETHREAD/KTHREAD */
1708 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
1709 100000LL;
1710 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
1711 100000LL;
1712 ThreadTime->CreateTime = Thread->CreateTime;
1713 ThreadTime->ExitTime = Thread->ExitTime;
1714 }
1715 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1716 {
1717 /* Get exception code */
1718 Status = _SEH2_GetExceptionCode();
1719 }
1720 _SEH2_END;
1721 break;
1722
1723 case ThreadQuerySetWin32StartAddress:
1724
1725 /* Set the return length*/
1726 Length = sizeof(PVOID);
1727
1728 if (ThreadInformationLength != Length)
1729 {
1730 Status = STATUS_INFO_LENGTH_MISMATCH;
1731 break;
1732 }
1733 /* Protect write with SEH */
1734 _SEH2_TRY
1735 {
1736 /* Return the Win32 Start Address */
1737 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
1738 }
1739 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1740 {
1741 /* Get exception code */
1742 Status = _SEH2_GetExceptionCode();
1743 }
1744 _SEH2_END;
1745 break;
1746
1747 case ThreadPerformanceCount:
1748
1749 /* Set the return length*/
1750 Length = sizeof(LARGE_INTEGER);
1751
1752 if (ThreadInformationLength != Length)
1753 {
1754 Status = STATUS_INFO_LENGTH_MISMATCH;
1755 break;
1756 }
1757 /* Protect write with SEH */
1758 _SEH2_TRY
1759 {
1760 /* FIXME */
1761 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
1762 }
1763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1764 {
1765 /* Get exception code */
1766 Status = _SEH2_GetExceptionCode();
1767 }
1768 _SEH2_END;
1769 break;
1770
1771 case ThreadAmILastThread:
1772
1773 /* Set the return length*/
1774 Length = sizeof(ULONG);
1775
1776 if (ThreadInformationLength != Length)
1777 {
1778 Status = STATUS_INFO_LENGTH_MISMATCH;
1779 break;
1780 }
1781 /* Protect write with SEH */
1782 _SEH2_TRY
1783 {
1784 /* Return whether or not we are the last thread */
1785 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1786 ThreadListHead.Flink->Flink ==
1787 &Thread->ThreadsProcess->
1788 ThreadListHead) ?
1789 TRUE : FALSE);
1790 }
1791 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1792 {
1793 /* Get exception code */
1794 Status = _SEH2_GetExceptionCode();
1795 }
1796 _SEH2_END;
1797 break;
1798
1799 case ThreadIsIoPending:
1800
1801 /* Set the return length*/
1802 Length = sizeof(ULONG);
1803
1804 if (ThreadInformationLength != Length)
1805 {
1806 Status = STATUS_INFO_LENGTH_MISMATCH;
1807 break;
1808 }
1809 /* Raise the IRQL to protect the IRP list */
1810 KeRaiseIrql(APC_LEVEL, &OldIrql);
1811
1812 /* Protect write with SEH */
1813 _SEH2_TRY
1814 {
1815 /* Check if the IRP list is empty or not */
1816 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1817 }
1818 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1819 {
1820 /* Get exception code */
1821 Status = _SEH2_GetExceptionCode();
1822 }
1823 _SEH2_END;
1824
1825 /* Lower IRQL back */
1826 KeLowerIrql(OldIrql);
1827 break;
1828
1829 case ThreadDescriptorTableEntry:
1830 DPRINT1("NtQueryInformationThread(): case ThreadDescriptorTableEntry not implemented!\n");
1831 Status = STATUS_NOT_IMPLEMENTED;
1832 break;
1833
1834 case ThreadPriorityBoost:
1835
1836 /* Set the return length*/
1837 Length = sizeof(ULONG);
1838
1839 if (ThreadInformationLength != Length)
1840 {
1841 Status = STATUS_INFO_LENGTH_MISMATCH;
1842 break;
1843 }
1844
1845 _SEH2_TRY
1846 {
1847 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
1848 }
1849 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1850 {
1851 Status = _SEH2_GetExceptionCode();
1852 }
1853 _SEH2_END;
1854 break;
1855
1856 /* Anything else */
1857 default:
1858
1859 /* Not yet implemented */
1860 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1861 Status = STATUS_NOT_IMPLEMENTED;
1862 }
1863
1864 /* Protect write with SEH */
1865 _SEH2_TRY
1866 {
1867 /* Check if caller wanted return length */
1868 if (ReturnLength) *ReturnLength = Length;
1869 }
1870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1871 {
1872 /* Get exception code */
1873 Status = _SEH2_GetExceptionCode();
1874 }
1875 _SEH2_END;
1876
1877 /* Dereference the thread, and return */
1878 ObDereferenceObject(Thread);
1879 return Status;
1880 }
1881
1882 /* EOF */