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