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