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