- Change RtlMoveMemory to RtlCopyMemory where memory regions are never overlapping
[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 <internal/debug.h>
15
16 /* Include Information Class Tables */
17 #include "internal/ps_i.h"
18
19 /* Debugging Level */
20 ULONG PspTraceLevel = 0;//PS_KILL_DEBUG | PS_REF_DEBUG;
21
22 /* PRIVATE FUNCTIONS *********************************************************/
23
24 NTSTATUS
25 NTAPI
26 PsReferenceProcessFilePointer(IN PEPROCESS Process,
27 OUT PFILE_OBJECT *FileObject)
28 {
29 PROS_SECTION_OBJECT Section;
30 PAGED_CODE();
31
32 /* Lock the process */
33 ExAcquireRundownProtection(&Process->RundownProtect);
34
35 /* Get the section */
36 Section = (PROS_SECTION_OBJECT)Process->SectionObject;
37 if (Section)
38 {
39 /* Get the file object and reference it */
40 *FileObject = MmGetFileObjectForSection(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;
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 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
76 PUNICODE_STRING ImageName;
77 ULONG Cookie;
78 PAGED_CODE();
79
80 /* Check validity of Information Class */
81 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
82 PsProcessInfoClass,
83 RTL_NUMBER_OF(PsProcessInfoClass),
84 ProcessInformation,
85 ProcessInformationLength,
86 ReturnLength,
87 PreviousMode);
88 if (!NT_SUCCESS(Status)) return Status;
89
90 /* Check if this isn't the cookie class */
91 if(ProcessInformationClass != ProcessCookie)
92 {
93 /* Reference the process */
94 Status = ObReferenceObjectByHandle(ProcessHandle,
95 PROCESS_QUERY_INFORMATION,
96 PsProcessType,
97 PreviousMode,
98 (PVOID*)&Process,
99 NULL);
100 if (!NT_SUCCESS(Status)) return Status;
101 }
102 else if(ProcessHandle != NtCurrentProcess())
103 {
104 /*
105 * Retreiving the process cookie is only allowed for the calling process
106 * itself! XP only allowes NtCurrentProcess() as process handles even if
107 * a real handle actually represents the current process.
108 */
109 return STATUS_INVALID_PARAMETER;
110 }
111
112 /* Check the information class */
113 switch (ProcessInformationClass)
114 {
115 /* Basic process information */
116 case ProcessBasicInformation:
117
118 /* Protect writes with SEH */
119 _SEH_TRY
120 {
121 /* Write all the information from the EPROCESS/KPROCESS */
122 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
123 ProcessBasicInfo->PebBaseAddress = Process->Peb;
124 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
125 ProcessBasicInfo->UniqueProcessId = (ULONG)Process->
126 UniqueProcessId;
127 ProcessBasicInfo->InheritedFromUniqueProcessId =
128 (ULONG)Process->InheritedFromUniqueProcessId;
129 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
130
131 /* Set return length */
132 Length = sizeof(PROCESS_BASIC_INFORMATION);
133 }
134 _SEH_HANDLE
135 {
136 /* Get exception code */
137 Status = _SEH_GetExceptionCode();
138 }
139 _SEH_END;
140 break;
141
142 /* Quote limits and I/O Counters: not implemented */
143 case ProcessQuotaLimits:
144 case ProcessIoCounters:
145 Status = STATUS_NOT_IMPLEMENTED;
146 break;
147
148 /* Timing */
149 case ProcessTimes:
150
151 /* Protect writes with SEH */
152 _SEH_TRY
153 {
154 /* Copy time information from EPROCESS/KPROCESS */
155 ProcessTime->CreateTime = Process->CreateTime;
156 ProcessTime->UserTime.QuadPart = Process->Pcb.UserTime *
157 100000LL;
158 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
159 100000LL;
160 ProcessTime->ExitTime = Process->ExitTime;
161
162 /* Set the return length */
163 Length = sizeof(KERNEL_USER_TIMES);
164 }
165 _SEH_HANDLE
166 {
167 /* Get exception code */
168 Status = _SEH_GetExceptionCode();
169 }
170 _SEH_END;
171 break;
172
173 /* Process Debug Port */
174 case ProcessDebugPort:
175
176 /* Protect write with SEH */
177 _SEH_TRY
178 {
179 /* Return whether or not we have a debug port */
180 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
181 (HANDLE)-1 : NULL);
182
183 /* Set the return length*/
184 Length = sizeof(HANDLE);
185 }
186 _SEH_HANDLE
187 {
188 /* Get exception code */
189 Status = _SEH_GetExceptionCode();
190 }
191 _SEH_END;
192 break;
193
194 /* LDT, WS and VDM Information: not implemented */
195 case ProcessLdtInformation:
196 case ProcessWorkingSetWatch:
197 case ProcessWx86Information:
198 Status = STATUS_NOT_IMPLEMENTED;
199 break;
200
201 case ProcessHandleCount:
202
203 /* Count the number of handles this process has */
204 HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
205
206 /* Protect write in SEH */
207 _SEH_TRY
208 {
209 /* Return the count of handles */
210 *(PULONG)ProcessInformation = HandleCount;
211
212 /* Set the return length*/
213 Length = sizeof(ULONG);
214 }
215 _SEH_HANDLE
216 {
217 /* Get the exception code */
218 Status = _SEH_GetExceptionCode();
219 }
220 _SEH_END;
221 break;
222
223 /* Session ID for the process */
224 case ProcessSessionInformation:
225
226 /* Enter SEH for write safety */
227 _SEH_TRY
228 {
229 /* Write back the Session ID */
230 SessionInfo->SessionId = Process->Session;
231
232 /* Set the return length */
233 Length = sizeof(PROCESS_SESSION_INFORMATION);
234 }
235 _SEH_HANDLE
236 {
237 /* Get the exception code */
238 Status = _SEH_GetExceptionCode();
239 }
240 _SEH_END;
241 break;
242
243 /* WOW64: Not implemented */
244 case ProcessWow64Information:
245 Status = STATUS_NOT_IMPLEMENTED;
246 break;
247
248 /* Virtual Memory Statistics */
249 case ProcessVmCounters:
250
251 /* Enter SEH for write safety */
252 _SEH_TRY
253 {
254 /* Return data from EPROCESS */
255 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
256 VmCounters->VirtualSize = Process->VirtualSize;
257 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
258 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
259 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
260 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
261 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
262 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
263 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
264 VmCounters->PagefileUsage = Process->QuotaUsage[2];
265 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
266
267 /* Set the return length */
268 *ReturnLength = sizeof(VM_COUNTERS);
269 }
270 _SEH_HANDLE
271 {
272 /* Get the exception code */
273 Status = _SEH_GetExceptionCode();
274 }
275 _SEH_END;
276 break;
277
278 /* Hard Error Processing Mode */
279 case ProcessDefaultHardErrorMode:
280
281 /* Enter SEH for writing back data */
282 _SEH_TRY
283 {
284 /* Write the current processing mode */
285 *(PULONG)ProcessInformation = Process->
286 DefaultHardErrorProcessing;
287
288 /* Set the return length */
289 Length = sizeof(ULONG);
290 }
291 _SEH_HANDLE
292 {
293 /* Get the exception code */
294 Status = _SEH_GetExceptionCode();
295 }
296 _SEH_END;
297 break;
298
299 /* Priority Boosting status */
300 case ProcessPriorityBoost:
301
302 /* Enter SEH for writing back data */
303 _SEH_TRY
304 {
305 /* Return boost status */
306 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
307 FALSE : TRUE;
308
309 /* Set the return length */
310 Length = sizeof(ULONG);
311 }
312 _SEH_HANDLE
313 {
314 /* Get the exception code */
315 Status = _SEH_GetExceptionCode();
316 }
317 _SEH_END;
318 break;
319
320 /* DOS Device Map */
321 case ProcessDeviceMap:
322
323 /* Query the device map information */
324 ObQueryDeviceMapInformation(Process, &DeviceMap);
325
326 /* Enter SEH for writing back data */
327 _SEH_TRY
328 {
329 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
330
331 /* Set the return length */
332 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
333 }
334 _SEH_HANDLE
335 {
336 /* Get the exception code */
337 Status = _SEH_GetExceptionCode();
338 }
339 _SEH_END;
340 break;
341
342 /* Priority class */
343 case ProcessPriorityClass:
344
345 /* Enter SEH for writing back data */
346 _SEH_TRY
347 {
348 /* Return current priority class */
349 *(PUSHORT)ProcessInformation = Process->PriorityClass;
350
351 /* Set the return length */
352 Length = sizeof(USHORT);
353 }
354 _SEH_HANDLE
355 {
356 /* Get the exception code */
357 Status = _SEH_GetExceptionCode();
358 }
359 _SEH_END;
360 break;
361
362 case ProcessImageFileName:
363
364 /* Get the image path */
365 Status = SeLocateProcessImageName(Process, &ImageName);
366 if (NT_SUCCESS(Status))
367 {
368 /* Set return length */
369 Length = ImageName->MaximumLength +
370 sizeof(OBJECT_NAME_INFORMATION);
371
372 /* Make sure it's large enough */
373 if (Length <= ProcessInformationLength)
374 {
375 /* Enter SEH to protect write */
376 _SEH_TRY
377 {
378 /* Copy it */
379 RtlCopyMemory(ProcessInformation,
380 ImageName,
381 Length);
382
383 /* Update pointer */
384 ((PUNICODE_STRING)ProcessInformation)->Buffer =
385 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
386 }
387 _SEH_HANDLE
388 {
389 /* Get the exception code */
390 Status = _SEH_GetExceptionCode();
391 }
392 _SEH_END;
393 }
394 }
395 break;
396
397 /* Per-process security cookie */
398 case ProcessCookie:
399
400 /* Get the current process and cookie */
401 Process = PsGetCurrentProcess();
402 Cookie = Process->Cookie;
403 if (!Cookie)
404 {
405 LARGE_INTEGER SystemTime;
406 ULONG NewCookie;
407 PKPRCB Prcb;
408
409 /* Generate a new cookie */
410 KeQuerySystemTime(&SystemTime);
411 Prcb = KeGetCurrentPrcb();
412 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
413 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
414
415 /* Set the new cookie or return the current one */
416 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
417 NewCookie,
418 Cookie);
419 if (!Cookie) Cookie = NewCookie;
420
421 /* Set return length */
422 Length = sizeof(ULONG);
423 }
424
425 /* Enter SEH to protect write */
426 _SEH_TRY
427 {
428 /* Write back the cookie */
429 *(PULONG)ProcessInformation = Cookie;
430 }
431 _SEH_HANDLE
432 {
433 /* Get the exception code */
434 Status = _SEH_GetExceptionCode();
435 }
436 _SEH_END;
437 break;
438
439 /* Not yet implemented, or unknown */
440 case ProcessBasePriority:
441 case ProcessRaisePriority:
442 case ProcessExceptionPort:
443 case ProcessAccessToken:
444 case ProcessLdtSize:
445 case ProcessIoPortHandlers:
446 case ProcessUserModeIOPL:
447 case ProcessEnableAlignmentFaultFixup:
448 case ProcessAffinityMask:
449 case ProcessForegroundInformation:
450 default:
451 Status = STATUS_INVALID_INFO_CLASS;
452 }
453
454 /* Protect write with SEH */
455 _SEH_TRY
456 {
457 /* Check if caller wanted return length */
458 if (ReturnLength) *ReturnLength = Length;
459 }
460 _SEH_HANDLE
461 {
462 /* Get exception code */
463 Status = _SEH_GetExceptionCode();
464 }
465 _SEH_END;
466
467 /* If we referenced the process, dereference it */
468 if(ProcessInformationClass != ProcessCookie) ObDereferenceObject(Process);
469 return Status;
470 }
471
472 /*
473 * @implemented
474 */
475 NTSTATUS
476 NTAPI
477 NtSetInformationProcess(IN HANDLE ProcessHandle,
478 IN PROCESSINFOCLASS ProcessInformationClass,
479 IN PVOID ProcessInformation,
480 IN ULONG ProcessInformationLength)
481 {
482 PEPROCESS Process;
483 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
484 ACCESS_MASK Access;
485 NTSTATUS Status;
486 HANDLE PortHandle = NULL;
487 HANDLE TokenHandle = NULL;
488 PROCESS_SESSION_INFORMATION SessionInfo = {0};
489 PEPORT ExceptionPort;
490 PAGED_CODE();
491
492 /* Verify Information Class validity */
493 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
494 PsProcessInfoClass,
495 RTL_NUMBER_OF(PsProcessInfoClass),
496 ProcessInformation,
497 ProcessInformationLength,
498 PreviousMode);
499 if (!NT_SUCCESS(Status)) return Status;
500
501 /* Check what class this is */
502 Access = PROCESS_SET_INFORMATION;
503 if (ProcessInformationClass == ProcessSessionInformation)
504 {
505 /* Setting the Session ID needs a special mask */
506 Access |= PROCESS_SET_SESSIONID;
507 }
508 else if (ProcessInformationClass == ProcessExceptionPort)
509 {
510 /* Setting the exception port needs a special mask */
511 Access |= PROCESS_SUSPEND_RESUME;
512 }
513
514 /* Reference the process */
515 Status = ObReferenceObjectByHandle(ProcessHandle,
516 Access,
517 PsProcessType,
518 PreviousMode,
519 (PVOID*)&Process,
520 NULL);
521 if (!NT_SUCCESS(Status)) return Status;
522
523 /* Check what kind of information class this is */
524 switch (ProcessInformationClass)
525 {
526 /* Quotas and priorities: not implemented */
527 case ProcessQuotaLimits:
528 case ProcessBasePriority:
529 case ProcessRaisePriority:
530 Status = STATUS_NOT_IMPLEMENTED;
531 break;
532
533 /* Error/Exception Port */
534 case ProcessExceptionPort:
535
536 /* Use SEH for capture */
537 _SEH_TRY
538 {
539 /* Capture the handle */
540 PortHandle = *(PHANDLE)ProcessInformation;
541 }
542 _SEH_HANDLE
543 {
544 /* Get the exception code */
545 Status = _SEH_GetExceptionCode();
546 }
547 _SEH_END;
548 if (!NT_SUCCESS(Status)) break;
549
550 /* Get the LPC Port */
551 Status = ObReferenceObjectByHandle(PortHandle,
552 0,
553 LpcPortObjectType,
554 PreviousMode,
555 (PVOID)&ExceptionPort,
556 NULL);
557 if (!NT_SUCCESS(Status)) break;
558
559 /* Change the pointer */
560 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
561 ExceptionPort,
562 NULL))
563 {
564 /* We already had one, fail */
565 ObDereferenceObject(ExceptionPort);
566 Status = STATUS_PORT_ALREADY_SET;
567 }
568 break;
569
570 /* Security Token */
571 case ProcessAccessToken:
572
573 /* Use SEH for capture */
574 _SEH_TRY
575 {
576 /* Save the token handle */
577 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
578 Token;
579 }
580 _SEH_HANDLE
581 {
582 /* Get the exception code */
583 Status = _SEH_GetExceptionCode();
584 }
585 _SEH_END;
586 if (!NT_SUCCESS(Status)) break;
587
588 /* Assign the actual token */
589 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
590 break;
591
592 /* Hard error processing */
593 case ProcessDefaultHardErrorMode:
594
595 /* Enter SEH for direct buffer read */
596 _SEH_TRY
597 {
598 /* Update the current mode abd return the previous one */
599 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
600 *(PLONG)ProcessInformation);
601 }
602 _SEH_HANDLE
603 {
604 /* Get exception code */
605 Status = _SEH_GetExceptionCode();
606 }
607 _SEH_END;
608 break;
609
610 /* Session ID */
611 case ProcessSessionInformation:
612
613 /* Enter SEH for capture */
614 _SEH_TRY
615 {
616 /* Capture the caller's buffer */
617 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
618 }
619 _SEH_HANDLE
620 {
621 /* Get the exception code */
622 Status = _SEH_GetExceptionCode();
623 }
624 _SEH_END;
625 if (!NT_SUCCESS(Status)) break;
626
627 /* Setting the session id requires the SeTcbPrivilege */
628 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
629 {
630 /* Can't set the session ID, bail out. */
631 Status = STATUS_PRIVILEGE_NOT_HELD;
632 break;
633 }
634
635 /* FIXME - update the session id for the process token */
636 //Status = PsLockProcess(Process, FALSE);
637 if (!NT_SUCCESS(Status)) break;
638
639 /* Write the session ID in the EPROCESS */
640 Process->Session = SessionInfo.SessionId;
641
642 /* Check if the process also has a PEB */
643 if (Process->Peb)
644 {
645 /*
646 * Attach to the process to make sure we're in the right
647 * context to access the PEB structure
648 */
649 KeAttachProcess(&Process->Pcb);
650
651 /* Enter SEH for write to user-mode PEB */
652 _SEH_TRY
653 {
654 /* Write the session ID */
655 Process->Peb->SessionId = SessionInfo.SessionId;
656 }
657 _SEH_HANDLE
658 {
659 /* Get exception code */
660 Status = _SEH_GetExceptionCode();
661 }
662 _SEH_END;
663
664 /* Detach from the process */
665 KeDetachProcess();
666 }
667
668 /* Unlock the process */
669 //PsUnlockProcess(Process);
670 break;
671
672 /* Priority class: HACK! */
673 case ProcessPriorityClass:
674 break;
675
676 /* We currently don't implement any of these */
677 case ProcessLdtInformation:
678 case ProcessLdtSize:
679 case ProcessIoPortHandlers:
680 case ProcessWorkingSetWatch:
681 case ProcessUserModeIOPL:
682 case ProcessEnableAlignmentFaultFixup:
683 case ProcessAffinityMask:
684 Status = STATUS_NOT_IMPLEMENTED;
685 break;
686
687 /* Supposedly these are invalid...!? verify! */
688 case ProcessBasicInformation:
689 case ProcessIoCounters:
690 case ProcessTimes:
691 case ProcessPooledUsageAndLimits:
692 case ProcessWx86Information:
693 case ProcessHandleCount:
694 case ProcessWow64Information:
695 case ProcessDebugPort:
696 default:
697 Status = STATUS_INVALID_INFO_CLASS;
698 }
699
700 /* Dereference and return status */
701 ObDereferenceObject(Process);
702 return Status;
703 }
704
705 /*
706 * @implemented
707 */
708 NTSTATUS
709 NTAPI
710 NtSetInformationThread(IN HANDLE ThreadHandle,
711 IN THREADINFOCLASS ThreadInformationClass,
712 IN PVOID ThreadInformation,
713 IN ULONG ThreadInformationLength)
714 {
715 PETHREAD Thread;
716 ULONG Access;
717 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
718 NTSTATUS Status;
719 HANDLE TokenHandle = NULL;
720 KPRIORITY Priority = 0;
721 KAFFINITY Affinity = 0;
722 PVOID Address = NULL;
723 PEPROCESS Process;
724 PAGED_CODE();
725
726 /* Verify Information Class validity */
727 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
728 PsThreadInfoClass,
729 RTL_NUMBER_OF(PsThreadInfoClass),
730 ThreadInformation,
731 ThreadInformationLength,
732 PreviousMode);
733 if (!NT_SUCCESS(Status)) return Status;
734
735 /* Check what class this is */
736 Access = THREAD_SET_INFORMATION;
737 if (ThreadInformationClass == ThreadImpersonationToken)
738 {
739 /* Setting the impersonation token needs a special mask */
740 Access = THREAD_SET_THREAD_TOKEN;
741 }
742
743 /* Reference the process */
744 Status = ObReferenceObjectByHandle(ThreadHandle,
745 Access,
746 PsThreadType,
747 PreviousMode,
748 (PVOID*)&Thread,
749 NULL);
750 if (!NT_SUCCESS(Status)) return Status;
751
752 /* Check what kind of information class this is */
753 switch (ThreadInformationClass)
754 {
755 /* Thread priority */
756 case ThreadPriority:
757
758 /* Use SEH for capture */
759 _SEH_TRY
760 {
761 /* Get the priority */
762 Priority = *(PLONG)ThreadInformation;
763 }
764 _SEH_HANDLE
765 {
766 /* Get the exception code */
767 Status = _SEH_GetExceptionCode();
768 }
769 _SEH_END;
770 if (!NT_SUCCESS(Status)) break;
771
772 /* Set the priority */
773 KeSetPriorityThread(&Thread->Tcb, Priority);
774 break;
775
776 case ThreadBasePriority:
777
778 /* Use SEH for capture */
779 _SEH_TRY
780 {
781 /* Get the priority */
782 Priority = *(PLONG)ThreadInformation;
783 }
784 _SEH_HANDLE
785 {
786 /* Get the exception code */
787 Status = _SEH_GetExceptionCode();
788 }
789 _SEH_END;
790 if (!NT_SUCCESS(Status)) break;
791
792 /* Set the base priority */
793 KeSetBasePriorityThread(&Thread->Tcb, Priority);
794 break;
795
796 case ThreadAffinityMask:
797
798 /* Use SEH for capture */
799 _SEH_TRY
800 {
801 /* Get the priority */
802 Affinity = *(PULONG_PTR)ThreadInformation;
803 }
804 _SEH_HANDLE
805 {
806 /* Get the exception code */
807 Status = _SEH_GetExceptionCode();
808 }
809 _SEH_END;
810 if (!NT_SUCCESS(Status)) break;
811
812 /* Get the process */
813 Process = Thread->ThreadsProcess;
814
815 /* Set the affinity */
816 KeSetAffinityThread(&Thread->Tcb, Affinity & Process->Pcb.Affinity);
817 break;
818
819 case ThreadImpersonationToken:
820
821 /* Use SEH for capture */
822 _SEH_TRY
823 {
824 /* Save the token handle */
825 TokenHandle = *(PHANDLE)ThreadInformation;
826 }
827 _SEH_HANDLE
828 {
829 /* Get the exception code */
830 Status = _SEH_GetExceptionCode();
831 }
832 _SEH_END;
833 if (!NT_SUCCESS(Status)) break;
834
835 /* Assign the actual token */
836 Status = PsAssignImpersonationToken(Thread, TokenHandle);
837 break;
838
839 case ThreadQuerySetWin32StartAddress:
840
841 /* Use SEH for capture */
842 _SEH_TRY
843 {
844 /* Get the priority */
845 Address = *(PVOID*)ThreadInformation;
846 }
847 _SEH_HANDLE
848 {
849 /* Get the exception code */
850 Status = _SEH_GetExceptionCode();
851 }
852 _SEH_END;
853 if (!NT_SUCCESS(Status)) break;
854
855 /* Set the address */
856 Thread->Win32StartAddress = Address;
857 break;
858
859 default:
860 /* We don't implement it yet */
861 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
862 Status = STATUS_NOT_IMPLEMENTED;
863 }
864
865 /* Dereference and return status */
866 ObDereferenceObject(Thread);
867 return Status;
868 }
869
870 /*
871 * @implemented
872 */
873 NTSTATUS
874 NTAPI
875 NtQueryInformationThread(IN HANDLE ThreadHandle,
876 IN THREADINFOCLASS ThreadInformationClass,
877 OUT PVOID ThreadInformation,
878 IN ULONG ThreadInformationLength,
879 OUT PULONG ReturnLength OPTIONAL)
880 {
881 PETHREAD Thread;
882 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
883 NTSTATUS Status = STATUS_SUCCESS;
884 ULONG Access;
885 ULONG Length = 0;
886 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
887 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
888 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
889 KIRQL OldIrql;
890 PAGED_CODE();
891
892 /* Verify Information Class validity */
893 Status = DefaultQueryInfoBufferCheck(ThreadInformationClass,
894 PsThreadInfoClass,
895 RTL_NUMBER_OF(PsThreadInfoClass),
896 ThreadInformation,
897 ThreadInformationLength,
898 ReturnLength,
899 PreviousMode);
900 if (!NT_SUCCESS(Status)) return Status;
901
902 /* Check what class this is */
903 Access = THREAD_QUERY_INFORMATION;
904
905 /* Reference the process */
906 Status = ObReferenceObjectByHandle(ThreadHandle,
907 Access,
908 PsThreadType,
909 PreviousMode,
910 (PVOID*)&Thread,
911 NULL);
912 if (!NT_SUCCESS(Status)) return Status;
913
914 /* Check what kind of information class this is */
915 switch (ThreadInformationClass)
916 {
917 /* Basic thread information */
918 case ThreadBasicInformation:
919
920 /* Protect writes with SEH */
921 _SEH_TRY
922 {
923 /* Write all the information from the ETHREAD/KTHREAD */
924 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
925 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
926 ThreadBasicInfo->ClientId = Thread->Cid;
927 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
928 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
929 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
930
931 /* Set return length */
932 Length = sizeof(THREAD_BASIC_INFORMATION);
933 }
934 _SEH_HANDLE
935 {
936 /* Get exception code */
937 Status = _SEH_GetExceptionCode();
938 }
939 _SEH_END;
940 break;
941
942 /* Thread time information */
943 case ThreadTimes:
944
945 /* Protect writes with SEH */
946 _SEH_TRY
947 {
948 /* Copy time information from ETHREAD/KTHREAD */
949 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
950 100000LL;
951 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
952 100000LL;
953 ThreadTime->CreateTime = Thread->CreateTime;
954 ThreadTime->ExitTime = Thread->ExitTime;
955
956 /* Set the return length */
957 Length = sizeof(KERNEL_USER_TIMES);
958 }
959 _SEH_HANDLE
960 {
961 /* Get exception code */
962 Status = _SEH_GetExceptionCode();
963 }
964 _SEH_END;
965 break;
966
967 case ThreadQuerySetWin32StartAddress:
968
969 /* Protect write with SEH */
970 _SEH_TRY
971 {
972 /* Return the Win32 Start Address */
973 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
974
975 /* Set the return length*/
976 Length = sizeof(PVOID);
977 }
978 _SEH_HANDLE
979 {
980 /* Get exception code */
981 Status = _SEH_GetExceptionCode();
982 }
983 _SEH_END;
984 break;
985
986 case ThreadPerformanceCount:
987
988 /* Protect write with SEH */
989 _SEH_TRY
990 {
991 /* FIXME */
992 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
993
994 /* Set the return length*/
995 Length = sizeof(LARGE_INTEGER);
996 }
997 _SEH_HANDLE
998 {
999 /* Get exception code */
1000 Status = _SEH_GetExceptionCode();
1001 }
1002 _SEH_END;
1003 break;
1004
1005 case ThreadAmILastThread:
1006
1007 /* Protect write with SEH */
1008 _SEH_TRY
1009 {
1010 /* Return whether or not we are the last thread */
1011 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
1012 ThreadListHead.Flink->Flink ==
1013 &Thread->ThreadsProcess->
1014 ThreadListHead) ?
1015 TRUE : FALSE);
1016
1017 /* Set the return length*/
1018 Length = sizeof(ULONG);
1019 }
1020 _SEH_HANDLE
1021 {
1022 /* Get exception code */
1023 Status = _SEH_GetExceptionCode();
1024 }
1025 _SEH_END;
1026 break;
1027
1028 case ThreadIsIoPending:
1029
1030 /* Raise the IRQL to protect the IRP list */
1031 KeRaiseIrql(APC_LEVEL, &OldIrql);
1032
1033 /* Protect write with SEH */
1034 _SEH_TRY
1035 {
1036 /* Check if the IRP list is empty or not */
1037 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
1038
1039 /* Set the return length*/
1040 Length = sizeof(ULONG);
1041 }
1042 _SEH_HANDLE
1043 {
1044 /* Get exception code */
1045 Status = _SEH_GetExceptionCode();
1046 }
1047 _SEH_END;
1048
1049 /* Lower IRQL back */
1050 KeLowerIrql(OldIrql);
1051 break;
1052
1053 /* Anything else */
1054 default:
1055
1056 /* Not yet implemented */
1057 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
1058 Status = STATUS_NOT_IMPLEMENTED;
1059 }
1060
1061 /* Protect write with SEH */
1062 _SEH_TRY
1063 {
1064 /* Check if caller wanted return length */
1065 if (ReturnLength) *ReturnLength = Length;
1066 }
1067 _SEH_HANDLE
1068 {
1069 /* Get exception code */
1070 Status = _SEH_GetExceptionCode();
1071 }
1072 _SEH_END;
1073
1074 /* Dereference the thread, and return */
1075 ObDereferenceObject(Thread);
1076 return Status;
1077 }
1078
1079 /* EOF */