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