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