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