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