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