- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / ps / query.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/query.c
5 * PURPOSE: Set/Query Process/Thread Information APIs
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File
8 * David Welch
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 static const INFORMATION_CLASS_INFO PsProcessInfoClass[] =
20 {
21 ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */
22 ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */
23 ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */
24 ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */
25 ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */
26 ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */
27 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */
28 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY ), /* ProcessDebugPort */
29 ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */
30 ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */
31 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */
32 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */
33 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */
34 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */
35 ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */
36 ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */
37 ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */
38 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */
39 ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */
40 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */
41 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */
42 ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */
43 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */
44
45 ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */
46 /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set),
47 /*Q*/ sizeof(ULONG),
48 /*S*/ sizeof(ULONG),
49 ICIF_QUERY | ICIF_SET ),
50
51 ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */
52 ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */
53 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */
54 ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */
55
56 /* FIXME */
57 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */
58 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */
59 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */
60 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */
61 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */
62 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */
63 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */
64 ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */
65
66 ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */
67 };
68
69 /*
70 * FIXME:
71 * Remove the Implemented value if all functions are implemented.
72 */
73
74 static const struct
75 {
76 BOOLEAN Implemented;
77 ULONG Size;
78 } QueryInformationData[MaxThreadInfoClass + 1] =
79 {
80 {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation
81 {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes
82 {TRUE, 0}, // ThreadPriority
83 {TRUE, 0}, // ThreadBasePriority
84 {TRUE, 0}, // ThreadAffinityMask
85 {TRUE, 0}, // ThreadImpersonationToken
86 {FALSE, 0}, // ThreadDescriptorTableEntry
87 {TRUE, 0}, // ThreadEnableAlignmentFaultFixup
88 {TRUE, 0}, // ThreadEventPair
89 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
90 {TRUE, 0}, // ThreadZeroTlsCell
91 {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount
92 {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread
93 {TRUE, 0}, // ThreadIdealProcessor
94 {FALSE, 0}, // ThreadPriorityBoost
95 {TRUE, 0}, // ThreadSetTlsArrayAddress
96 {FALSE, 0}, // ThreadIsIoPending
97 {TRUE, 0} // ThreadHideFromDebugger
98 };
99
100 static const struct
101 {
102 BOOLEAN Implemented;
103 ULONG Size;
104 } SetInformationData[MaxThreadInfoClass + 1] =
105 {
106 {TRUE, 0}, // ThreadBasicInformation
107 {TRUE, 0}, // ThreadTimes
108 {TRUE, sizeof(KPRIORITY)}, // ThreadPriority
109 {TRUE, sizeof(LONG)}, // ThreadBasePriority
110 {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask
111 {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken
112 {TRUE, 0}, // ThreadDescriptorTableEntry
113 {FALSE, 0}, // ThreadEnableAlignmentFaultFixup
114 {FALSE, 0}, // ThreadEventPair
115 {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress
116 {FALSE, 0}, // ThreadZeroTlsCell
117 {TRUE, 0}, // ThreadPerformanceCount
118 {TRUE, 0}, // ThreadAmILastThread
119 {FALSE, 0}, // ThreadIdealProcessor
120 {FALSE, 0}, // ThreadPriorityBoost
121 {FALSE, 0}, // ThreadSetTlsArrayAddress
122 {TRUE, 0}, // ThreadIsIoPending
123 {FALSE, 0} // ThreadHideFromDebugger
124 };
125
126 /* FUNCTIONS *****************************************************************/
127
128 /*
129 * @unimplemented
130 */
131 NTSTATUS STDCALL
132 NtQueryInformationProcess(IN HANDLE ProcessHandle,
133 IN PROCESSINFOCLASS ProcessInformationClass,
134 OUT PVOID ProcessInformation,
135 IN ULONG ProcessInformationLength,
136 OUT PULONG ReturnLength OPTIONAL)
137 {
138 PEPROCESS Process;
139 KPROCESSOR_MODE PreviousMode;
140 NTSTATUS Status = STATUS_SUCCESS;
141
142 PAGED_CODE();
143
144 PreviousMode = ExGetPreviousMode();
145
146 Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
147 PsProcessInfoClass,
148 sizeof(PsProcessInfoClass) / sizeof(PsProcessInfoClass[0]),
149 ProcessInformation,
150 ProcessInformationLength,
151 ReturnLength,
152 PreviousMode);
153 if(!NT_SUCCESS(Status))
154 {
155 DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status);
156 return Status;
157 }
158
159 if(ProcessInformationClass != ProcessCookie)
160 {
161 Status = ObReferenceObjectByHandle(ProcessHandle,
162 PROCESS_QUERY_INFORMATION,
163 PsProcessType,
164 PreviousMode,
165 (PVOID*)&Process,
166 NULL);
167 if (!NT_SUCCESS(Status))
168 {
169 return(Status);
170 }
171 }
172 else if(ProcessHandle != NtCurrentProcess())
173 {
174 /* retreiving the process cookie is only allowed for the calling process
175 itself! XP only allowes NtCurrentProcess() as process handles even if a
176 real handle actually represents the current process. */
177 return STATUS_INVALID_PARAMETER;
178 }
179
180 switch (ProcessInformationClass)
181 {
182 case ProcessBasicInformation:
183 {
184 PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
185 (PPROCESS_BASIC_INFORMATION)ProcessInformation;
186
187 _SEH_TRY
188 {
189 ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
190 ProcessBasicInformationP->PebBaseAddress = Process->Peb;
191 ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
192 ProcessBasicInformationP->UniqueProcessId =
193 (ULONG)Process->UniqueProcessId;
194 ProcessBasicInformationP->InheritedFromUniqueProcessId =
195 (ULONG)Process->InheritedFromUniqueProcessId;
196 ProcessBasicInformationP->BasePriority =
197 Process->Pcb.BasePriority;
198
199 if (ReturnLength)
200 {
201 *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
202 }
203 }
204 _SEH_HANDLE
205 {
206 Status = _SEH_GetExceptionCode();
207 }
208 _SEH_END;
209 break;
210 }
211
212 case ProcessQuotaLimits:
213 case ProcessIoCounters:
214 Status = STATUS_NOT_IMPLEMENTED;
215 break;
216
217 case ProcessTimes:
218 {
219 PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation;
220 _SEH_TRY
221 {
222 ProcessTimeP->CreateTime = Process->CreateTime;
223 ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL;
224 ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL;
225 ProcessTimeP->ExitTime = Process->ExitTime;
226
227 if (ReturnLength)
228 {
229 *ReturnLength = sizeof(KERNEL_USER_TIMES);
230 }
231 }
232 _SEH_HANDLE
233 {
234 Status = _SEH_GetExceptionCode();
235 }
236 _SEH_END;
237 break;
238 }
239
240 case ProcessDebugPort:
241 {
242 _SEH_TRY
243 {
244 *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL);
245 if (ReturnLength)
246 {
247 *ReturnLength = sizeof(HANDLE);
248 }
249 }
250 _SEH_HANDLE
251 {
252 Status = _SEH_GetExceptionCode();
253 }
254 _SEH_END;
255 break;
256 }
257
258 case ProcessLdtInformation:
259 case ProcessWorkingSetWatch:
260 case ProcessWx86Information:
261 Status = STATUS_NOT_IMPLEMENTED;
262 break;
263
264 case ProcessHandleCount:
265 {
266 ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
267
268 _SEH_TRY
269 {
270 *(PULONG)ProcessInformation = HandleCount;
271 if (ReturnLength)
272 {
273 *ReturnLength = sizeof(ULONG);
274 }
275 }
276 _SEH_HANDLE
277 {
278 Status = _SEH_GetExceptionCode();
279 }
280 _SEH_END;
281 break;
282 }
283
284 case ProcessSessionInformation:
285 {
286 PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation;
287
288 _SEH_TRY
289 {
290 SessionInfo->SessionId = Process->Session;
291 if (ReturnLength)
292 {
293 *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION);
294 }
295 }
296 _SEH_HANDLE
297 {
298 Status = _SEH_GetExceptionCode();
299 }
300 _SEH_END;
301 break;
302 }
303
304 case ProcessWow64Information:
305 DPRINT1("We currently don't support the ProcessWow64Information information class!\n");
306 Status = STATUS_NOT_IMPLEMENTED;
307 break;
308
309 case ProcessVmCounters:
310 {
311 PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
312
313 _SEH_TRY
314 {
315 pOut->PeakVirtualSize = Process->PeakVirtualSize;
316 /*
317 * Here we should probably use VirtualSize.LowPart, but due to
318 * incompatibilities in current headers (no unnamed union),
319 * I opted for cast.
320 */
321 pOut->VirtualSize = (ULONG)Process->VirtualSize;
322 pOut->PageFaultCount = Process->Vm.PageFaultCount;
323 pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize;
324 pOut->WorkingSetSize = Process->Vm.WorkingSetSize;
325 pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeak[0]; // TODO: Verify!
326 pOut->QuotaPagedPoolUsage = Process->QuotaUsage[0]; // TODO: Verify!
327 pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeak[1]; // TODO: Verify!
328 pOut->QuotaNonPagedPoolUsage = Process->QuotaUsage[1]; // TODO: Verify!
329 pOut->PagefileUsage = Process->QuotaUsage[2];
330 pOut->PeakPagefileUsage = Process->QuotaPeak[2];
331
332 if (ReturnLength)
333 {
334 *ReturnLength = sizeof(VM_COUNTERS);
335 }
336 }
337 _SEH_HANDLE
338 {
339 Status = _SEH_GetExceptionCode();
340 }
341 _SEH_END;
342 break;
343 }
344
345 case ProcessDefaultHardErrorMode:
346 {
347 PULONG HardErrMode = (PULONG)ProcessInformation;
348 _SEH_TRY
349 {
350 *HardErrMode = Process->DefaultHardErrorProcessing;
351 if (ReturnLength)
352 {
353 *ReturnLength = sizeof(ULONG);
354 }
355 }
356 _SEH_HANDLE
357 {
358 Status = _SEH_GetExceptionCode();
359 }
360 _SEH_END;
361 break;
362 }
363
364 case ProcessPriorityBoost:
365 {
366 PULONG BoostEnabled = (PULONG)ProcessInformation;
367
368 _SEH_TRY
369 {
370 *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
371
372 if (ReturnLength)
373 {
374 *ReturnLength = sizeof(ULONG);
375 }
376 }
377 _SEH_HANDLE
378 {
379 Status = _SEH_GetExceptionCode();
380 }
381 _SEH_END;
382 break;
383 }
384
385 case ProcessDeviceMap:
386 {
387 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
388
389 ObQueryDeviceMapInformation(Process, &DeviceMap);
390
391 _SEH_TRY
392 {
393 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
394 if (ReturnLength)
395 {
396 *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION);
397 }
398 }
399 _SEH_HANDLE
400 {
401 Status = _SEH_GetExceptionCode();
402 }
403 _SEH_END;
404 break;
405 }
406
407 case ProcessPriorityClass:
408 {
409 PUSHORT Priority = (PUSHORT)ProcessInformation;
410
411 _SEH_TRY
412 {
413 *Priority = Process->PriorityClass;
414
415 if (ReturnLength)
416 {
417 *ReturnLength = sizeof(USHORT);
418 }
419 }
420 _SEH_HANDLE
421 {
422 Status = _SEH_GetExceptionCode();
423 }
424 _SEH_END;
425 break;
426 }
427
428 case ProcessImageFileName:
429 {
430 ULONG ImagePathLen = 0;
431 PROS_SECTION_OBJECT Section;
432 PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation;
433 PWSTR SrcBuffer = NULL, DstBuffer = (PWSTR)(DstPath + 1);
434
435 Section = (PROS_SECTION_OBJECT)Process->SectionObject;
436
437 if (Section != NULL && Section->FileObject != NULL)
438 {
439 /* FIXME - check for SEC_IMAGE and/or SEC_FILE instead
440 of relying on FileObject being != NULL? */
441 SrcBuffer = Section->FileObject->FileName.Buffer;
442 if (SrcBuffer != NULL)
443 {
444 ImagePathLen = Section->FileObject->FileName.Length;
445 }
446 }
447
448 if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR))
449 {
450 Status = STATUS_INFO_LENGTH_MISMATCH;
451 }
452 else
453 {
454 _SEH_TRY
455 {
456 /* copy the string manually, don't use RtlCopyUnicodeString with DstPath! */
457 DstPath->Length = ImagePathLen;
458 DstPath->MaximumLength = ImagePathLen + sizeof(WCHAR);
459 DstPath->Buffer = DstBuffer;
460 if (ImagePathLen != 0)
461 {
462 RtlCopyMemory(DstBuffer,
463 SrcBuffer,
464 ImagePathLen);
465 }
466 DstBuffer[ImagePathLen / sizeof(WCHAR)] = L'\0';
467
468 Status = STATUS_SUCCESS;
469 }
470 _SEH_HANDLE
471 {
472 Status = _SEH_GetExceptionCode();
473 }
474 _SEH_END;
475 }
476 break;
477 }
478
479 case ProcessCookie:
480 {
481 ULONG Cookie;
482
483 /* receive the process cookie, this is only allowed for the current
484 process! */
485
486 Process = PsGetCurrentProcess();
487
488 Cookie = Process->Cookie;
489 if(Cookie == 0)
490 {
491 LARGE_INTEGER SystemTime;
492 ULONG NewCookie;
493 PKPRCB Prcb;
494
495 /* generate a new cookie */
496
497 KeQuerySystemTime(&SystemTime);
498
499 Prcb = KeGetCurrentPrcb();
500
501 NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^
502 SystemTime.u.LowPart ^ SystemTime.u.HighPart;
503
504 /* try to set the new cookie, return the current one if another thread
505 set it in the meanwhile */
506 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
507 NewCookie,
508 Cookie);
509 if(Cookie == 0)
510 {
511 /* successfully set the cookie */
512 Cookie = NewCookie;
513 }
514 }
515
516 _SEH_TRY
517 {
518 *(PULONG)ProcessInformation = Cookie;
519 if (ReturnLength)
520 {
521 *ReturnLength = sizeof(ULONG);
522 }
523 }
524 _SEH_HANDLE
525 {
526 Status = _SEH_GetExceptionCode();
527 }
528 _SEH_END;
529
530 break;
531 }
532
533 /*
534 * Note: The following 10 information classes are verified to not be
535 * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
536 */
537 case ProcessBasePriority:
538 case ProcessRaisePriority:
539 case ProcessExceptionPort:
540 case ProcessAccessToken:
541 case ProcessLdtSize:
542 case ProcessIoPortHandlers:
543 case ProcessUserModeIOPL:
544 case ProcessEnableAlignmentFaultFixup:
545 case ProcessAffinityMask:
546 case ProcessForegroundInformation:
547 default:
548 Status = STATUS_INVALID_INFO_CLASS;
549 }
550
551 if(ProcessInformationClass != ProcessCookie)
552 {
553 ObDereferenceObject(Process);
554 }
555
556 return Status;
557 }
558
559 /*
560 * @unimplemented
561 */
562 NTSTATUS STDCALL
563 NtSetInformationProcess(IN HANDLE ProcessHandle,
564 IN PROCESSINFOCLASS ProcessInformationClass,
565 IN PVOID ProcessInformation,
566 IN ULONG ProcessInformationLength)
567 {
568 PEPROCESS Process;
569 KPROCESSOR_MODE PreviousMode;
570 ACCESS_MASK Access;
571 NTSTATUS Status = STATUS_SUCCESS;
572
573 PAGED_CODE();
574
575 PreviousMode = ExGetPreviousMode();
576
577 Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
578 PsProcessInfoClass,
579 sizeof(PsProcessInfoClass) / sizeof(PsProcessInfoClass[0]),
580 ProcessInformation,
581 ProcessInformationLength,
582 PreviousMode);
583 if(!NT_SUCCESS(Status))
584 {
585 DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength);
586 DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status);
587 return Status;
588 }
589
590 switch(ProcessInformationClass)
591 {
592 case ProcessSessionInformation:
593 Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID;
594 break;
595 case ProcessExceptionPort:
596 Access = PROCESS_SET_INFORMATION | PROCESS_SUSPEND_RESUME;
597 break;
598
599 default:
600 Access = PROCESS_SET_INFORMATION;
601 break;
602 }
603
604 Status = ObReferenceObjectByHandle(ProcessHandle,
605 Access,
606 PsProcessType,
607 PreviousMode,
608 (PVOID*)&Process,
609 NULL);
610 if (!NT_SUCCESS(Status))
611 {
612 return(Status);
613 }
614
615 switch (ProcessInformationClass)
616 {
617 case ProcessQuotaLimits:
618 case ProcessBasePriority:
619 case ProcessRaisePriority:
620 Status = STATUS_NOT_IMPLEMENTED;
621 break;
622
623 case ProcessExceptionPort:
624 {
625 HANDLE PortHandle = NULL;
626
627 /* make a safe copy of the buffer on the stack */
628 _SEH_TRY
629 {
630 PortHandle = *(PHANDLE)ProcessInformation;
631 Status = STATUS_SUCCESS;
632 }
633 _SEH_HANDLE
634 {
635 Status = _SEH_GetExceptionCode();
636 }
637 _SEH_END;
638
639 if(NT_SUCCESS(Status))
640 {
641 PEPORT ExceptionPort;
642
643 /* in case we had success reading from the buffer, verify the provided
644 * LPC port handle
645 */
646 Status = ObReferenceObjectByHandle(PortHandle,
647 0,
648 LpcPortObjectType,
649 PreviousMode,
650 (PVOID)&ExceptionPort,
651 NULL);
652 if(NT_SUCCESS(Status))
653 {
654 /* lock the process to be thread-safe! */
655
656 Status = PsLockProcess((PROS_EPROCESS)Process, FALSE);
657 if(NT_SUCCESS(Status))
658 {
659 /*
660 * according to "NT Native API" documentation, setting the exception
661 * port is only permitted once!
662 */
663 if(Process->ExceptionPort == NULL)
664 {
665 /* keep the reference to the handle! */
666 Process->ExceptionPort = ExceptionPort;
667 Status = STATUS_SUCCESS;
668 }
669 else
670 {
671 ObDereferenceObject(ExceptionPort);
672 Status = STATUS_PORT_ALREADY_SET;
673 }
674 PsUnlockProcess((PROS_EPROCESS)Process);
675 }
676 else
677 {
678 ObDereferenceObject(ExceptionPort);
679 }
680 }
681 }
682 break;
683 }
684
685 case ProcessAccessToken:
686 {
687 HANDLE TokenHandle = NULL;
688
689 /* make a safe copy of the buffer on the stack */
690 _SEH_TRY
691 {
692 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token;
693 Status = STATUS_SUCCESS;
694 }
695 _SEH_HANDLE
696 {
697 Status = _SEH_GetExceptionCode();
698 }
699 _SEH_END;
700
701 if(NT_SUCCESS(Status))
702 {
703 /* in case we had success reading from the buffer, perform the actual task */
704 Status = PspAssignPrimaryToken(Process, TokenHandle);
705 }
706 break;
707 }
708
709 case ProcessDefaultHardErrorMode:
710 {
711 _SEH_TRY
712 {
713 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
714 *(PLONG)ProcessInformation);
715 Status = STATUS_SUCCESS;
716 }
717 _SEH_HANDLE
718 {
719 Status = _SEH_GetExceptionCode();
720 }
721 _SEH_END;
722 break;
723 }
724
725 case ProcessSessionInformation:
726 {
727 PROCESS_SESSION_INFORMATION SessionInfo;
728 Status = STATUS_SUCCESS;
729
730 RtlZeroMemory(&SessionInfo, sizeof(SessionInfo));
731
732 _SEH_TRY
733 {
734 /* copy the structure to the stack */
735 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
736 }
737 _SEH_HANDLE
738 {
739 Status = _SEH_GetExceptionCode();
740 }
741 _SEH_END;
742
743 if(NT_SUCCESS(Status))
744 {
745 /* we successfully copied the structure to the stack, continue processing */
746
747 /*
748 * setting the session id requires the SeTcbPrivilege!
749 */
750 if(!SeSinglePrivilegeCheck(SeTcbPrivilege,
751 PreviousMode))
752 {
753 DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n");
754 /* can't set the session id, bail! */
755 Status = STATUS_PRIVILEGE_NOT_HELD;
756 break;
757 }
758
759 /* FIXME - update the session id for the process token */
760
761 Status = PsLockProcess((PROS_EPROCESS)Process, FALSE);
762 if(NT_SUCCESS(Status))
763 {
764 Process->Session = SessionInfo.SessionId;
765
766 /* Update the session id in the PEB structure */
767 if(Process->Peb != NULL)
768 {
769 /* we need to attach to the process to make sure we're in the right
770 context to access the PEB structure */
771 KeAttachProcess(&Process->Pcb);
772
773 _SEH_TRY
774 {
775 /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */
776
777 Status = STATUS_SUCCESS;
778 }
779 _SEH_HANDLE
780 {
781 Status = _SEH_GetExceptionCode();
782 }
783 _SEH_END;
784
785 KeDetachProcess();
786 }
787
788 PsUnlockProcess((PROS_EPROCESS)Process);
789 }
790 }
791 break;
792 }
793
794 case ProcessPriorityClass:
795 {
796 PROCESS_PRIORITY_CLASS ppc;
797
798 _SEH_TRY
799 {
800 ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
801 }
802 _SEH_HANDLE
803 {
804 Status = _SEH_GetExceptionCode();
805 }
806 _SEH_END;
807
808 if(NT_SUCCESS(Status))
809 {
810 }
811
812 break;
813 }
814
815 case ProcessLdtInformation:
816 case ProcessLdtSize:
817 case ProcessIoPortHandlers:
818 case ProcessWorkingSetWatch:
819 case ProcessUserModeIOPL:
820 case ProcessEnableAlignmentFaultFixup:
821 case ProcessAffinityMask:
822 Status = STATUS_NOT_IMPLEMENTED;
823 break;
824
825 case ProcessBasicInformation:
826 case ProcessIoCounters:
827 case ProcessTimes:
828 case ProcessPooledUsageAndLimits:
829 case ProcessWx86Information:
830 case ProcessHandleCount:
831 case ProcessWow64Information:
832 case ProcessDebugPort:
833 default:
834 Status = STATUS_INVALID_INFO_CLASS;
835 }
836 ObDereferenceObject(Process);
837 return(Status);
838 }
839
840
841 /**********************************************************************
842 * NAME INTERNAL
843 * PiQuerySystemProcessInformation
844 *
845 * DESCRIPTION
846 * Compute the size of a process+thread snapshot as
847 * expected by NtQuerySystemInformation.
848 *
849 * RETURN VALUE
850 * 0 on error; otherwise the size, in bytes of the buffer
851 * required to write a full snapshot.
852 *
853 * NOTE
854 * We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
855 */
856 NTSTATUS
857 PiQuerySystemProcessInformation(PVOID Buffer,
858 ULONG Size,
859 PULONG ReqSize)
860 {
861 return STATUS_NOT_IMPLEMENTED;
862
863 #if 0
864 PLIST_ENTRY CurrentEntryP;
865 PEPROCESS CurrentP;
866 PLIST_ENTRY CurrentEntryT;
867 PETHREAD CurrentT;
868
869 ULONG RequiredSize = 0L;
870 BOOLEAN SizeOnly = FALSE;
871
872 ULONG SpiSize = 0L;
873
874 PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
875 PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL;
876 PSYSTEM_THREAD_INFO pInfoT = NULL;
877
878
879 /* Lock the process list. */
880 ExAcquireFastMutex(&PspActiveProcessMutex);
881
882 /*
883 * Scan the process list. Since the
884 * list is circular, the guard is false
885 * after the last process.
886 */
887 for ( CurrentEntryP = PsActiveProcessHead.Flink;
888 (CurrentEntryP != & PsActiveProcessHead);
889 CurrentEntryP = CurrentEntryP->Flink
890 )
891 {
892 /*
893 * Compute how much space is
894 * occupied in the snapshot
895 * by adding this process info.
896 * (at least one thread).
897 */
898 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
899 RequiredSize += SpiSizeCurrent;
900 /*
901 * Do not write process data in the
902 * buffer if it is too small.
903 */
904 if (TRUE == SizeOnly) continue;
905 /*
906 * Check if the buffer can contain
907 * the full snapshot.
908 */
909 if (Size < RequiredSize)
910 {
911 SizeOnly = TRUE;
912 continue;
913 }
914 /*
915 * Get a reference to the
916 * process descriptor we are
917 * handling.
918 */
919 CurrentP = CONTAINING_RECORD(
920 CurrentEntryP,
921 EPROCESS,
922 ProcessListEntry
923 );
924 /*
925 * Write process data in the buffer.
926 */
927 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
928 /* PROCESS */
929 pInfoP->ThreadCount = 0L;
930 pInfoP->ProcessId = CurrentP->UniqueProcessId;
931 RtlInitUnicodeString (
932 & pInfoP->Name,
933 CurrentP->ImageFileName
934 );
935 /* THREAD */
936 for ( pInfoT = & CurrentP->ThreadSysInfo [0],
937 CurrentEntryT = CurrentP->ThreadListHead.Flink;
938
939 (CurrentEntryT != & CurrentP->ThreadListHead);
940
941 pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
942 CurrentEntryT = CurrentEntryT->Flink
943 )
944 {
945 /*
946 * Recalculate the size of the
947 * information block.
948 */
949 if (0 < pInfoP->ThreadCount)
950 {
951 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
952 }
953 /*
954 * Do not write thread data in the
955 * buffer if it is too small.
956 */
957 if (TRUE == SizeOnly) continue;
958 /*
959 * Check if the buffer can contain
960 * the full snapshot.
961 */
962 if (Size < RequiredSize)
963 {
964 SizeOnly = TRUE;
965 continue;
966 }
967 /*
968 * Get a reference to the
969 * thread descriptor we are
970 * handling.
971 */
972 CurrentT = CONTAINING_RECORD(
973 CurrentEntryT,
974 KTHREAD,
975 ThreadListEntry
976 );
977 /*
978 * Write thread data.
979 */
980 RtlZeroMemory (
981 pInfoT,
982 sizeof (SYSTEM_THREAD_INFORMATION)
983 );
984 pInfoT->KernelTime = CurrentT-> ; /* TIME */
985 pInfoT->UserTime = CurrentT-> ; /* TIME */
986 pInfoT->CreateTime = CurrentT-> ; /* TIME */
987 pInfoT->TickCount = CurrentT-> ; /* ULONG */
988 pInfoT->StartEIP = CurrentT-> ; /* ULONG */
989 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
990 pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */
991 pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */
992 pInfoT->BasePriority = CurrentT-> ; /* ULONG */
993 pInfoT->nSwitches = CurrentT-> ; /* ULONG */
994 pInfoT->State = CurrentT-> ; /* DWORD */
995 pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */
996 /*
997 * Count the number of threads
998 * this process has.
999 */
1000 ++ pInfoP->ThreadCount;
1001 }
1002 /*
1003 * Save the size of information
1004 * stored in the buffer for the
1005 * current process.
1006 */
1007 pInfoP->RelativeOffset = SpiSize;
1008 /*
1009 * Save a reference to the last
1010 * valid information block.
1011 */
1012 pInfoPLast = pInfoP;
1013 /*
1014 * Compute the offset of the
1015 * SYSTEM_PROCESS_INFORMATION
1016 * descriptor in the snapshot
1017 * buffer for the next process.
1018 */
1019 (ULONG) pInfoP += SpiSize;
1020 }
1021 /*
1022 * Unlock the process list.
1023 */
1024 ExReleaseFastMutex (
1025 & PspActiveProcessMutex
1026 );
1027 /*
1028 * Return the proper error status code,
1029 * if the buffer was too small.
1030 */
1031 if (TRUE == SizeOnly)
1032 {
1033 if (NULL != RequiredSize)
1034 {
1035 *pRequiredSize = RequiredSize;
1036 }
1037 return STATUS_INFO_LENGTH_MISMATCH;
1038 }
1039 /*
1040 * Mark the end of the snapshot.
1041 */
1042 pInfoP->RelativeOffset = 0L;
1043 /* OK */
1044 return STATUS_SUCCESS;
1045 #endif
1046 }
1047
1048 /*
1049 * @unimplemented
1050 */
1051 NTSTATUS STDCALL
1052 NtSetInformationThread (IN HANDLE ThreadHandle,
1053 IN THREADINFOCLASS ThreadInformationClass,
1054 IN PVOID ThreadInformation,
1055 IN ULONG ThreadInformationLength)
1056 {
1057 PETHREAD Thread;
1058 union
1059 {
1060 KPRIORITY Priority;
1061 LONG Increment;
1062 KAFFINITY Affinity;
1063 HANDLE Handle;
1064 PVOID Address;
1065 }u;
1066 KPROCESSOR_MODE PreviousMode;
1067 NTSTATUS Status = STATUS_SUCCESS;
1068
1069 PAGED_CODE();
1070
1071 PreviousMode = ExGetPreviousMode();
1072
1073 if (ThreadInformationClass <= MaxThreadInfoClass &&
1074 !SetInformationData[ThreadInformationClass].Implemented)
1075 {
1076 return STATUS_NOT_IMPLEMENTED;
1077 }
1078 if (ThreadInformationClass > MaxThreadInfoClass ||
1079 SetInformationData[ThreadInformationClass].Size == 0)
1080 {
1081 return STATUS_INVALID_INFO_CLASS;
1082 }
1083 if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size)
1084 {
1085 return STATUS_INFO_LENGTH_MISMATCH;
1086 }
1087
1088 if (PreviousMode != KernelMode)
1089 {
1090 _SEH_TRY
1091 {
1092 ProbeForRead(ThreadInformation,
1093 SetInformationData[ThreadInformationClass].Size,
1094 1);
1095 RtlCopyMemory(&u.Priority,
1096 ThreadInformation,
1097 SetInformationData[ThreadInformationClass].Size);
1098 }
1099 _SEH_HANDLE
1100 {
1101 Status = _SEH_GetExceptionCode();
1102 }
1103 _SEH_END;
1104
1105 if (!NT_SUCCESS(Status))
1106 {
1107 return Status;
1108 }
1109 }
1110 else
1111 {
1112 RtlCopyMemory(&u.Priority,
1113 ThreadInformation,
1114 SetInformationData[ThreadInformationClass].Size);
1115 }
1116
1117 /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
1118 /* FIXME: We should also check for certain things before doing the reference */
1119 Status = ObReferenceObjectByHandle (ThreadHandle,
1120 THREAD_SET_INFORMATION,
1121 PsThreadType,
1122 ExGetPreviousMode (),
1123 (PVOID*)&Thread,
1124 NULL);
1125 if (NT_SUCCESS(Status))
1126 {
1127 switch (ThreadInformationClass)
1128 {
1129 case ThreadPriority:
1130 if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
1131 {
1132 Status = STATUS_INVALID_PARAMETER;
1133 break;
1134 }
1135 KeSetPriorityThread(&Thread->Tcb, u.Priority);
1136 break;
1137
1138 case ThreadBasePriority:
1139 KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
1140 break;
1141
1142 case ThreadAffinityMask:
1143
1144 /* Check if this is valid */
1145 DPRINT1("%lx, %lx\n", Thread->ThreadsProcess->Pcb.Affinity, u.Affinity);
1146 if ((Thread->ThreadsProcess->Pcb.Affinity & u.Affinity) !=
1147 u.Affinity)
1148 {
1149 DPRINT1("Wrong affinity given\n");
1150 Status = STATUS_INVALID_PARAMETER;
1151 }
1152 else
1153 {
1154 Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
1155 }
1156 break;
1157
1158 case ThreadImpersonationToken:
1159 Status = PsAssignImpersonationToken (Thread, u.Handle);
1160 break;
1161
1162 case ThreadQuerySetWin32StartAddress:
1163 Thread->Win32StartAddress = u.Address;
1164 break;
1165
1166 default:
1167 /* Shoult never occure if the data table is correct */
1168 KEBUGCHECK(0);
1169 }
1170 ObDereferenceObject (Thread);
1171 }
1172
1173 return Status;
1174 }
1175
1176 /*
1177 * @implemented
1178 */
1179 NTSTATUS STDCALL
1180 NtQueryInformationThread (IN HANDLE ThreadHandle,
1181 IN THREADINFOCLASS ThreadInformationClass,
1182 OUT PVOID ThreadInformation,
1183 IN ULONG ThreadInformationLength,
1184 OUT PULONG ReturnLength OPTIONAL)
1185 {
1186 PETHREAD Thread;
1187 union
1188 {
1189 THREAD_BASIC_INFORMATION TBI;
1190 KERNEL_USER_TIMES TTI;
1191 PVOID Address;
1192 LARGE_INTEGER Count;
1193 BOOLEAN Last;
1194 }u;
1195 KPROCESSOR_MODE PreviousMode;
1196 NTSTATUS Status = STATUS_SUCCESS;
1197
1198 PAGED_CODE();
1199
1200 PreviousMode = ExGetPreviousMode();
1201
1202 if (ThreadInformationClass <= MaxThreadInfoClass &&
1203 !QueryInformationData[ThreadInformationClass].Implemented)
1204 {
1205 return STATUS_NOT_IMPLEMENTED;
1206 }
1207 if (ThreadInformationClass > MaxThreadInfoClass ||
1208 QueryInformationData[ThreadInformationClass].Size == 0)
1209 {
1210 return STATUS_INVALID_INFO_CLASS;
1211 }
1212 if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size)
1213 {
1214 return STATUS_INFO_LENGTH_MISMATCH;
1215 }
1216
1217 if (PreviousMode != KernelMode)
1218 {
1219 _SEH_TRY
1220 {
1221 ProbeForWrite(ThreadInformation,
1222 QueryInformationData[ThreadInformationClass].Size,
1223 1);
1224 if (ReturnLength != NULL)
1225 {
1226 ProbeForWriteUlong(ReturnLength);
1227 }
1228 }
1229 _SEH_HANDLE
1230 {
1231 Status = _SEH_GetExceptionCode();
1232 }
1233 _SEH_END;
1234
1235 if (!NT_SUCCESS(Status))
1236 {
1237 return Status;
1238 }
1239 }
1240
1241 Status = ObReferenceObjectByHandle(ThreadHandle,
1242 THREAD_QUERY_INFORMATION,
1243 PsThreadType,
1244 ExGetPreviousMode(),
1245 (PVOID*)&Thread,
1246 NULL);
1247 if (!NT_SUCCESS(Status))
1248 {
1249 return Status;
1250 }
1251
1252 switch (ThreadInformationClass)
1253 {
1254 case ThreadBasicInformation:
1255 /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
1256 * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
1257 * 0. So do the conversion here:
1258 * -Gunnar */
1259 u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
1260 u.TBI.TebBaseAddress = (PVOID)Thread->Tcb.Teb;
1261 u.TBI.ClientId = Thread->Cid;
1262 u.TBI.AffinityMask = Thread->Tcb.Affinity;
1263 u.TBI.Priority = Thread->Tcb.Priority;
1264 u.TBI.BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
1265 break;
1266
1267 case ThreadTimes:
1268 u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
1269 u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
1270 u.TTI.CreateTime = Thread->CreateTime;
1271 /*This works*/
1272 u.TTI.ExitTime = Thread->ExitTime;
1273 break;
1274
1275 case ThreadQuerySetWin32StartAddress:
1276 u.Address = Thread->Win32StartAddress;
1277 break;
1278
1279 case ThreadPerformanceCount:
1280 /* Nebbett says this class is always zero */
1281 u.Count.QuadPart = 0;
1282 break;
1283
1284 case ThreadAmILastThread:
1285 if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
1286 &Thread->ThreadsProcess->ThreadListHead)
1287 {
1288 u.Last = TRUE;
1289 }
1290 else
1291 {
1292 u.Last = FALSE;
1293 }
1294 break;
1295 default:
1296 /* Shoult never occure if the data table is correct */
1297 KEBUGCHECK(0);
1298 }
1299
1300 if (PreviousMode != KernelMode)
1301 {
1302 _SEH_TRY
1303 {
1304 if (QueryInformationData[ThreadInformationClass].Size)
1305 {
1306 RtlCopyMemory(ThreadInformation,
1307 &u.TBI,
1308 QueryInformationData[ThreadInformationClass].Size);
1309 }
1310 if (ReturnLength != NULL)
1311 {
1312 *ReturnLength = QueryInformationData[ThreadInformationClass].Size;
1313 }
1314 }
1315 _SEH_HANDLE
1316 {
1317 Status = _SEH_GetExceptionCode();
1318 }
1319 _SEH_END;
1320 }
1321 else
1322 {
1323 if (QueryInformationData[ThreadInformationClass].Size)
1324 {
1325 RtlCopyMemory(ThreadInformation,
1326 &u.TBI,
1327 QueryInformationData[ThreadInformationClass].Size);
1328 }
1329
1330 if (ReturnLength != NULL)
1331 {
1332 *ReturnLength = QueryInformationData[ThreadInformationClass].Size;
1333 }
1334 }
1335
1336 ObDereferenceObject(Thread);
1337 return(Status);
1338 }
1339 /* EOF */