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