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