Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / 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 * Eric Kohl
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* Debugging Level */
18 ULONG PspTraceLevel = 0;
19
20 /* PRIVATE FUNCTIONS *********************************************************/
21
22 NTSTATUS
23 NTAPI
24 PsReferenceProcessFilePointer(IN PEPROCESS Process,
25 OUT PFILE_OBJECT *FileObject)
26 {
27 PSECTION Section;
28 PAGED_CODE();
29
30 /* Lock the process */
31 ExAcquireRundownProtection(&Process->RundownProtect);
32
33 /* Get the section */
34 Section = Process->SectionObject;
35 if (Section)
36 {
37 /* Get the file object and reference it */
38 *FileObject = MmGetFileObjectForSection((PVOID)Section);
39 ObReferenceObject(*FileObject);
40 }
41
42 /* Release the protection */
43 ExReleaseRundownProtection(&Process->RundownProtect);
44
45 /* Return status */
46 return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
47 }
48
49 /* PUBLIC FUNCTIONS **********************************************************/
50
51 /*
52 * @implemented
53 */
54 NTSTATUS
55 NTAPI
56 NtQueryInformationProcess(IN HANDLE ProcessHandle,
57 IN PROCESSINFOCLASS ProcessInformationClass,
58 OUT PVOID ProcessInformation,
59 IN ULONG ProcessInformationLength,
60 OUT PULONG ReturnLength OPTIONAL)
61 {
62 PEPROCESS Process;
63 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
64 NTSTATUS Status;
65 ULONG Length = 0;
66 HANDLE DebugPort = 0;
67 PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
68 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
69 PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
70 ULONG UserTime, KernelTime;
71 PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
72 ULONG HandleCount;
73 PPROCESS_SESSION_INFORMATION SessionInfo =
74 (PPROCESS_SESSION_INFORMATION)ProcessInformation;
75 PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
76 PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
77 PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
78 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
79 PUNICODE_STRING ImageName;
80 ULONG Cookie, ExecuteOptions = 0;
81 ULONG_PTR Wow64 = 0;
82 PAGED_CODE();
83
84 /* Check for user-mode caller */
85 if (PreviousMode != KernelMode)
86 {
87 /* Prepare to probe parameters */
88 _SEH2_TRY
89 {
90 /* Probe the buffer */
91 ProbeForRead(ProcessInformation,
92 ProcessInformationLength,
93 sizeof(ULONG));
94
95 /* Probe the return length if required */
96 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
97 }
98 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
99 {
100 /* Return the exception code */
101 _SEH2_YIELD(return _SEH2_GetExceptionCode());
102 }
103 _SEH2_END;
104 }
105
106 if (((ProcessInformationClass == ProcessCookie) ||
107 (ProcessInformationClass == ProcessImageInformation)) &&
108 (ProcessHandle != NtCurrentProcess()))
109 {
110 /*
111 * Retrieving the process cookie is only allowed for the calling process
112 * itself! XP only allows NtCurrentProcess() as process handles even if
113 * a real handle actually represents the current process.
114 */
115 return STATUS_INVALID_PARAMETER;
116 }
117
118 /* Check the information class */
119 switch (ProcessInformationClass)
120 {
121 /* Basic process information */
122 case ProcessBasicInformation:
123
124 if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION))
125 {
126 Status = STATUS_INFO_LENGTH_MISMATCH;
127 break;
128 }
129
130 /* Set return length */
131 Length = sizeof(PROCESS_BASIC_INFORMATION);
132
133 /* Reference the process */
134 Status = ObReferenceObjectByHandle(ProcessHandle,
135 PROCESS_QUERY_INFORMATION,
136 PsProcessType,
137 PreviousMode,
138 (PVOID*)&Process,
139 NULL);
140 if (!NT_SUCCESS(Status)) break;
141
142 /* Protect writes with SEH */
143 _SEH2_TRY
144 {
145 /* Write all the information from the EPROCESS/KPROCESS */
146 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
147 ProcessBasicInfo->PebBaseAddress = Process->Peb;
148 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
149 ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
150 UniqueProcessId;
151 ProcessBasicInfo->InheritedFromUniqueProcessId =
152 (ULONG_PTR)Process->InheritedFromUniqueProcessId;
153 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
154
155 }
156 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
157 {
158 /* Get exception code */
159 Status = _SEH2_GetExceptionCode();
160 }
161 _SEH2_END;
162
163 /* Dereference the process */
164 ObDereferenceObject(Process);
165 break;
166
167 /* Process quota limits */
168 case ProcessQuotaLimits:
169
170 if (ProcessInformationLength != sizeof(QUOTA_LIMITS))
171 {
172 Status = STATUS_INFO_LENGTH_MISMATCH;
173 break;
174 }
175
176 Length = sizeof(QUOTA_LIMITS);
177
178 /* Reference the process */
179 Status = ObReferenceObjectByHandle(ProcessHandle,
180 PROCESS_QUERY_INFORMATION,
181 PsProcessType,
182 PreviousMode,
183 (PVOID*)&Process,
184 NULL);
185 if (!NT_SUCCESS(Status)) break;
186
187 /* Indicate success */
188 Status = STATUS_SUCCESS;
189
190 _SEH2_TRY
191 {
192 /* Set max/min working set sizes */
193 QuotaLimits->MaximumWorkingSetSize =
194 Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
195 QuotaLimits->MinimumWorkingSetSize =
196 Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
197
198 /* Set default time limits */
199 QuotaLimits->TimeLimit.LowPart = MAXULONG;
200 QuotaLimits->TimeLimit.HighPart = MAXULONG;
201
202 /* Is quota block a default one? */
203 if (Process->QuotaBlock == &PspDefaultQuotaBlock)
204 {
205 /* Set default pools and pagefile limits */
206 QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
207 QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
208 QuotaLimits->PagefileLimit = (SIZE_T)-1;
209 }
210 else
211 {
212 /* Get limits from non-default quota block */
213 QuotaLimits->PagedPoolLimit =
214 Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
215 QuotaLimits->NonPagedPoolLimit =
216 Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
217 QuotaLimits->PagefileLimit =
218 Process->QuotaBlock->QuotaEntry[2].Limit;
219 }
220 }
221 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
222 {
223 /* Get exception code */
224 Status = _SEH2_GetExceptionCode();
225 }
226 _SEH2_END;
227
228 /* Dereference the process */
229 ObDereferenceObject(Process);
230 break;
231
232 case ProcessIoCounters:
233
234 if (ProcessInformationLength != sizeof(IO_COUNTERS))
235 {
236 Status = STATUS_INFO_LENGTH_MISMATCH;
237 break;
238 }
239
240 Length = sizeof(IO_COUNTERS);
241
242 /* Reference the process */
243 Status = ObReferenceObjectByHandle(ProcessHandle,
244 PROCESS_QUERY_INFORMATION,
245 PsProcessType,
246 PreviousMode,
247 (PVOID*)&Process,
248 NULL);
249 if (!NT_SUCCESS(Status)) break;
250
251 _SEH2_TRY
252 {
253 /* FIXME: Call KeQueryValuesProcess */
254 IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
255 IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
256 IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
257 IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
258 IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
259 IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
260 }
261 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
262 {
263 /* Ignore exception */
264 }
265 _SEH2_END;
266
267 /* Set status to success in any case */
268 Status = STATUS_SUCCESS;
269
270 /* Dereference the process */
271 ObDereferenceObject(Process);
272 break;
273
274 /* Timing */
275 case ProcessTimes:
276
277 /* Set the return length */
278 if (ProcessInformationLength != sizeof(KERNEL_USER_TIMES))
279 {
280 Status = STATUS_INFO_LENGTH_MISMATCH;
281 break;
282 }
283
284 Length = sizeof(KERNEL_USER_TIMES);
285
286 /* Reference the process */
287 Status = ObReferenceObjectByHandle(ProcessHandle,
288 PROCESS_QUERY_INFORMATION,
289 PsProcessType,
290 PreviousMode,
291 (PVOID*)&Process,
292 NULL);
293 if (!NT_SUCCESS(Status)) break;
294
295 /* Protect writes with SEH */
296 _SEH2_TRY
297 {
298 /* Copy time information from EPROCESS/KPROCESS */
299 KernelTime = KeQueryRuntimeProcess(&Process->Pcb, &UserTime);
300 ProcessTime->CreateTime = Process->CreateTime;
301 ProcessTime->UserTime.QuadPart = (LONGLONG)UserTime * KeMaximumIncrement;
302 ProcessTime->KernelTime.QuadPart = (LONGLONG)KernelTime * KeMaximumIncrement;
303 ProcessTime->ExitTime = Process->ExitTime;
304 }
305 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
306 {
307 /* Get exception code */
308 Status = _SEH2_GetExceptionCode();
309 }
310 _SEH2_END;
311
312 /* Dereference the process */
313 ObDereferenceObject(Process);
314 break;
315
316 /* Process Debug Port */
317 case ProcessDebugPort:
318
319 if (ProcessInformationLength != sizeof(HANDLE))
320 {
321 Status = STATUS_INFO_LENGTH_MISMATCH;
322 break;
323 }
324
325 /* Set return length */
326 Length = sizeof(HANDLE);
327
328 /* Reference the process */
329 Status = ObReferenceObjectByHandle(ProcessHandle,
330 PROCESS_QUERY_INFORMATION,
331 PsProcessType,
332 PreviousMode,
333 (PVOID*)&Process,
334 NULL);
335 if (!NT_SUCCESS(Status)) break;
336
337 /* Protect write with SEH */
338 _SEH2_TRY
339 {
340 /* Return whether or not we have a debug port */
341 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
342 (HANDLE)-1 : NULL);
343 }
344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
345 {
346 /* Get exception code */
347 Status = _SEH2_GetExceptionCode();
348 }
349 _SEH2_END;
350
351 /* Dereference the process */
352 ObDereferenceObject(Process);
353 break;
354
355 case ProcessHandleCount:
356
357 if (ProcessInformationLength != sizeof(ULONG))
358 {
359 Status = STATUS_INFO_LENGTH_MISMATCH;
360 break;
361 }
362
363 /* Set the return length*/
364 Length = sizeof(ULONG);
365
366 /* Reference the process */
367 Status = ObReferenceObjectByHandle(ProcessHandle,
368 PROCESS_QUERY_INFORMATION,
369 PsProcessType,
370 PreviousMode,
371 (PVOID*)&Process,
372 NULL);
373 if (!NT_SUCCESS(Status)) break;
374
375 /* Count the number of handles this process has */
376 HandleCount = ObGetProcessHandleCount(Process);
377
378 /* Protect write in SEH */
379 _SEH2_TRY
380 {
381 /* Return the count of handles */
382 *(PULONG)ProcessInformation = HandleCount;
383 }
384 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
385 {
386 /* Get the exception code */
387 Status = _SEH2_GetExceptionCode();
388 }
389 _SEH2_END;
390
391 /* Dereference the process */
392 ObDereferenceObject(Process);
393 break;
394
395 /* Session ID for the process */
396 case ProcessSessionInformation:
397
398 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
399 {
400 Status = STATUS_INFO_LENGTH_MISMATCH;
401 break;
402 }
403
404 /* Set the return length*/
405 Length = sizeof(PROCESS_SESSION_INFORMATION);
406
407 /* Reference the process */
408 Status = ObReferenceObjectByHandle(ProcessHandle,
409 PROCESS_QUERY_INFORMATION,
410 PsProcessType,
411 PreviousMode,
412 (PVOID*)&Process,
413 NULL);
414 if (!NT_SUCCESS(Status)) break;
415
416 /* Enter SEH for write safety */
417 _SEH2_TRY
418 {
419 /* Write back the Session ID */
420 SessionInfo->SessionId = PsGetProcessSessionId(Process);
421 }
422 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
423 {
424 /* Get the exception code */
425 Status = _SEH2_GetExceptionCode();
426 }
427 _SEH2_END;
428
429 /* Dereference the process */
430 ObDereferenceObject(Process);
431 break;
432
433 /* Virtual Memory Statistics */
434 case ProcessVmCounters:
435
436 /* Validate the input length */
437 if ((ProcessInformationLength != sizeof(VM_COUNTERS)) &&
438 (ProcessInformationLength != sizeof(VM_COUNTERS_EX)))
439 {
440 Status = STATUS_INFO_LENGTH_MISMATCH;
441 break;
442 }
443
444 /* Reference the process */
445 Status = ObReferenceObjectByHandle(ProcessHandle,
446 PROCESS_QUERY_INFORMATION,
447 PsProcessType,
448 PreviousMode,
449 (PVOID*)&Process,
450 NULL);
451 if (!NT_SUCCESS(Status)) break;
452
453 /* Enter SEH for write safety */
454 _SEH2_TRY
455 {
456 /* Return data from EPROCESS */
457 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
458 VmCounters->VirtualSize = Process->VirtualSize;
459 VmCounters->PageFaultCount = Process->Vm.PageFaultCount;
460 VmCounters->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
461 VmCounters->WorkingSetSize = Process->Vm.WorkingSetSize;
462 VmCounters->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0];
463 VmCounters->QuotaPagedPoolUsage = Process->QuotaUsage[0];
464 VmCounters->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1];
465 VmCounters->QuotaNonPagedPoolUsage = Process->QuotaUsage[1];
466 VmCounters->PagefileUsage = Process->QuotaUsage[2] << PAGE_SHIFT;
467 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2] << PAGE_SHIFT;
468 //VmCounters->PrivateUsage = Process->CommitCharge << PAGE_SHIFT;
469 //
470
471 /* Set the return length */
472 Length = ProcessInformationLength;
473 }
474 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
475 {
476 /* Get the exception code */
477 Status = _SEH2_GetExceptionCode();
478 }
479 _SEH2_END;
480
481 /* Dereference the process */
482 ObDereferenceObject(Process);
483 break;
484
485 /* Hard Error Processing Mode */
486 case ProcessDefaultHardErrorMode:
487
488 if (ProcessInformationLength != sizeof(ULONG))
489 {
490 Status = STATUS_INFO_LENGTH_MISMATCH;
491 break;
492 }
493
494 /* Set the return length*/
495 Length = sizeof(ULONG);
496
497 /* Reference the process */
498 Status = ObReferenceObjectByHandle(ProcessHandle,
499 PROCESS_QUERY_INFORMATION,
500 PsProcessType,
501 PreviousMode,
502 (PVOID*)&Process,
503 NULL);
504 if (!NT_SUCCESS(Status)) break;
505
506 /* Enter SEH for writing back data */
507 _SEH2_TRY
508 {
509 /* Write the current processing mode */
510 *(PULONG)ProcessInformation = Process->
511 DefaultHardErrorProcessing;
512 }
513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
514 {
515 /* Get the exception code */
516 Status = _SEH2_GetExceptionCode();
517 }
518 _SEH2_END;
519
520 /* Dereference the process */
521 ObDereferenceObject(Process);
522 break;
523
524 /* Priority Boosting status */
525 case ProcessPriorityBoost:
526
527 if (ProcessInformationLength != sizeof(ULONG))
528 {
529 Status = STATUS_INFO_LENGTH_MISMATCH;
530 break;
531 }
532
533 /* Set the return length */
534 Length = sizeof(ULONG);
535
536 /* Reference the process */
537 Status = ObReferenceObjectByHandle(ProcessHandle,
538 PROCESS_QUERY_INFORMATION,
539 PsProcessType,
540 PreviousMode,
541 (PVOID*)&Process,
542 NULL);
543 if (!NT_SUCCESS(Status)) break;
544
545 /* Enter SEH for writing back data */
546 _SEH2_TRY
547 {
548 /* Return boost status */
549 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
550 TRUE : FALSE;
551 }
552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
553 {
554 /* Get the exception code */
555 Status = _SEH2_GetExceptionCode();
556 }
557 _SEH2_END;
558
559 /* Dereference the process */
560 ObDereferenceObject(Process);
561 break;
562
563 /* DOS Device Map */
564 case ProcessDeviceMap:
565
566 if (ProcessInformationLength != sizeof(PROCESS_DEVICEMAP_INFORMATION))
567 {
568 if (ProcessInformationLength == sizeof(PROCESS_DEVICEMAP_INFORMATION_EX))
569 {
570 DPRINT1("PROCESS_DEVICEMAP_INFORMATION_EX not supported!\n");
571 Status = STATUS_NOT_IMPLEMENTED;
572 }
573 else
574 {
575 Status = STATUS_INFO_LENGTH_MISMATCH;
576 }
577 break;
578 }
579
580 /* Set the return length */
581 Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
582
583 /* Reference the process */
584 Status = ObReferenceObjectByHandle(ProcessHandle,
585 PROCESS_QUERY_INFORMATION,
586 PsProcessType,
587 PreviousMode,
588 (PVOID*)&Process,
589 NULL);
590 if (!NT_SUCCESS(Status)) break;
591
592 /* Query the device map information */
593 ObQueryDeviceMapInformation(Process, &DeviceMap);
594
595 /* Enter SEH for writing back data */
596 _SEH2_TRY
597 {
598 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
599 }
600 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
601 {
602 /* Get the exception code */
603 Status = _SEH2_GetExceptionCode();
604 }
605 _SEH2_END;
606
607 /* Dereference the process */
608 ObDereferenceObject(Process);
609 break;
610
611 /* Priority class */
612 case ProcessPriorityClass:
613
614 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
615 {
616 Status = STATUS_INFO_LENGTH_MISMATCH;
617 break;
618 }
619
620 /* Set the return length*/
621 Length = sizeof(PROCESS_PRIORITY_CLASS);
622
623 /* Reference the process */
624 Status = ObReferenceObjectByHandle(ProcessHandle,
625 PROCESS_QUERY_INFORMATION,
626 PsProcessType,
627 PreviousMode,
628 (PVOID*)&Process,
629 NULL);
630 if (!NT_SUCCESS(Status)) break;
631
632 /* Enter SEH for writing back data */
633 _SEH2_TRY
634 {
635 /* Return current priority class */
636 PsPriorityClass->PriorityClass = Process->PriorityClass;
637 PsPriorityClass->Foreground = FALSE;
638 }
639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
640 {
641 /* Get the exception code */
642 Status = _SEH2_GetExceptionCode();
643 }
644 _SEH2_END;
645
646 /* Dereference the process */
647 ObDereferenceObject(Process);
648 break;
649
650 case ProcessImageFileName:
651
652 /* Reference the process */
653 Status = ObReferenceObjectByHandle(ProcessHandle,
654 PROCESS_QUERY_INFORMATION,
655 PsProcessType,
656 PreviousMode,
657 (PVOID*)&Process,
658 NULL);
659 if (!NT_SUCCESS(Status)) break;
660
661 /* Get the image path */
662 Status = SeLocateProcessImageName(Process, &ImageName);
663 if (NT_SUCCESS(Status))
664 {
665 /* Set return length */
666 Length = ImageName->MaximumLength +
667 sizeof(OBJECT_NAME_INFORMATION);
668
669 /* Make sure it's large enough */
670 if (Length <= ProcessInformationLength)
671 {
672 /* Enter SEH to protect write */
673 _SEH2_TRY
674 {
675 /* Copy it */
676 RtlCopyMemory(ProcessInformation,
677 ImageName,
678 Length);
679
680 /* Update pointer */
681 ((PUNICODE_STRING)ProcessInformation)->Buffer =
682 (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
683 }
684 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
685 {
686 /* Get the exception code */
687 Status = _SEH2_GetExceptionCode();
688 }
689 _SEH2_END;
690 }
691 else
692 {
693 /* Buffer too small */
694 Status = STATUS_INFO_LENGTH_MISMATCH;
695 }
696
697 /* Free the image path */
698 ExFreePoolWithTag(ImageName, TAG_SEPA);
699 }
700 /* Dereference the process */
701 ObDereferenceObject(Process);
702 break;
703
704 case ProcessDebugFlags:
705
706 if (ProcessInformationLength != sizeof(ULONG))
707 {
708 Status = STATUS_INFO_LENGTH_MISMATCH;
709 break;
710 }
711
712 /* Set the return length*/
713 Length = sizeof(ULONG);
714
715 /* Reference the process */
716 Status = ObReferenceObjectByHandle(ProcessHandle,
717 PROCESS_QUERY_INFORMATION,
718 PsProcessType,
719 PreviousMode,
720 (PVOID*)&Process,
721 NULL);
722 if (!NT_SUCCESS(Status)) break;
723
724 /* Enter SEH for writing back data */
725 _SEH2_TRY
726 {
727 /* Return the debug flag state */
728 *(PULONG)ProcessInformation = Process->NoDebugInherit ? 0 : 1;
729 }
730 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
731 {
732 /* Get the exception code */
733 Status = _SEH2_GetExceptionCode();
734 }
735 _SEH2_END;
736
737 /* Dereference the process */
738 ObDereferenceObject(Process);
739 break;
740
741 case ProcessBreakOnTermination:
742
743 if (ProcessInformationLength != sizeof(ULONG))
744 {
745 Status = STATUS_INFO_LENGTH_MISMATCH;
746 break;
747 }
748
749 /* Set the return length */
750 Length = sizeof(ULONG);
751
752 /* Reference the process */
753 Status = ObReferenceObjectByHandle(ProcessHandle,
754 PROCESS_QUERY_INFORMATION,
755 PsProcessType,
756 PreviousMode,
757 (PVOID*)&Process,
758 NULL);
759 if (!NT_SUCCESS(Status)) break;
760
761 /* Enter SEH for writing back data */
762 _SEH2_TRY
763 {
764 /* Return the BreakOnTermination state */
765 *(PULONG)ProcessInformation = Process->BreakOnTermination;
766 }
767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
768 {
769 /* Get the exception code */
770 Status = _SEH2_GetExceptionCode();
771 }
772 _SEH2_END;
773
774 /* Dereference the process */
775 ObDereferenceObject(Process);
776 break;
777
778 /* Per-process security cookie */
779 case ProcessCookie:
780
781 /* Get the current process and cookie */
782 Process = PsGetCurrentProcess();
783 Cookie = Process->Cookie;
784 if (!Cookie)
785 {
786 LARGE_INTEGER SystemTime;
787 ULONG NewCookie;
788 PKPRCB Prcb;
789
790 /* Generate a new cookie */
791 KeQuerySystemTime(&SystemTime);
792 Prcb = KeGetCurrentPrcb();
793 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
794 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
795
796 /* Set the new cookie or return the current one */
797 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
798 NewCookie,
799 Cookie);
800 if (!Cookie) Cookie = NewCookie;
801
802 /* Set return length */
803 Length = sizeof(ULONG);
804 }
805
806 /* Indicate success */
807 Status = STATUS_SUCCESS;
808
809 /* Enter SEH to protect write */
810 _SEH2_TRY
811 {
812 /* Write back the cookie */
813 *(PULONG)ProcessInformation = Cookie;
814 }
815 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
816 {
817 /* Get the exception code */
818 Status = _SEH2_GetExceptionCode();
819 }
820 _SEH2_END;
821 break;
822
823 case ProcessImageInformation:
824
825 if (ProcessInformationLength != sizeof(SECTION_IMAGE_INFORMATION))
826 {
827 /* Break out */
828 Status = STATUS_INFO_LENGTH_MISMATCH;
829 break;
830 }
831
832 /* Set the length required and validate it */
833 Length = sizeof(SECTION_IMAGE_INFORMATION);
834
835 /* Enter SEH to protect write */
836 _SEH2_TRY
837 {
838 MmGetImageInformation((PSECTION_IMAGE_INFORMATION)ProcessInformation);
839 }
840 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
841 {
842 /* Get the exception code */
843 Status = _SEH2_GetExceptionCode();
844 }
845 _SEH2_END;
846
847 /* Indicate success */
848 Status = STATUS_SUCCESS;
849 break;
850
851 case ProcessDebugObjectHandle:
852
853 if (ProcessInformationLength != sizeof(HANDLE))
854 {
855 Status = STATUS_INFO_LENGTH_MISMATCH;
856 break;
857 }
858
859 /* Set the return length */
860 Length = sizeof(HANDLE);
861
862 /* Reference the process */
863 Status = ObReferenceObjectByHandle(ProcessHandle,
864 PROCESS_QUERY_INFORMATION,
865 PsProcessType,
866 PreviousMode,
867 (PVOID*)&Process,
868 NULL);
869 if (!NT_SUCCESS(Status)) break;
870
871 /* Get the debug port */
872 Status = DbgkOpenProcessDebugPort(Process, PreviousMode, &DebugPort);
873
874 /* Let go of the process */
875 ObDereferenceObject(Process);
876
877 /* Protect write in SEH */
878 _SEH2_TRY
879 {
880 /* Return debug port's handle */
881 *(PHANDLE)ProcessInformation = DebugPort;
882 }
883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
884 {
885 /* Get the exception code */
886 Status = _SEH2_GetExceptionCode();
887 }
888 _SEH2_END;
889 break;
890
891 case ProcessHandleTracing:
892 DPRINT1("Handle tracing Not implemented: %lx\n", ProcessInformationClass);
893 Status = STATUS_NOT_IMPLEMENTED;
894 break;
895
896 case ProcessLUIDDeviceMapsEnabled:
897
898 if (ProcessInformationLength != sizeof(ULONG))
899 {
900 Status = STATUS_INFO_LENGTH_MISMATCH;
901 break;
902 }
903
904 /* Set the return length */
905 Length = sizeof(ULONG);
906
907 /* Indicate success */
908 Status = STATUS_SUCCESS;
909
910 /* Protect write in SEH */
911 _SEH2_TRY
912 {
913 /* Return FALSE -- we don't support this */
914 *(PULONG)ProcessInformation = FALSE;
915 }
916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
917 {
918 /* Get the exception code */
919 Status = _SEH2_GetExceptionCode();
920 }
921 _SEH2_END;
922 break;
923
924 case ProcessWx86Information:
925
926 if (ProcessInformationLength != sizeof(ULONG))
927 {
928 Status = STATUS_INFO_LENGTH_MISMATCH;
929 break;
930 }
931
932 /* Set the return length */
933 Length = sizeof(ULONG);
934
935 /* Reference the process */
936 Status = ObReferenceObjectByHandle(ProcessHandle,
937 PROCESS_QUERY_INFORMATION,
938 PsProcessType,
939 PreviousMode,
940 (PVOID*)&Process,
941 NULL);
942 if (!NT_SUCCESS(Status)) break;
943
944 /* Protect write in SEH */
945 _SEH2_TRY
946 {
947 /* Return if the flag is set */
948 *(PULONG)ProcessInformation = (ULONG)Process->VdmAllowed;
949 }
950 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
951 {
952 /* Get the exception code */
953 Status = _SEH2_GetExceptionCode();
954 }
955 _SEH2_END;
956
957 /* Dereference the process */
958 ObDereferenceObject(Process);
959 break;
960
961 case ProcessWow64Information:
962
963 if (ProcessInformationLength != sizeof(ULONG_PTR))
964 {
965 Status = STATUS_INFO_LENGTH_MISMATCH;
966 break;
967 }
968
969 /* Set return length */
970 Length = sizeof(ULONG_PTR);
971
972 /* Reference the process */
973 Status = ObReferenceObjectByHandle(ProcessHandle,
974 PROCESS_QUERY_INFORMATION,
975 PsProcessType,
976 PreviousMode,
977 (PVOID*)&Process,
978 NULL);
979 if (!NT_SUCCESS(Status)) break;
980
981 /* Make sure the process isn't dying */
982 if (ExAcquireRundownProtection(&Process->RundownProtect))
983 {
984 /* Get the WOW64 process structure */
985 #ifdef _WIN64
986 Wow64 = (ULONG_PTR)Process->Wow64Process;
987 #else
988 Wow64 = 0;
989 #endif
990 /* Release the lock */
991 ExReleaseRundownProtection(&Process->RundownProtect);
992 }
993
994 /* Protect write with SEH */
995 _SEH2_TRY
996 {
997 /* Return whether or not we have a debug port */
998 *(PULONG_PTR)ProcessInformation = Wow64;
999 }
1000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1001 {
1002 /* Get exception code */
1003 Status = _SEH2_GetExceptionCode();
1004 }
1005 _SEH2_END;
1006
1007 /* Dereference the process */
1008 ObDereferenceObject(Process);
1009 break;
1010
1011 case ProcessExecuteFlags:
1012
1013 if (ProcessInformationLength != sizeof(ULONG))
1014 {
1015 Status = STATUS_INFO_LENGTH_MISMATCH;
1016 break;
1017 }
1018
1019 /* Set return length */
1020 Length = sizeof(ULONG);
1021
1022 if (ProcessHandle != NtCurrentProcess())
1023 {
1024 return STATUS_INVALID_PARAMETER;
1025 }
1026
1027 /* Get the options */
1028 Status = MmGetExecuteOptions(&ExecuteOptions);
1029 if (NT_SUCCESS(Status))
1030 {
1031 /* Protect write with SEH */
1032 _SEH2_TRY
1033 {
1034 /* Return them */
1035 *(PULONG)ProcessInformation = ExecuteOptions;
1036 }
1037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1038 {
1039 /* Get exception code */
1040 Status = _SEH2_GetExceptionCode();
1041 }
1042 _SEH2_END;
1043 }
1044 break;
1045
1046 case ProcessLdtInformation:
1047 DPRINT1("VDM/16-bit not implemented: %lx\n", ProcessInformationClass);
1048 Status = STATUS_NOT_IMPLEMENTED;
1049 break;
1050
1051 case ProcessWorkingSetWatch:
1052 DPRINT1("WS Watch Not implemented: %lx\n", ProcessInformationClass);
1053 Status = STATUS_NOT_IMPLEMENTED;
1054 break;
1055
1056 case ProcessPooledUsageAndLimits:
1057 DPRINT1("Pool limits Not implemented: %lx\n", ProcessInformationClass);
1058 Status = STATUS_NOT_IMPLEMENTED;
1059 break;
1060
1061 /* Not supported by Server 2003 */
1062 default:
1063 DPRINT1("Unsupported info class: %lx\n", ProcessInformationClass);
1064 Status = STATUS_INVALID_INFO_CLASS;
1065 }
1066
1067 /* Protect write with SEH */
1068 _SEH2_TRY
1069 {
1070 /* Check if caller wanted return length */
1071 if ((ReturnLength) && (Length)) *ReturnLength = Length;
1072 }
1073 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1074 {
1075 /* Get exception code */
1076 Status = _SEH2_GetExceptionCode();
1077 }
1078 _SEH2_END;
1079
1080 return Status;
1081 }
1082
1083 /*
1084 * @implemented
1085 */
1086 NTSTATUS
1087 NTAPI
1088 NtSetInformationProcess(IN HANDLE ProcessHandle,
1089 IN PROCESSINFOCLASS ProcessInformationClass,
1090 IN PVOID ProcessInformation,
1091 IN ULONG ProcessInformationLength)
1092 {
1093 PEPROCESS Process;
1094 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1095 ACCESS_MASK Access;
1096 NTSTATUS Status;
1097 HANDLE PortHandle = NULL;
1098 HANDLE TokenHandle = NULL;
1099 PROCESS_SESSION_INFORMATION SessionInfo = {0};
1100 PROCESS_PRIORITY_CLASS PriorityClass = {0};
1101 PROCESS_FOREGROUND_BACKGROUND Foreground = {0};
1102 PVOID ExceptionPort;
1103 ULONG Break;
1104 KAFFINITY ValidAffinity, Affinity = 0;
1105 KPRIORITY BasePriority = 0;
1106 UCHAR MemoryPriority = 0;
1107 BOOLEAN DisableBoost = 0;
1108 ULONG DefaultHardErrorMode = 0;
1109 ULONG DebugFlags = 0, EnableFixup = 0, Boost = 0;
1110 ULONG NoExecute = 0, VdmPower = 0;
1111 BOOLEAN HasPrivilege;
1112 PLIST_ENTRY Next;
1113 PETHREAD Thread;
1114 PAGED_CODE();
1115
1116 /* Verify Information Class validity */
1117 #if 0
1118 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
1119 PsProcessInfoClass,
1120 RTL_NUMBER_OF(PsProcessInfoClass),
1121 ProcessInformation,
1122 ProcessInformationLength,
1123 PreviousMode);
1124 if (!NT_SUCCESS(Status)) return Status;
1125 #endif
1126
1127 /* Check what class this is */
1128 Access = PROCESS_SET_INFORMATION;
1129 if (ProcessInformationClass == ProcessSessionInformation)
1130 {
1131 /* Setting the Session ID needs a special mask */
1132 Access |= PROCESS_SET_SESSIONID;
1133 }
1134 else if (ProcessInformationClass == ProcessExceptionPort)
1135 {
1136 /* Setting the exception port needs a special mask */
1137 Access |= PROCESS_SUSPEND_RESUME;
1138 }
1139
1140 /* Reference the process */
1141 Status = ObReferenceObjectByHandle(ProcessHandle,
1142 Access,
1143 PsProcessType,
1144 PreviousMode,
1145 (PVOID*)&Process,
1146 NULL);
1147 if (!NT_SUCCESS(Status)) return Status;
1148
1149 /* Check what kind of information class this is */
1150 switch (ProcessInformationClass)
1151 {
1152 case ProcessWx86Information:
1153
1154 /* Check buffer length */
1155 if (ProcessInformationLength != sizeof(HANDLE))
1156 {
1157 Status = STATUS_INFO_LENGTH_MISMATCH;
1158 break;
1159 }
1160
1161 /* Use SEH for capture */
1162 _SEH2_TRY
1163 {
1164 /* Capture the boolean */
1165 VdmPower = *(PULONG)ProcessInformation;
1166 }
1167 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1168 {
1169 /* Get the exception code */
1170 Status = _SEH2_GetExceptionCode();
1171 _SEH2_YIELD(break);
1172 }
1173 _SEH2_END;
1174
1175 /* Getting VDM powers requires the SeTcbPrivilege */
1176 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1177 {
1178 /* We don't hold the privilege, bail out */
1179 Status = STATUS_PRIVILEGE_NOT_HELD;
1180 DPRINT1("Need TCB privilege\n");
1181 break;
1182 }
1183
1184 /* Set or clear the flag */
1185 if (VdmPower)
1186 {
1187 PspSetProcessFlag(Process, PSF_VDM_ALLOWED_BIT);
1188 }
1189 else
1190 {
1191 PspClearProcessFlag(Process, PSF_VDM_ALLOWED_BIT);
1192 }
1193 break;
1194
1195 /* Error/Exception Port */
1196 case ProcessExceptionPort:
1197
1198 /* Check buffer length */
1199 if (ProcessInformationLength != sizeof(HANDLE))
1200 {
1201 Status = STATUS_INFO_LENGTH_MISMATCH;
1202 break;
1203 }
1204
1205 /* Use SEH for capture */
1206 _SEH2_TRY
1207 {
1208 /* Capture the handle */
1209 PortHandle = *(PHANDLE)ProcessInformation;
1210 }
1211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1212 {
1213 /* Get the exception code */
1214 Status = _SEH2_GetExceptionCode();
1215 _SEH2_YIELD(break);
1216 }
1217 _SEH2_END;
1218
1219 /* Setting the error port requires the SeTcbPrivilege */
1220 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1221 {
1222 /* We don't hold the privilege, bail out */
1223 Status = STATUS_PRIVILEGE_NOT_HELD;
1224 break;
1225 }
1226
1227 /* Get the LPC Port */
1228 Status = ObReferenceObjectByHandle(PortHandle,
1229 0,
1230 LpcPortObjectType,
1231 PreviousMode,
1232 (PVOID)&ExceptionPort,
1233 NULL);
1234 if (!NT_SUCCESS(Status)) break;
1235
1236 /* Change the pointer */
1237 if (InterlockedCompareExchangePointer(&Process->ExceptionPort,
1238 ExceptionPort,
1239 NULL))
1240 {
1241 /* We already had one, fail */
1242 ObDereferenceObject(ExceptionPort);
1243 Status = STATUS_PORT_ALREADY_SET;
1244 }
1245 break;
1246
1247 /* Security Token */
1248 case ProcessAccessToken:
1249
1250 /* Check buffer length */
1251 if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
1252 {
1253 Status = STATUS_INFO_LENGTH_MISMATCH;
1254 break;
1255 }
1256
1257 /* Use SEH for capture */
1258 _SEH2_TRY
1259 {
1260 /* Save the token handle */
1261 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
1262 Token;
1263 }
1264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1265 {
1266 /* Get the exception code */
1267 Status = _SEH2_GetExceptionCode();
1268 _SEH2_YIELD(break);
1269 }
1270 _SEH2_END;
1271
1272 /* Assign the actual token */
1273 Status = PspSetPrimaryToken(Process, TokenHandle, NULL);
1274 break;
1275
1276 /* Hard error processing */
1277 case ProcessDefaultHardErrorMode:
1278
1279 /* Check buffer length */
1280 if (ProcessInformationLength != sizeof(ULONG))
1281 {
1282 Status = STATUS_INFO_LENGTH_MISMATCH;
1283 break;
1284 }
1285
1286 /* Enter SEH for direct buffer read */
1287 _SEH2_TRY
1288 {
1289 DefaultHardErrorMode = *(PULONG)ProcessInformation;
1290 }
1291 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1292 {
1293 /* Get exception code */
1294 Status = _SEH2_GetExceptionCode();
1295 _SEH2_YIELD(break);
1296 }
1297 _SEH2_END;
1298
1299 /* Set the mode */
1300 Process->DefaultHardErrorProcessing = DefaultHardErrorMode;
1301
1302 /* Call Ke for the update */
1303 if (DefaultHardErrorMode & SEM_NOALIGNMENTFAULTEXCEPT)
1304 {
1305 KeSetAutoAlignmentProcess(&Process->Pcb, TRUE);
1306 }
1307 else
1308 {
1309 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE);
1310 }
1311 Status = STATUS_SUCCESS;
1312 break;
1313
1314 /* Session ID */
1315 case ProcessSessionInformation:
1316
1317 /* Check buffer length */
1318 if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
1319 {
1320 Status = STATUS_INFO_LENGTH_MISMATCH;
1321 break;
1322 }
1323
1324 /* Enter SEH for capture */
1325 _SEH2_TRY
1326 {
1327 /* Capture the caller's buffer */
1328 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
1329 }
1330 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1331 {
1332 /* Get the exception code */
1333 Status = _SEH2_GetExceptionCode();
1334 _SEH2_YIELD(break);
1335 }
1336 _SEH2_END;
1337
1338 /* Setting the session id requires the SeTcbPrivilege */
1339 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1340 {
1341 /* We don't hold the privilege, bail out */
1342 Status = STATUS_PRIVILEGE_NOT_HELD;
1343 break;
1344 }
1345
1346 #if 0 // OLD AND DEPRECATED CODE!!!!
1347
1348 /* FIXME - update the session id for the process token */
1349 //Status = PsLockProcess(Process, FALSE);
1350 if (!NT_SUCCESS(Status)) break;
1351
1352 /* Write the session ID in the EPROCESS */
1353 Process->Session = UlongToPtr(SessionInfo.SessionId); // HACK!!!
1354
1355 /* Check if the process also has a PEB */
1356 if (Process->Peb)
1357 {
1358 /*
1359 * Attach to the process to make sure we're in the right
1360 * context to access the PEB structure
1361 */
1362 KeAttachProcess(&Process->Pcb);
1363
1364 /* Enter SEH for write to user-mode PEB */
1365 _SEH2_TRY
1366 {
1367 /* Write the session ID */
1368 Process->Peb->SessionId = SessionInfo.SessionId;
1369 }
1370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1371 {
1372 /* Get exception code */
1373 Status = _SEH2_GetExceptionCode();
1374 }
1375 _SEH2_END;
1376
1377 /* Detach from the process */
1378 KeDetachProcess();
1379 }
1380
1381 /* Unlock the process */
1382 //PsUnlockProcess(Process);
1383
1384 #endif
1385
1386 /*
1387 * Since we cannot change the session ID of the given
1388 * process anymore because it is set once and for all
1389 * at process creation time and because it is stored
1390 * inside the Process->Session structure managed by MM,
1391 * we fake changing it: we just return success if the
1392 * user-defined value is the same as the session ID of
1393 * the process, and otherwise we fail.
1394 */
1395 if (SessionInfo.SessionId == PsGetProcessSessionId(Process))
1396 {
1397 Status = STATUS_SUCCESS;
1398 }
1399 else
1400 {
1401 Status = STATUS_ACCESS_DENIED;
1402 }
1403
1404 break;
1405
1406 case ProcessPriorityClass:
1407
1408 /* Check buffer length */
1409 if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
1410 {
1411 Status = STATUS_INFO_LENGTH_MISMATCH;
1412 break;
1413 }
1414
1415 /* Enter SEH for capture */
1416 _SEH2_TRY
1417 {
1418 /* Capture the caller's buffer */
1419 PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
1420 }
1421 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1422 {
1423 /* Return the exception code */
1424 Status = _SEH2_GetExceptionCode();
1425 _SEH2_YIELD(break);
1426 }
1427 _SEH2_END;
1428
1429 /* Check for invalid PriorityClass value */
1430 if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
1431 {
1432 Status = STATUS_INVALID_PARAMETER;
1433 break;
1434 }
1435
1436 if ((PriorityClass.PriorityClass != Process->PriorityClass) &&
1437 (PriorityClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME))
1438 {
1439 /* Check the privilege */
1440 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1441 ProcessHandle,
1442 PROCESS_SET_INFORMATION,
1443 PreviousMode);
1444 if (!HasPrivilege)
1445 {
1446 ObDereferenceObject(Process);
1447 DPRINT1("Privilege to change priority to realtime lacking\n");
1448 return STATUS_PRIVILEGE_NOT_HELD;
1449 }
1450 }
1451
1452 /* Check if we have a job */
1453 if (Process->Job)
1454 {
1455 DPRINT1("Jobs not yet supported\n");
1456 }
1457
1458 /* Set process priority class */
1459 Process->PriorityClass = PriorityClass.PriorityClass;
1460
1461 /* Set process priority mode (foreground or background) */
1462 PsSetProcessPriorityByClass(Process,
1463 PriorityClass.Foreground ?
1464 PsProcessPriorityForeground :
1465 PsProcessPriorityBackground);
1466 Status = STATUS_SUCCESS;
1467 break;
1468
1469 case ProcessForegroundInformation:
1470
1471 /* Check buffer length */
1472 if (ProcessInformationLength != sizeof(PROCESS_FOREGROUND_BACKGROUND))
1473 {
1474 Status = STATUS_INFO_LENGTH_MISMATCH;
1475 break;
1476 }
1477
1478 /* Enter SEH for capture */
1479 _SEH2_TRY
1480 {
1481 /* Capture the caller's buffer */
1482 Foreground = *(PPROCESS_FOREGROUND_BACKGROUND)ProcessInformation;
1483 }
1484 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1485 {
1486 /* Return the exception code */
1487 Status = _SEH2_GetExceptionCode();
1488 _SEH2_YIELD(break);
1489 }
1490 _SEH2_END;
1491
1492 /* Set process priority mode (foreground or background) */
1493 PsSetProcessPriorityByClass(Process,
1494 Foreground.Foreground ?
1495 PsProcessPriorityForeground :
1496 PsProcessPriorityBackground);
1497 Status = STATUS_SUCCESS;
1498 break;
1499
1500 case ProcessBasePriority:
1501
1502 /* Validate input length */
1503 if (ProcessInformationLength != sizeof(KPRIORITY))
1504 {
1505 Status = STATUS_INFO_LENGTH_MISMATCH;
1506 break;
1507 }
1508
1509 /* Enter SEH for direct buffer read */
1510 _SEH2_TRY
1511 {
1512 BasePriority = *(KPRIORITY*)ProcessInformation;
1513 }
1514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1515 {
1516 /* Get exception code */
1517 Break = 0;
1518 Status = _SEH2_GetExceptionCode();
1519 _SEH2_YIELD(break);
1520 }
1521 _SEH2_END;
1522
1523 /* Extract the memory priority out of there */
1524 if (BasePriority & 0x80000000)
1525 {
1526 MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
1527 BasePriority &= ~0x80000000;
1528 }
1529 else
1530 {
1531 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
1532 }
1533
1534 /* Validate the number */
1535 if ((BasePriority > HIGH_PRIORITY) || (BasePriority <= LOW_PRIORITY))
1536 {
1537 ObDereferenceObject(Process);
1538 return STATUS_INVALID_PARAMETER;
1539 }
1540
1541 /* Check if the new base is higher */
1542 if (BasePriority > Process->Pcb.BasePriority)
1543 {
1544 HasPrivilege = SeCheckPrivilegedObject(SeIncreaseBasePriorityPrivilege,
1545 ProcessHandle,
1546 PROCESS_SET_INFORMATION,
1547 PreviousMode);
1548 if (!HasPrivilege)
1549 {
1550 ObDereferenceObject(Process);
1551 DPRINT1("Privilege to change priority from %lx to %lx lacking\n", BasePriority, Process->Pcb.BasePriority);
1552 return STATUS_PRIVILEGE_NOT_HELD;
1553 }
1554 }
1555
1556 /* Call Ke */
1557 KeSetPriorityAndQuantumProcess(&Process->Pcb, BasePriority, 0);
1558
1559 /* Now set the memory priority */
1560 MmSetMemoryPriorityProcess(Process, MemoryPriority);
1561 Status = STATUS_SUCCESS;
1562 break;
1563
1564 case ProcessRaisePriority:
1565
1566 /* Validate input length */
1567 if (ProcessInformationLength != sizeof(ULONG))
1568 {
1569 Status = STATUS_INFO_LENGTH_MISMATCH;
1570 break;
1571 }
1572
1573 /* Enter SEH for direct buffer read */
1574 _SEH2_TRY
1575 {
1576 Boost = *(PULONG)ProcessInformation;
1577 }
1578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1579 {
1580 /* Get exception code */
1581 Break = 0;
1582 Status = _SEH2_GetExceptionCode();
1583 _SEH2_YIELD(break);
1584 }
1585 _SEH2_END;
1586
1587 /* Make sure the process isn't dying */
1588 if (ExAcquireRundownProtection(&Process->RundownProtect))
1589 {
1590 /* Lock it */
1591 KeEnterCriticalRegion();
1592 ExAcquirePushLockShared(&Process->ProcessLock);
1593
1594 /* Loop the threads */
1595 for (Next = Process->ThreadListHead.Flink;
1596 Next != &Process->ThreadListHead;
1597 Next = Next->Flink)
1598 {
1599 /* Call Ke for the thread */
1600 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1601 KeBoostPriorityThread(&Thread->Tcb, Boost);
1602 }
1603
1604 /* Release the lock and rundown */
1605 ExReleasePushLockShared(&Process->ProcessLock);
1606 KeLeaveCriticalRegion();
1607 ExReleaseRundownProtection(&Process->RundownProtect);
1608
1609 /* Set success code */
1610 Status = STATUS_SUCCESS;
1611 }
1612 else
1613 {
1614 /* Avoid race conditions */
1615 Status = STATUS_PROCESS_IS_TERMINATING;
1616 }
1617 break;
1618
1619 case ProcessBreakOnTermination:
1620
1621 /* Check buffer length */
1622 if (ProcessInformationLength != sizeof(ULONG))
1623 {
1624 Status = STATUS_INFO_LENGTH_MISMATCH;
1625 break;
1626 }
1627
1628 /* Enter SEH for direct buffer read */
1629 _SEH2_TRY
1630 {
1631 Break = *(PULONG)ProcessInformation;
1632 }
1633 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1634 {
1635 /* Get exception code */
1636 Break = 0;
1637 Status = _SEH2_GetExceptionCode();
1638 _SEH2_YIELD(break);
1639 }
1640 _SEH2_END;
1641
1642 /* Setting 'break on termination' requires the SeDebugPrivilege */
1643 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1644 {
1645 /* We don't hold the privilege, bail out */
1646 Status = STATUS_PRIVILEGE_NOT_HELD;
1647 break;
1648 }
1649
1650 /* Set or clear the flag */
1651 if (Break)
1652 {
1653 PspSetProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1654 }
1655 else
1656 {
1657 PspClearProcessFlag(Process, PSF_BREAK_ON_TERMINATION_BIT);
1658 }
1659
1660 break;
1661
1662 case ProcessAffinityMask:
1663
1664 /* Check buffer length */
1665 if (ProcessInformationLength != sizeof(KAFFINITY))
1666 {
1667 Status = STATUS_INFO_LENGTH_MISMATCH;
1668 break;
1669 }
1670
1671 /* Enter SEH for direct buffer read */
1672 _SEH2_TRY
1673 {
1674 Affinity = *(PKAFFINITY)ProcessInformation;
1675 }
1676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1677 {
1678 /* Get exception code */
1679 Break = 0;
1680 Status = _SEH2_GetExceptionCode();
1681 _SEH2_YIELD(break);
1682 }
1683 _SEH2_END;
1684
1685 /* Make sure it's valid for the CPUs present */
1686 ValidAffinity = Affinity & KeActiveProcessors;
1687 if (!Affinity || (ValidAffinity != Affinity))
1688 {
1689 Status = STATUS_INVALID_PARAMETER;
1690 break;
1691 }
1692
1693 /* Check if it's within job affinity limits */
1694 if (Process->Job)
1695 {
1696 /* Not yet implemented */
1697 UNIMPLEMENTED;
1698 Status = STATUS_NOT_IMPLEMENTED;
1699 break;
1700 }
1701
1702 /* Make sure the process isn't dying */
1703 if (ExAcquireRundownProtection(&Process->RundownProtect))
1704 {
1705 /* Lock it */
1706 KeEnterCriticalRegion();
1707 ExAcquirePushLockShared(&Process->ProcessLock);
1708
1709 /* Call Ke to do the work */
1710 KeSetAffinityProcess(&Process->Pcb, ValidAffinity);
1711
1712 /* Release the lock and rundown */
1713 ExReleasePushLockShared(&Process->ProcessLock);
1714 KeLeaveCriticalRegion();
1715 ExReleaseRundownProtection(&Process->RundownProtect);
1716
1717 /* Set success code */
1718 Status = STATUS_SUCCESS;
1719 }
1720 else
1721 {
1722 /* Avoid race conditions */
1723 Status = STATUS_PROCESS_IS_TERMINATING;
1724 }
1725 break;
1726
1727 /* Priority Boosting status */
1728 case ProcessPriorityBoost:
1729
1730 /* Validate input length */
1731 if (ProcessInformationLength != sizeof(ULONG))
1732 {
1733 Status = STATUS_INFO_LENGTH_MISMATCH;
1734 break;
1735 }
1736
1737 /* Enter SEH for direct buffer read */
1738 _SEH2_TRY
1739 {
1740 DisableBoost = *(PBOOLEAN)ProcessInformation;
1741 }
1742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1743 {
1744 /* Get exception code */
1745 Break = 0;
1746 Status = _SEH2_GetExceptionCode();
1747 _SEH2_YIELD(break);
1748 }
1749 _SEH2_END;
1750
1751 /* Make sure the process isn't dying */
1752 if (ExAcquireRundownProtection(&Process->RundownProtect))
1753 {
1754 /* Lock it */
1755 KeEnterCriticalRegion();
1756 ExAcquirePushLockShared(&Process->ProcessLock);
1757
1758 /* Call Ke to do the work */
1759 KeSetDisableBoostProcess(&Process->Pcb, DisableBoost);
1760
1761 /* Loop the threads too */
1762 for (Next = Process->ThreadListHead.Flink;
1763 Next != &Process->ThreadListHead;
1764 Next = Next->Flink)
1765 {
1766 /* Call Ke for the thread */
1767 Thread = CONTAINING_RECORD(Next, ETHREAD, ThreadListEntry);
1768 KeSetDisableBoostThread(&Thread->Tcb, DisableBoost);
1769 }
1770
1771 /* Release the lock and rundown */
1772 ExReleasePushLockShared(&Process->ProcessLock);
1773 KeLeaveCriticalRegion();
1774 ExReleaseRundownProtection(&Process->RundownProtect);
1775
1776 /* Set success code */
1777 Status = STATUS_SUCCESS;
1778 }
1779 else
1780 {
1781 /* Avoid race conditions */
1782 Status = STATUS_PROCESS_IS_TERMINATING;
1783 }
1784 break;
1785
1786 case ProcessDebugFlags:
1787
1788 /* Check buffer length */
1789 if (ProcessInformationLength != sizeof(ULONG))
1790 {
1791 Status = STATUS_INFO_LENGTH_MISMATCH;
1792 break;
1793 }
1794
1795 /* Enter SEH for direct buffer read */
1796 _SEH2_TRY
1797 {
1798 DebugFlags = *(PULONG)ProcessInformation;
1799 }
1800 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1801 {
1802 /* Get exception code */
1803 Status = _SEH2_GetExceptionCode();
1804 _SEH2_YIELD(break);
1805 }
1806 _SEH2_END;
1807
1808 /* Set the mode */
1809 if (DebugFlags & ~1)
1810 {
1811 Status = STATUS_INVALID_PARAMETER;
1812 }
1813 else
1814 {
1815 if (DebugFlags & 1)
1816 {
1817 PspClearProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1818 }
1819 else
1820 {
1821 PspSetProcessFlag(Process, PSF_NO_DEBUG_INHERIT_BIT);
1822 }
1823 }
1824
1825 /* Done */
1826 Status = STATUS_SUCCESS;
1827 break;
1828
1829 case ProcessEnableAlignmentFaultFixup:
1830
1831 /* Check buffer length */
1832 if (ProcessInformationLength != sizeof(ULONG))
1833 {
1834 Status = STATUS_INFO_LENGTH_MISMATCH;
1835 break;
1836 }
1837
1838 /* Enter SEH for direct buffer read */
1839 _SEH2_TRY
1840 {
1841 EnableFixup = *(PULONG)ProcessInformation;
1842 }
1843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1844 {
1845 /* Get exception code */
1846 Status = _SEH2_GetExceptionCode();
1847 _SEH2_YIELD(break);
1848 }
1849 _SEH2_END;
1850
1851 /* Set the mode */
1852 if (EnableFixup)
1853 {
1854 Process->DefaultHardErrorProcessing |= SEM_NOALIGNMENTFAULTEXCEPT;
1855 }
1856 else
1857 {
1858 Process->DefaultHardErrorProcessing &= ~SEM_NOALIGNMENTFAULTEXCEPT;
1859 }
1860
1861 /* Call Ke for the update */
1862 KeSetAutoAlignmentProcess(&Process->Pcb, FALSE);
1863 Status = STATUS_SUCCESS;
1864 break;
1865
1866 case ProcessUserModeIOPL:
1867
1868 /* Only TCB can do this */
1869 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1870 {
1871 /* We don't hold the privilege, bail out */
1872 DPRINT1("Need TCB to set IOPL\n");
1873 Status = STATUS_PRIVILEGE_NOT_HELD;
1874 break;
1875 }
1876
1877 /* Only supported on x86 */
1878 #if defined (_X86_)
1879 Ke386SetIOPL();
1880 #else
1881 Status = STATUS_NOT_IMPLEMENTED;
1882 #endif
1883 /* Done */
1884 break;
1885
1886 case ProcessExecuteFlags:
1887
1888 /* Check buffer length */
1889 if (ProcessInformationLength != sizeof(ULONG))
1890 {
1891 Status = STATUS_INFO_LENGTH_MISMATCH;
1892 break;
1893 }
1894
1895 if (ProcessHandle != NtCurrentProcess())
1896 {
1897 Status = STATUS_INVALID_PARAMETER;
1898 break;
1899 }
1900
1901 /* Enter SEH for direct buffer read */
1902 _SEH2_TRY
1903 {
1904 NoExecute = *(PULONG)ProcessInformation;
1905 }
1906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1907 {
1908 /* Get exception code */
1909 Status = _SEH2_GetExceptionCode();
1910 _SEH2_YIELD(break);
1911 }
1912 _SEH2_END;
1913
1914 /* Call Mm for the update */
1915 Status = MmSetExecuteOptions(NoExecute);
1916 break;
1917
1918 /* We currently don't implement any of these */
1919 case ProcessLdtInformation:
1920 case ProcessLdtSize:
1921 case ProcessIoPortHandlers:
1922 DPRINT1("VDM/16-bit Request not implemented: %lx\n", ProcessInformationClass);
1923 Status = STATUS_NOT_IMPLEMENTED;
1924 break;
1925
1926 case ProcessQuotaLimits:
1927
1928 Status = PspSetQuotaLimits(Process,
1929 1,
1930 ProcessInformation,
1931 ProcessInformationLength,
1932 PreviousMode);
1933 break;
1934
1935 case ProcessWorkingSetWatch:
1936 DPRINT1("WS watch not implemented\n");
1937 Status = STATUS_NOT_IMPLEMENTED;
1938 break;
1939
1940 case ProcessDeviceMap:
1941 DPRINT1("Device map not implemented\n");
1942 Status = STATUS_NOT_IMPLEMENTED;
1943 break;
1944
1945 case ProcessHandleTracing:
1946 DPRINT1("Handle tracing not implemented\n");
1947 Status = STATUS_NOT_IMPLEMENTED;
1948 break;
1949
1950 /* Anything else is invalid */
1951 default:
1952 DPRINT1("Invalid Server 2003 Info Class: %lx\n", ProcessInformationClass);
1953 Status = STATUS_INVALID_INFO_CLASS;
1954 }
1955
1956 /* Dereference and return status */
1957 ObDereferenceObject(Process);
1958 return Status;
1959 }
1960
1961 /*
1962 * @implemented
1963 */
1964 NTSTATUS
1965 NTAPI
1966 NtSetInformationThread(IN HANDLE ThreadHandle,
1967 IN THREADINFOCLASS ThreadInformationClass,
1968 IN PVOID ThreadInformation,
1969 IN ULONG ThreadInformationLength)
1970 {
1971 PETHREAD Thread;
1972 ULONG Access;
1973 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1974 NTSTATUS Status;
1975 HANDLE TokenHandle = NULL;
1976 KPRIORITY Priority = 0;
1977 KAFFINITY Affinity = 0, CombinedAffinity;
1978 PVOID Address = NULL;
1979 PEPROCESS Process;
1980 ULONG_PTR DisableBoost = 0;
1981 ULONG_PTR IdealProcessor = 0;
1982 ULONG_PTR Break = 0;
1983 PTEB Teb;
1984 ULONG_PTR TlsIndex = 0;
1985 PVOID *ExpansionSlots;
1986 PETHREAD ProcThread;
1987 PAGED_CODE();
1988
1989 /* Verify Information Class validity */
1990 #if 0
1991 Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
1992 PsThreadInfoClass,
1993 RTL_NUMBER_OF(PsThreadInfoClass),
1994 ThreadInformation,
1995 ThreadInformationLength,
1996 PreviousMode);
1997 if (!NT_SUCCESS(Status)) return Status;
1998 #endif
1999
2000 /* Check what class this is */
2001 Access = THREAD_SET_INFORMATION;
2002 if (ThreadInformationClass == ThreadImpersonationToken)
2003 {
2004 /* Setting the impersonation token needs a special mask */
2005 Access = THREAD_SET_THREAD_TOKEN;
2006 }
2007
2008 /* Reference the thread */
2009 Status = ObReferenceObjectByHandle(ThreadHandle,
2010 Access,
2011 PsThreadType,
2012 PreviousMode,
2013 (PVOID*)&Thread,
2014 NULL);
2015 if (!NT_SUCCESS(Status)) return Status;
2016
2017 /* Check what kind of information class this is */
2018 switch (ThreadInformationClass)
2019 {
2020 /* Thread priority */
2021 case ThreadPriority:
2022
2023 /* Check buffer length */
2024 if (ThreadInformationLength != sizeof(KPRIORITY))
2025 {
2026 Status = STATUS_INFO_LENGTH_MISMATCH;
2027 break;
2028 }
2029
2030 /* Use SEH for capture */
2031 _SEH2_TRY
2032 {
2033 /* Get the priority */
2034 Priority = *(PLONG)ThreadInformation;
2035 }
2036 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2037 {
2038 /* Get the exception code */
2039 Status = _SEH2_GetExceptionCode();
2040 _SEH2_YIELD(break);
2041 }
2042 _SEH2_END;
2043
2044 /* Validate it */
2045 if ((Priority > HIGH_PRIORITY) ||
2046 (Priority <= LOW_PRIORITY))
2047 {
2048 /* Fail */
2049 Status = STATUS_INVALID_PARAMETER;
2050 break;
2051 }
2052
2053 /* Set the priority */
2054 KeSetPriorityThread(&Thread->Tcb, Priority);
2055 break;
2056
2057 case ThreadBasePriority:
2058
2059 /* Check buffer length */
2060 if (ThreadInformationLength != sizeof(LONG))
2061 {
2062 Status = STATUS_INFO_LENGTH_MISMATCH;
2063 break;
2064 }
2065
2066 /* Use SEH for capture */
2067 _SEH2_TRY
2068 {
2069 /* Get the priority */
2070 Priority = *(PLONG)ThreadInformation;
2071 }
2072 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2073 {
2074 /* Get the exception code */
2075 Status = _SEH2_GetExceptionCode();
2076 _SEH2_YIELD(break);
2077 }
2078 _SEH2_END;
2079
2080 /* Validate it */
2081 if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
2082 (Priority < THREAD_BASE_PRIORITY_MIN))
2083 {
2084 /* These ones are OK */
2085 if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
2086 (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
2087 {
2088 /* Check if the process is real time */
2089 if (PsGetCurrentProcess()->PriorityClass !=
2090 PROCESS_PRIORITY_CLASS_REALTIME)
2091 {
2092 /* It isn't, fail */
2093 Status = STATUS_INVALID_PARAMETER;
2094 break;
2095 }
2096 }
2097 }
2098
2099 /* Set the base priority */
2100 KeSetBasePriorityThread(&Thread->Tcb, Priority);
2101 break;
2102
2103 case ThreadAffinityMask:
2104
2105 /* Check buffer length */
2106 if (ThreadInformationLength != sizeof(ULONG_PTR))
2107 {
2108 Status = STATUS_INFO_LENGTH_MISMATCH;
2109 break;
2110 }
2111
2112 /* Use SEH for capture */
2113 _SEH2_TRY
2114 {
2115 /* Get the priority */
2116 Affinity = *(PULONG_PTR)ThreadInformation;
2117 }
2118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2119 {
2120 /* Get the exception code */
2121 Status = _SEH2_GetExceptionCode();
2122 _SEH2_YIELD(break);
2123 }
2124 _SEH2_END;
2125
2126 /* Validate it */
2127 if (!Affinity)
2128 {
2129 /* Fail */
2130 Status = STATUS_INVALID_PARAMETER;
2131 break;
2132 }
2133
2134 /* Get the process */
2135 Process = Thread->ThreadsProcess;
2136
2137 /* Try to acquire rundown */
2138 if (ExAcquireRundownProtection(&Process->RundownProtect))
2139 {
2140 /* Lock it */
2141 KeEnterCriticalRegion();
2142 ExAcquirePushLockShared(&Process->ProcessLock);
2143
2144 /* Combine masks */
2145 CombinedAffinity = Affinity & Process->Pcb.Affinity;
2146 if (CombinedAffinity != Affinity)
2147 {
2148 /* Fail */
2149 Status = STATUS_INVALID_PARAMETER;
2150 }
2151 else
2152 {
2153 /* Set the affinity */
2154 KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
2155 }
2156
2157 /* Release the lock and rundown */
2158 ExReleasePushLockShared(&Process->ProcessLock);
2159 KeLeaveCriticalRegion();
2160 ExReleaseRundownProtection(&Process->RundownProtect);
2161 }
2162 else
2163 {
2164 /* Too late */
2165 Status = STATUS_PROCESS_IS_TERMINATING;
2166 }
2167
2168 /* Return status */
2169 break;
2170
2171 case ThreadImpersonationToken:
2172
2173 /* Check buffer length */
2174 if (ThreadInformationLength != sizeof(HANDLE))
2175 {
2176 Status = STATUS_INFO_LENGTH_MISMATCH;
2177 break;
2178 }
2179
2180 /* Use SEH for capture */
2181 _SEH2_TRY
2182 {
2183 /* Save the token handle */
2184 TokenHandle = *(PHANDLE)ThreadInformation;
2185 }
2186 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2187 {
2188 /* Get the exception code */
2189 Status = _SEH2_GetExceptionCode();
2190 _SEH2_YIELD(break);
2191 }
2192 _SEH2_END;
2193
2194 /* Assign the actual token */
2195 Status = PsAssignImpersonationToken(Thread, TokenHandle);
2196 break;
2197
2198 case ThreadQuerySetWin32StartAddress:
2199
2200 /* Check buffer length */
2201 if (ThreadInformationLength != sizeof(ULONG_PTR))
2202 {
2203 Status = STATUS_INFO_LENGTH_MISMATCH;
2204 break;
2205 }
2206
2207 /* Use SEH for capture */
2208 _SEH2_TRY
2209 {
2210 /* Get the priority */
2211 Address = *(PVOID*)ThreadInformation;
2212 }
2213 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2214 {
2215 /* Get the exception code */
2216 Status = _SEH2_GetExceptionCode();
2217 _SEH2_YIELD(break);
2218 }
2219 _SEH2_END;
2220
2221 /* Set the address */
2222 Thread->Win32StartAddress = Address;
2223 break;
2224
2225 case ThreadIdealProcessor:
2226
2227 /* Check buffer length */
2228 if (ThreadInformationLength != sizeof(ULONG_PTR))
2229 {
2230 Status = STATUS_INFO_LENGTH_MISMATCH;
2231 break;
2232 }
2233
2234 /* Use SEH for capture */
2235 _SEH2_TRY
2236 {
2237 /* Get the priority */
2238 IdealProcessor = *(PULONG_PTR)ThreadInformation;
2239 }
2240 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2241 {
2242 /* Get the exception code */
2243 Status = _SEH2_GetExceptionCode();
2244 _SEH2_YIELD(break);
2245 }
2246 _SEH2_END;
2247
2248 /* Validate it */
2249 if (IdealProcessor > MAXIMUM_PROCESSORS)
2250 {
2251 /* Fail */
2252 Status = STATUS_INVALID_PARAMETER;
2253 break;
2254 }
2255
2256 /* Set the ideal */
2257 Status = KeSetIdealProcessorThread(&Thread->Tcb,
2258 (CCHAR)IdealProcessor);
2259
2260 /* Get the TEB and protect the thread */
2261 Teb = Thread->Tcb.Teb;
2262 if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
2263 {
2264 /* Save the ideal processor */
2265 Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
2266
2267 /* Release rundown protection */
2268 ExReleaseRundownProtection(&Thread->RundownProtect);
2269 }
2270
2271 break;
2272
2273 case ThreadPriorityBoost:
2274
2275 /* Check buffer length */
2276 if (ThreadInformationLength != sizeof(ULONG_PTR))
2277 {
2278 Status = STATUS_INFO_LENGTH_MISMATCH;
2279 break;
2280 }
2281
2282 /* Use SEH for capture */
2283 _SEH2_TRY
2284 {
2285 /* Get the priority */
2286 DisableBoost = *(PULONG_PTR)ThreadInformation;
2287 }
2288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2289 {
2290 /* Get the exception code */
2291 Status = _SEH2_GetExceptionCode();
2292 _SEH2_YIELD(break);
2293 }
2294 _SEH2_END;
2295
2296 /* Call the kernel */
2297 KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
2298 break;
2299
2300 case ThreadZeroTlsCell:
2301
2302 /* Check buffer length */
2303 if (ThreadInformationLength != sizeof(ULONG_PTR))
2304 {
2305 Status = STATUS_INFO_LENGTH_MISMATCH;
2306 break;
2307 }
2308
2309 /* Use SEH for capture */
2310 _SEH2_TRY
2311 {
2312 /* Get the priority */
2313 TlsIndex = *(PULONG_PTR)ThreadInformation;
2314 }
2315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2316 {
2317 /* Get the exception code */
2318 Status = _SEH2_GetExceptionCode();
2319 _SEH2_YIELD(break);
2320 }
2321 _SEH2_END;
2322
2323 /* This is only valid for the current thread */
2324 if (Thread != PsGetCurrentThread())
2325 {
2326 /* Fail */
2327 Status = STATUS_INVALID_PARAMETER;
2328 break;
2329 }
2330
2331 /* Get the process */
2332 Process = Thread->ThreadsProcess;
2333
2334 /* Loop the threads */
2335 ProcThread = PsGetNextProcessThread(Process, NULL);
2336 while (ProcThread)
2337 {
2338 /* Acquire rundown */
2339 if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
2340 {
2341 /* Get the TEB */
2342 Teb = ProcThread->Tcb.Teb;
2343 if (Teb)
2344 {
2345 /* Check if we're in the expansion range */
2346 if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
2347 {
2348 if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
2349 TLS_EXPANSION_SLOTS) - 1)
2350 {
2351 /* Check if we have expansion slots */
2352 ExpansionSlots = Teb->TlsExpansionSlots;
2353 if (ExpansionSlots)
2354 {
2355 /* Clear the index */
2356 ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
2357 }
2358 }
2359 }
2360 else
2361 {
2362 /* Clear the index */
2363 Teb->TlsSlots[TlsIndex] = NULL;
2364 }
2365 }
2366
2367 /* Release rundown */
2368 ExReleaseRundownProtection(&ProcThread->RundownProtect);
2369 }
2370
2371 /* Go to the next thread */
2372 ProcThread = PsGetNextProcessThread(Process, ProcThread);
2373 }
2374
2375 /* All done */
2376 break;
2377
2378 case ThreadBreakOnTermination:
2379
2380 /* Check buffer length */
2381 if (ThreadInformationLength != sizeof(ULONG))
2382 {
2383 Status = STATUS_INFO_LENGTH_MISMATCH;
2384 break;
2385 }
2386
2387 /* Enter SEH for direct buffer read */
2388 _SEH2_TRY
2389 {
2390 Break = *(PULONG)ThreadInformation;
2391 }
2392 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2393 {
2394 /* Get exception code */
2395 Break = 0;
2396 Status = _SEH2_GetExceptionCode();
2397 _SEH2_YIELD(break);
2398 }
2399 _SEH2_END;
2400
2401 /* Setting 'break on termination' requires the SeDebugPrivilege */
2402 if (!SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
2403 {
2404 /* We don't hold the privilege, bail out */
2405 Status = STATUS_PRIVILEGE_NOT_HELD;
2406 break;
2407 }
2408
2409 /* Set or clear the flag */
2410 if (Break)
2411 {
2412 PspSetCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2413 }
2414 else
2415 {
2416 PspClearCrossThreadFlag(Thread, CT_BREAK_ON_TERMINATION_BIT);
2417 }
2418 break;
2419
2420 default:
2421 /* We don't implement it yet */
2422 DPRINT1("Not implemented: %d\n", ThreadInformationClass);
2423 Status = STATUS_NOT_IMPLEMENTED;
2424 }
2425
2426 /* Dereference and return status */
2427 ObDereferenceObject(Thread);
2428 return Status;
2429 }
2430
2431 /*
2432 * @implemented
2433 */
2434 NTSTATUS
2435 NTAPI
2436 NtQueryInformationThread(IN HANDLE ThreadHandle,
2437 IN THREADINFOCLASS ThreadInformationClass,
2438 OUT PVOID ThreadInformation,
2439 IN ULONG ThreadInformationLength,
2440 OUT PULONG ReturnLength OPTIONAL)
2441 {
2442 PETHREAD Thread;
2443 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2444 NTSTATUS Status;
2445 ULONG Access;
2446 ULONG Length = 0;
2447 PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
2448 (PTHREAD_BASIC_INFORMATION)ThreadInformation;
2449 PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
2450 KIRQL OldIrql;
2451 ULONG ThreadTerminated;
2452 PAGED_CODE();
2453
2454 /* Check if we were called from user mode */
2455 if (PreviousMode != KernelMode)
2456 {
2457 /* Enter SEH */
2458 _SEH2_TRY
2459 {
2460 /* Probe the buffer */
2461 ProbeForWrite(ThreadInformation,
2462 ThreadInformationLength,
2463 sizeof(ULONG));
2464
2465 /* Probe the return length if required */
2466 if (ReturnLength) ProbeForWriteUlong(ReturnLength);
2467 }
2468 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2469 {
2470 /* Return the exception code */
2471 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2472 }
2473 _SEH2_END;
2474 }
2475
2476 /* Check what class this is */
2477 Access = THREAD_QUERY_INFORMATION;
2478
2479 /* Reference the process */
2480 Status = ObReferenceObjectByHandle(ThreadHandle,
2481 Access,
2482 PsThreadType,
2483 PreviousMode,
2484 (PVOID*)&Thread,
2485 NULL);
2486 if (!NT_SUCCESS(Status)) return Status;
2487
2488 /* Check what kind of information class this is */
2489 switch (ThreadInformationClass)
2490 {
2491 /* Basic thread information */
2492 case ThreadBasicInformation:
2493
2494 /* Set return length */
2495 Length = sizeof(THREAD_BASIC_INFORMATION);
2496
2497 if (ThreadInformationLength != Length)
2498 {
2499 Status = STATUS_INFO_LENGTH_MISMATCH;
2500 break;
2501 }
2502 /* Protect writes with SEH */
2503 _SEH2_TRY
2504 {
2505 /* Write all the information from the ETHREAD/KTHREAD */
2506 ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
2507 ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
2508 ThreadBasicInfo->ClientId = Thread->Cid;
2509 ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
2510 ThreadBasicInfo->Priority = Thread->Tcb.Priority;
2511 ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
2512 }
2513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2514 {
2515 /* Get exception code */
2516 Status = _SEH2_GetExceptionCode();
2517 }
2518 _SEH2_END;
2519 break;
2520
2521 /* Thread time information */
2522 case ThreadTimes:
2523
2524 /* Set the return length */
2525 Length = sizeof(KERNEL_USER_TIMES);
2526
2527 if (ThreadInformationLength != Length)
2528 {
2529 Status = STATUS_INFO_LENGTH_MISMATCH;
2530 break;
2531 }
2532 /* Protect writes with SEH */
2533 _SEH2_TRY
2534 {
2535 /* Copy time information from ETHREAD/KTHREAD */
2536 ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime * KeMaximumIncrement;
2537 ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime * KeMaximumIncrement;
2538 ThreadTime->CreateTime = Thread->CreateTime;
2539
2540 /* Exit time is in a union and only valid on actual exit! */
2541 if (KeReadStateThread(&Thread->Tcb))
2542 {
2543 ThreadTime->ExitTime = Thread->ExitTime;
2544 }
2545 else
2546 {
2547 ThreadTime->ExitTime.QuadPart = 0;
2548 }
2549 }
2550 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2551 {
2552 /* Get exception code */
2553 Status = _SEH2_GetExceptionCode();
2554 }
2555 _SEH2_END;
2556 break;
2557
2558 case ThreadQuerySetWin32StartAddress:
2559
2560 /* Set the return length*/
2561 Length = sizeof(PVOID);
2562
2563 if (ThreadInformationLength != Length)
2564 {
2565 Status = STATUS_INFO_LENGTH_MISMATCH;
2566 break;
2567 }
2568 /* Protect write with SEH */
2569 _SEH2_TRY
2570 {
2571 /* Return the Win32 Start Address */
2572 *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
2573 }
2574 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2575 {
2576 /* Get exception code */
2577 Status = _SEH2_GetExceptionCode();
2578 }
2579 _SEH2_END;
2580 break;
2581
2582 case ThreadPerformanceCount:
2583
2584 /* Set the return length*/
2585 Length = sizeof(LARGE_INTEGER);
2586
2587 if (ThreadInformationLength != Length)
2588 {
2589 Status = STATUS_INFO_LENGTH_MISMATCH;
2590 break;
2591 }
2592 /* Protect write with SEH */
2593 _SEH2_TRY
2594 {
2595 /* FIXME */
2596 (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
2597 }
2598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2599 {
2600 /* Get exception code */
2601 Status = _SEH2_GetExceptionCode();
2602 }
2603 _SEH2_END;
2604 break;
2605
2606 case ThreadAmILastThread:
2607
2608 /* Set the return length*/
2609 Length = sizeof(ULONG);
2610
2611 if (ThreadInformationLength != Length)
2612 {
2613 Status = STATUS_INFO_LENGTH_MISMATCH;
2614 break;
2615 }
2616 /* Protect write with SEH */
2617 _SEH2_TRY
2618 {
2619 /* Return whether or not we are the last thread */
2620 *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
2621 ThreadListHead.Flink->Flink ==
2622 &Thread->ThreadsProcess->
2623 ThreadListHead) ?
2624 TRUE : FALSE);
2625 }
2626 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2627 {
2628 /* Get exception code */
2629 Status = _SEH2_GetExceptionCode();
2630 }
2631 _SEH2_END;
2632 break;
2633
2634 case ThreadIsIoPending:
2635
2636 /* Set the return length*/
2637 Length = sizeof(ULONG);
2638
2639 if (ThreadInformationLength != Length)
2640 {
2641 Status = STATUS_INFO_LENGTH_MISMATCH;
2642 break;
2643 }
2644 /* Raise the IRQL to protect the IRP list */
2645 KeRaiseIrql(APC_LEVEL, &OldIrql);
2646
2647 /* Protect write with SEH */
2648 _SEH2_TRY
2649 {
2650 /* Check if the IRP list is empty or not */
2651 *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
2652 }
2653 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2654 {
2655 /* Get exception code */
2656 Status = _SEH2_GetExceptionCode();
2657 }
2658 _SEH2_END;
2659
2660 /* Lower IRQL back */
2661 KeLowerIrql(OldIrql);
2662 break;
2663
2664 /* LDT and GDT information */
2665 case ThreadDescriptorTableEntry:
2666
2667 #if defined(_X86_)
2668 /* Call the worker routine */
2669 Status = PspQueryDescriptorThread(Thread,
2670 ThreadInformation,
2671 ThreadInformationLength,
2672 ReturnLength);
2673 #else
2674 /* Only implemented on x86 */
2675 Status = STATUS_NOT_IMPLEMENTED;
2676 #endif
2677 break;
2678
2679 case ThreadPriorityBoost:
2680
2681 /* Set the return length*/
2682 Length = sizeof(ULONG);
2683
2684 if (ThreadInformationLength != Length)
2685 {
2686 Status = STATUS_INFO_LENGTH_MISMATCH;
2687 break;
2688 }
2689
2690 _SEH2_TRY
2691 {
2692 *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
2693 }
2694 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2695 {
2696 Status = _SEH2_GetExceptionCode();
2697 }
2698 _SEH2_END;
2699 break;
2700
2701 case ThreadIsTerminated:
2702
2703 /* Set the return length*/
2704 Length = sizeof(ThreadTerminated);
2705
2706 if (ThreadInformationLength != Length)
2707 {
2708 Status = STATUS_INFO_LENGTH_MISMATCH;
2709 break;
2710 }
2711
2712 ThreadTerminated = PsIsThreadTerminating(Thread);
2713
2714 _SEH2_TRY
2715 {
2716 *(PULONG)ThreadInformation = ThreadTerminated ? 1 : 0;
2717 }
2718 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2719 {
2720 Status = _SEH2_GetExceptionCode();
2721 }
2722 _SEH2_END;
2723
2724 break;
2725
2726 /* Anything else */
2727 default:
2728
2729 /* Not yet implemented */
2730 DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
2731 Status = STATUS_NOT_IMPLEMENTED;
2732 }
2733
2734 /* Protect write with SEH */
2735 _SEH2_TRY
2736 {
2737 /* Check if caller wanted return length */
2738 if (ReturnLength) *ReturnLength = Length;
2739 }
2740 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2741 {
2742 /* Get exception code */
2743 Status = _SEH2_GetExceptionCode();
2744 }
2745 _SEH2_END;
2746
2747 /* Dereference the thread, and return */
2748 ObDereferenceObject(Thread);
2749 return Status;
2750 }
2751
2752 /* EOF */