Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

psjob.c File Reference

#include "psp.h"
#include "winerror.h"

Go to the source code of this file.

Functions

NTSTATUS NTAPI NtCreateJobObject (OUT PHANDLE JobHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL)
NTSTATUS NTAPI NtOpenJobObject (OUT PHANDLE JobHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
NTSTATUS NTAPI NtAssignProcessToJobObject (IN HANDLE JobHandle, IN HANDLE ProcessHandle)
NTSTATUS PspAddProcessToJob (PEJOB Job, PEPROCESS Process)
VOID PspRemoveProcessFromJob (PEJOB Job, PEPROCESS Process)
VOID PspExitProcessFromJob (PEJOB Job, PEPROCESS Process)
VOID PspJobDelete (IN PVOID Object)
VOID PspJobClose (IN PEPROCESS Process, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG ProcessHandleCount, IN ULONG SystemHandleCount)
NTSTATUS NtQueryInformationJobObject (IN HANDLE JobHandle, IN JOBOBJECTINFOCLASS JobObjectInformationClass, OUT PVOID JobObjectInformation, IN ULONG JobObjectInformationLength, OUT PULONG ReturnLength OPTIONAL)
NTSTATUS NtSetInformationJobObject (IN HANDLE JobHandle, IN JOBOBJECTINFOCLASS JobObjectInformationClass, IN PVOID JobObjectInformation, IN ULONG JobObjectInformationLength)
VOID PspApplyJobLimitsToProcessSet (PEJOB Job)
VOID PspApplyJobLimitsToProcess (PEJOB Job, PEPROCESS Process)
NTSTATUS NtTerminateJobObject (IN HANDLE JobHandle, IN NTSTATUS ExitStatus)
VOID PsEnforceExecutionTimeLimits (VOID)
BOOLEAN PspTerminateAllProcessesInJob (PEJOB Job, NTSTATUS Status, PSLOCKPROCESSMODE LockMode)
VOID PspFoldProcessAccountingIntoJob (PEJOB Job, PEPROCESS Process)
NTSTATUS PspCaptureTokenFilter (KPROCESSOR_MODE PreviousMode, PJOBOBJECT_SECURITY_LIMIT_INFORMATION SecurityLimitInfo, PPS_JOB_TOKEN_FILTER *TokenFilter)
BOOLEAN PsChangeJobMemoryUsage (SSIZE_T Amount)
VOID PsReportProcessMemoryLimitViolation (VOID)

Variables

POBJECT_TYPE IoCompletionObjectType
ULONG PspJobInfoLengths []
ULONG PspJobInfoAlign []


Function Documentation

NTSTATUS NTAPI NtAssignProcessToJobObject IN HANDLE  JobHandle,
IN HANDLE  ProcessHandle
 

Definition at line 266 of file psjob.c.

References _WIN32_JOBCALLOUT_PARAMETERS::CalloutType, _WIN32_JOBCALLOUT_PARAMETERS::Data, ExAcquireResourceExclusive, ExReleaseResource, IsAdmin(), _WIN32_JOBCALLOUT_PARAMETERS::Job, KeEnterCriticalRegion, KeLeaveCriticalRegion, KPROCESSOR_MODE, MmDispatchWin32Callout(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PsFreeProcessSecurityFields, PsJobType, PsLockPollOnTimeout, PsLockProcess(), PsLockProcessSecurityFields, PspAddProcessToJob(), PsProcessType, PspSetPrimaryToken(), PspTerminateProcess(), PspW32JobCallout, PsUnlockProcess(), PsW32JobCalloutAddProcess, SeTokenIsAdmin(), Status, and TRUE.

00270 { 00271 PEJOB Job; 00272 PEPROCESS Process; 00273 NTSTATUS Status; 00274 KPROCESSOR_MODE PreviousMode; 00275 BOOLEAN IsAdmin ; 00276 00277 PAGED_CODE(); 00278 00279 PreviousMode = KeGetPreviousMode(); 00280 00281 // 00282 // Reference the process object, lock the process, test for already been assigned 00283 // 00284 00285 Status = ObReferenceObjectByHandle( 00286 ProcessHandle, 00287 PROCESS_SET_QUOTA | PROCESS_TERMINATE, 00288 PsProcessType, 00289 PreviousMode, 00290 (PVOID *)&Process, 00291 NULL 00292 ); 00293 if ( !NT_SUCCESS(Status) ) { 00294 return Status; 00295 } 00296 00297 // 00298 // Quick Check for prior assignment 00299 // 00300 00301 if ( Process->Job ) { 00302 ObDereferenceObject(Process); 00303 return STATUS_ACCESS_DENIED; 00304 } 00305 00306 00307 // 00308 // Now reference the job object. Then we need to lock the process and check again 00309 // 00310 00311 Status = ObReferenceObjectByHandle( 00312 JobHandle, 00313 JOB_OBJECT_ASSIGN_PROCESS, 00314 PsJobType, 00315 PreviousMode, 00316 (PVOID *)&Job, 00317 NULL 00318 ); 00319 if ( !NT_SUCCESS(Status) ) { 00320 ObDereferenceObject(Process); 00321 return Status; 00322 } 00323 00324 // 00325 // We only allow a process that is running in the Job creator's hydra session 00326 // to be assigned to the job. 00327 // 00328 00329 if ( Process->SessionId != Job->SessionId ) { 00330 00331 ObDereferenceObject(Process); 00332 ObDereferenceObject(Job); 00333 return STATUS_ACCESS_DENIED; 00334 00335 } 00336 00337 00338 Status = PsLockProcess(Process,PreviousMode,PsLockPollOnTimeout); 00339 if ( !NT_SUCCESS(Status) || Process->Job ) { 00340 if ( !NT_SUCCESS(Status) ) { 00341 Status = STATUS_PROCESS_IS_TERMINATING; 00342 } 00343 else { 00344 Status = STATUS_ACCESS_DENIED; 00345 PsUnlockProcess(Process); 00346 } 00347 ObDereferenceObject(Process); 00348 ObDereferenceObject(Job); 00349 return Status ; 00350 } 00351 00352 // 00353 // Security Rules: If the job has no-admin set, and it is running 00354 // as admin, that's not allowed 00355 // 00356 00357 if ( Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN ) 00358 { 00359 PsLockProcessSecurityFields(); 00360 00361 IsAdmin = SeTokenIsAdmin( Process->Token ); 00362 00363 PsFreeProcessSecurityFields(); 00364 00365 if ( IsAdmin ) 00366 { 00367 Status = STATUS_ACCESS_DENIED ; 00368 00369 PsUnlockProcess( Process ); 00370 00371 ObDereferenceObject( Process ); 00372 00373 ObDereferenceObject( Job ); 00374 00375 return Status ; 00376 } 00377 00378 } 00379 00380 // 00381 // If the job has a token filter established, 00382 // use it to filter the 00383 00384 // 00385 // ref the job for the process 00386 // 00387 00388 ObReferenceObject(Job); 00389 00390 Process->Job = Job; 00391 00392 PsUnlockProcess(Process); 00393 00394 Status = PspAddProcessToJob(Job,Process); 00395 if ( !NT_SUCCESS(Status) ) { 00396 Job->TotalTerminatedProcesses++; 00397 PspTerminateProcess(Process,ERROR_NOT_ENOUGH_QUOTA,PsLockPollOnTimeout); 00398 } 00399 00400 // 00401 // If the job has UI restrictions and this is a GUI process, call ntuser 00402 // 00403 if ( ( Job->UIRestrictionsClass != JOB_OBJECT_UILIMIT_NONE ) && 00404 ( Process->Win32Process != NULL ) ) { 00405 WIN32_JOBCALLOUT_PARAMETERS Parms; 00406 00407 KeEnterCriticalRegion(); 00408 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00409 00410 Parms.Job = Job; 00411 Parms.CalloutType = PsW32JobCalloutAddProcess; 00412 Parms.Data = Process->Win32Process; 00413 MmDispatchWin32Callout( PspW32JobCallout,NULL, (PVOID)&Parms, &(Job->SessionId)); 00414 00415 ExReleaseResource(&Job->JobLock); 00416 KeLeaveCriticalRegion(); 00417 00418 } 00419 00420 if ( Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_ONLY_TOKEN ) 00421 { 00422 Status = PspSetPrimaryToken( ProcessHandle, NULL, Job->Token ); 00423 00424 if ( !NT_SUCCESS( Status ) ) 00425 { 00426 // 00427 // What? 00428 // 00429 } 00430 } 00431 00432 ObDereferenceObject(Process); 00433 ObDereferenceObject(Job); 00434 00435 return Status; 00436 }

NTSTATUS NTAPI NtCreateJobObject OUT PHANDLE  JobHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL
 

Definition at line 48 of file psjob.c.

References EJOB, ExInitializeFastMutex, ExInitializeResource, ExSystemExceptionFilter(), FALSE, Handle, KeInitializeEvent, KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObCreateObject(), ObDereferenceObject, ObInsertObject(), ObjectAttributes, PAGED_CODE, ProbeForWriteHandle, PsGetCurrentProcess, PsJobType, PSP_DEFAULT_SCHEDULING_CLASSES, PspJobList, PspJobListLock, and Status.

00053 { 00054 00055 PEJOB Job; 00056 HANDLE Handle; 00057 KPROCESSOR_MODE PreviousMode; 00058 NTSTATUS Status; 00059 00060 PAGED_CODE(); 00061 00062 // 00063 // Establish an exception handler, probe the output handle address, and 00064 // attempt to create a job object. If the probe fails, then return the 00065 // exception code as the service status. Otherwise return the status value 00066 // returned by the object insertion routine. 00067 // 00068 00069 try { 00070 00071 // 00072 // Get previous processor mode and probe output handle address if 00073 // necessary. 00074 // 00075 00076 PreviousMode = KeGetPreviousMode(); 00077 if (PreviousMode != KernelMode) { 00078 ProbeForWriteHandle(JobHandle); 00079 } 00080 00081 // 00082 // Allocate job object. 00083 // 00084 00085 Status = ObCreateObject( 00086 PreviousMode, 00087 PsJobType, 00088 ObjectAttributes, 00089 PreviousMode, 00090 NULL, 00091 sizeof(EJOB), 00092 0, 00093 0, 00094 (PVOID *)&Job 00095 ); 00096 00097 // 00098 // If the job object was successfully allocated, then initialize it 00099 // and attempt to insert the job object in the current 00100 // process' handle table. 00101 // 00102 00103 if (NT_SUCCESS(Status)) { 00104 00105 RtlZeroMemory(Job,sizeof(EJOB)); 00106 InitializeListHead(&Job->ProcessListHead); 00107 KeInitializeEvent(&Job->Event,NotificationEvent,FALSE); 00108 00109 // 00110 // Job Object gets the SessionId of the Process creating the Job 00111 // We will use this sessionid to restrict the processes that can 00112 // be added to a job. 00113 // 00114 Job->SessionId = PsGetCurrentProcess()->SessionId; 00115 00116 // 00117 // Initialize the scheduling class for the Job 00118 // 00119 Job->SchedulingClass = PSP_DEFAULT_SCHEDULING_CLASSES; 00120 00121 // 00122 // Insert Job on Job List 00123 // 00124 00125 ExAcquireFastMutex(&PspJobListLock); 00126 InsertTailList(&PspJobList,&Job->JobLinks); 00127 ExReleaseFastMutex(&PspJobListLock); 00128 00129 Status = ExInitializeResource(&Job->JobLock); 00130 if ( !NT_SUCCESS(Status) ) { 00131 00132 // 00133 // Note that ExInitializeResource really can't fail and 00134 // is hard coded to return success. 00135 // 00136 ObDereferenceObject(Job); 00137 00138 } 00139 else { 00140 ExInitializeFastMutex(&Job->MemoryLimitsLock); 00141 Status = ObInsertObject( 00142 (PVOID)Job, 00143 NULL, 00144 DesiredAccess, 00145 0, 00146 (PVOID *)NULL, 00147 &Handle 00148 ); 00149 } 00150 00151 // 00152 // If the job object was successfully inserted in the current 00153 // process' handle table, then attempt to write the job object 00154 // handle value. If the write attempt fails, then do not report 00155 // an error. When the caller attempts to access the handle value, 00156 // an access violation will occur. 00157 // 00158 00159 if (NT_SUCCESS(Status)) { 00160 try { 00161 *JobHandle = Handle; 00162 } 00163 except(ExSystemExceptionFilter()) { 00164 } 00165 } 00166 } 00167 00168 // 00169 // If an exception occurs during the probe of the output handle address, 00170 // then always handle the exception and return the exception code as the 00171 // status value. 00172 // 00173 00174 } 00175 except(ExSystemExceptionFilter()) { 00176 return GetExceptionCode(); 00177 } 00178 00179 // 00180 // Return service status. 00181 // 00182 00183 return Status; 00184 }

NTSTATUS NTAPI NtOpenJobObject OUT PHANDLE  JobHandle,
IN ACCESS_MASK  DesiredAccess,
IN POBJECT_ATTRIBUTES  ObjectAttributes
 

Definition at line 188 of file psjob.c.

References ExSystemExceptionFilter(), Handle, KernelMode, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObjectAttributes, ObOpenObjectByName(), PAGED_CODE, ProbeForWriteHandle, PsJobType, and Status.

00193 { 00194 HANDLE Handle; 00195 KPROCESSOR_MODE PreviousMode; 00196 NTSTATUS Status; 00197 00198 PAGED_CODE(); 00199 00200 // 00201 // Establish an exception handler, probe the output handle address, and 00202 // attempt to open the job object. If the probe fails, then return the 00203 // exception code as the service status. Otherwise return the status value 00204 // returned by the object open routine. 00205 // 00206 00207 try { 00208 00209 // 00210 // Get previous processor mode and probe output handle address 00211 // if necessary. 00212 // 00213 00214 PreviousMode = KeGetPreviousMode(); 00215 if (PreviousMode != KernelMode) { 00216 ProbeForWriteHandle(JobHandle); 00217 } 00218 00219 // 00220 // Open handle to the event object with the specified desired access. 00221 // 00222 00223 Status = ObOpenObjectByName( 00224 ObjectAttributes, 00225 PsJobType, 00226 PreviousMode, 00227 NULL, 00228 DesiredAccess, 00229 NULL, 00230 &Handle 00231 ); 00232 00233 // 00234 // If the open was successful, then attempt to write the job object 00235 // handle value. If the write attempt fails, then do not report an 00236 // error. When the caller attempts to access the handle value, an 00237 // access violation will occur. 00238 // 00239 00240 if (NT_SUCCESS(Status)) { 00241 try { 00242 *JobHandle = Handle; 00243 } 00244 except(ExSystemExceptionFilter()) { 00245 } 00246 } 00247 00248 } 00249 00250 except(ExSystemExceptionFilter()) { 00251 00252 // 00253 // If an exception occurs during the probe of the output job handle, 00254 // then always handle the exception and return the exception code as the 00255 // status value. 00256 // 00257 00258 Status = GetExceptionCode(); 00259 } 00260 00261 return Status; 00262 }

NTSTATUS NtQueryInformationJobObject IN HANDLE  JobHandle,
IN JOBOBJECTINFOCLASS  JobObjectInformationClass,
OUT PVOID  JobObjectInformation,
IN ULONG  JobObjectInformationLength,
OUT PULONG ReturnLength  OPTIONAL
 

Definition at line 814 of file psjob.c.

References _EJOB::ActiveProcesses, _EJOB::ActiveProcessLimit, _EJOB::Affinity, _PS_JOB_TOKEN_FILTER::CapturedGroupCount, _PS_JOB_TOKEN_FILTER::CapturedGroups, _PS_JOB_TOKEN_FILTER::CapturedGroupsLength, _PS_JOB_TOKEN_FILTER::CapturedPrivilegeCount, _PS_JOB_TOKEN_FILTER::CapturedPrivileges, _PS_JOB_TOKEN_FILTER::CapturedPrivilegesLength, _PS_JOB_TOKEN_FILTER::CapturedSidCount, _PS_JOB_TOKEN_FILTER::CapturedSids, _PS_JOB_TOKEN_FILTER::CapturedSidsLength, ExAcquireFastMutexUnsafe(), ExAcquireResourceShared, EXCEPTION_EXECUTE_HANDLER, ExReleaseFastMutexUnsafe(), ExReleaseResource, ExSystemExceptionFilter(), FALSE, _EJOB::Filter, _EPROCESS::Job, _EJOB::JobLock, _EJOB::JobMemoryLimit, _EPROCESS::JobStatus, KeEnterCriticalRegion, KeLeaveCriticalRegion, KeMaximumIncrement, KernelMode, _KPROCESS::KernelTime, KPROCESSOR_MODE, _EJOB::LimitFlags, _EJOB::MaximumWorkingSetSize, _EJOB::MemoryLimitsLock, _EJOB::MinimumWorkingSetSize, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObject, ObReferenceObjectByHandle(), _EPROCESS::OtherOperationCount, _EJOB::OtherOperationCount, _EPROCESS::OtherTransferCount, _EJOB::OtherTransferCount, PAGE_SHIFT, PAGED_CODE, _MMSUPPORT::PageFaultCount, _EPROCESS::Pcb, _EJOB::PeakJobMemoryUsed, _EJOB::PeakProcessMemoryUsed, _EJOB::PerJobUserTimeLimit, _EJOB::PerProcessUserTimeLimit, _EJOB::PriorityClass, ProbeForWrite(), ProbeForWriteUlong, _EJOB::ProcessListHead, _EJOB::ProcessMemoryLimit, PS_JOB_STATUS_ACCOUNTING_FOLDED, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PsGetCurrentProcess, PsJobType, PspJobInfoAlign, PspJobInfoLengths, _EPROCESS::ReadOperationCount, _EJOB::ReadOperationCount, _EPROCESS::ReadTransferCount, _EJOB::ReadTransferCount, RtlCopySidAndAttributesArray(), _EJOB::SchedulingClass, _EJOB::SecurityLimitFlags, _EJOB::ThisPeriodTotalKernelTime, _EJOB::ThisPeriodTotalUserTime, _EJOB::TotalKernelTime, _EJOB::TotalPageFaultCount, _EJOB::TotalProcesses, _EJOB::TotalTerminatedProcesses, _EJOB::TotalUserTime, TRUE, _EJOB::UIRestrictionsClass, _EPROCESS::UniqueProcessId, _KPROCESS::UserTime, _EPROCESS::Vm, _EPROCESS::WriteOperationCount, _EJOB::WriteOperationCount, _EPROCESS::WriteTransferCount, and _EJOB::WriteTransferCount.

00821 { 00822 PEJOB Job; 00823 KPROCESSOR_MODE PreviousMode; 00824 JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION AccountingInfo; 00825 JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInfo; 00826 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimitInfo; 00827 JOBOBJECT_BASIC_UI_RESTRICTIONS BasicUIRestrictions; 00828 JOBOBJECT_SECURITY_LIMIT_INFORMATION SecurityLimitInfo ; 00829 NTSTATUS st; 00830 ULONG RequiredLength, RequiredAlign, ActualReturnLength; 00831 PVOID ReturnData; 00832 PEPROCESS Process; 00833 PLIST_ENTRY Next; 00834 LARGE_INTEGER UserTime, KernelTime; 00835 PULONG_PTR NextProcessIdSlot; 00836 ULONG WorkingLength; 00837 PJOBOBJECT_BASIC_PROCESS_ID_LIST IdList; 00838 PUCHAR CurrentOffset ; 00839 PTOKEN_GROUPS WorkingGroup ; 00840 PTOKEN_PRIVILEGES WorkingPrivs ; 00841 ULONG RemainingSidBuffer ; 00842 PSID TargetSidBuffer ; 00843 PSID RemainingSid ; 00844 BOOLEAN AlreadyCopied ; 00845 00846 PAGED_CODE(); 00847 00848 // 00849 // Get previous processor mode and probe output argument if necessary. 00850 // 00851 00852 if ( JobObjectInformationClass >= MaxJobObjectInfoClass || JobObjectInformationClass <= 0) { 00853 return STATUS_INVALID_INFO_CLASS; 00854 } 00855 00856 RequiredLength = PspJobInfoLengths[JobObjectInformationClass-1]; 00857 RequiredAlign = PspJobInfoAlign[JobObjectInformationClass-1]; 00858 ActualReturnLength = RequiredLength; 00859 00860 if ( JobObjectInformationLength != RequiredLength ) { 00861 00862 // 00863 // BasicProcessIdList is variable length, so make sure header is 00864 // ok. Can not enforce an exact match ! Security Limits can be 00865 // as well, due to the token groups and privs 00866 // 00867 if ( ( JobObjectInformationClass == JobObjectBasicProcessIdList ) || 00868 ( JobObjectInformationClass == JobObjectSecurityLimitInformation ) ) { 00869 if ( JobObjectInformationLength < RequiredLength ) { 00870 return STATUS_INFO_LENGTH_MISMATCH; 00871 } 00872 else { 00873 RequiredLength = JobObjectInformationLength; 00874 } 00875 } 00876 else { 00877 return STATUS_INFO_LENGTH_MISMATCH; 00878 } 00879 } 00880 00881 00882 PreviousMode = KeGetPreviousMode(); 00883 if (PreviousMode != KernelMode) { 00884 try { 00885 ProbeForWrite( 00886 JobObjectInformation, 00887 JobObjectInformationLength, 00888 RequiredAlign 00889 ); 00890 if (ARGUMENT_PRESENT(ReturnLength)) { 00891 ProbeForWriteUlong(ReturnLength); 00892 } 00893 } 00894 except(EXCEPTION_EXECUTE_HANDLER) { 00895 return GetExceptionCode(); 00896 } 00897 } 00898 00899 // 00900 // reference the job 00901 // 00902 00903 if ( ARGUMENT_PRESENT(JobHandle) ) { 00904 st = ObReferenceObjectByHandle( 00905 JobHandle, 00906 JOB_OBJECT_QUERY, 00907 PsJobType, 00908 PreviousMode, 00909 (PVOID *)&Job, 00910 NULL 00911 ); 00912 if ( !NT_SUCCESS(st) ) { 00913 return st; 00914 } 00915 } 00916 else { 00917 00918 // 00919 // if the current process has a job, NULL means the job of the 00920 // current process. Query is always allowed for this case 00921 // 00922 00923 Process = PsGetCurrentProcess(); 00924 00925 if ( Process->Job ) { 00926 Job = Process->Job; 00927 ObReferenceObject(Job); 00928 } 00929 else { 00930 return STATUS_ACCESS_DENIED; 00931 } 00932 } 00933 00934 AlreadyCopied = FALSE ; 00935 00936 KeEnterCriticalRegion(); 00937 ExAcquireResourceShared(&Job->JobLock, TRUE); 00938 00939 // 00940 // Check argument validity. 00941 // 00942 00943 switch ( JobObjectInformationClass ) { 00944 00945 case JobObjectBasicAccountingInformation: 00946 case JobObjectBasicAndIoAccountingInformation: 00947 00948 // 00949 // These two cases are identical, EXCEPT that with AndIo, IO information 00950 // is returned as well, but the first part of the local is identical to 00951 // basic, and the shorter return'd data length chops what we return. 00952 // 00953 00954 RtlZeroMemory(&AccountingInfo.IoInfo,sizeof(AccountingInfo.IoInfo)); 00955 00956 AccountingInfo.BasicInfo.TotalUserTime = Job->TotalUserTime; 00957 AccountingInfo.BasicInfo.TotalKernelTime = Job->TotalKernelTime; 00958 AccountingInfo.BasicInfo.ThisPeriodTotalUserTime = Job->ThisPeriodTotalUserTime; 00959 AccountingInfo.BasicInfo.ThisPeriodTotalKernelTime = Job->ThisPeriodTotalKernelTime; 00960 AccountingInfo.BasicInfo.TotalPageFaultCount = Job->TotalPageFaultCount; 00961 00962 AccountingInfo.BasicInfo.TotalProcesses = Job->TotalProcesses; 00963 AccountingInfo.BasicInfo.ActiveProcesses = Job->ActiveProcesses; 00964 AccountingInfo.BasicInfo.TotalTerminatedProcesses = Job->TotalTerminatedProcesses; 00965 00966 AccountingInfo.IoInfo.ReadOperationCount = Job->ReadOperationCount; 00967 AccountingInfo.IoInfo.WriteOperationCount = Job->WriteOperationCount; 00968 AccountingInfo.IoInfo.OtherOperationCount = Job->OtherOperationCount; 00969 AccountingInfo.IoInfo.ReadTransferCount = Job->ReadTransferCount; 00970 AccountingInfo.IoInfo.WriteTransferCount = Job->WriteTransferCount; 00971 AccountingInfo.IoInfo.OtherTransferCount = Job->OtherTransferCount; 00972 00973 // 00974 // Add in the time and page faults for each process 00975 // 00976 00977 Next = Job->ProcessListHead.Flink; 00978 00979 while ( Next != &Job->ProcessListHead) { 00980 00981 Process = (PEPROCESS)(CONTAINING_RECORD(Next,EPROCESS,JobLinks)); 00982 if ( !(Process->JobStatus & PS_JOB_STATUS_ACCOUNTING_FOLDED) ) { 00983 00984 UserTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,KeMaximumIncrement); 00985 KernelTime.QuadPart = UInt32x32To64(Process->Pcb.KernelTime,KeMaximumIncrement); 00986 00987 AccountingInfo.BasicInfo.TotalUserTime.QuadPart += UserTime.QuadPart; 00988 AccountingInfo.BasicInfo.TotalKernelTime.QuadPart += KernelTime.QuadPart; 00989 AccountingInfo.BasicInfo.ThisPeriodTotalUserTime.QuadPart += UserTime.QuadPart; 00990 AccountingInfo.BasicInfo.ThisPeriodTotalKernelTime.QuadPart += KernelTime.QuadPart; 00991 AccountingInfo.BasicInfo.TotalPageFaultCount += Process->Vm.PageFaultCount; 00992 00993 AccountingInfo.IoInfo.ReadOperationCount += Process->ReadOperationCount.QuadPart; 00994 AccountingInfo.IoInfo.WriteOperationCount += Process->WriteOperationCount.QuadPart; 00995 AccountingInfo.IoInfo.OtherOperationCount += Process->OtherOperationCount.QuadPart; 00996 AccountingInfo.IoInfo.ReadTransferCount += Process->ReadTransferCount.QuadPart; 00997 AccountingInfo.IoInfo.WriteTransferCount += Process->WriteTransferCount.QuadPart; 00998 AccountingInfo.IoInfo.OtherTransferCount += Process->OtherTransferCount.QuadPart; 00999 } 01000 Next = Next->Flink; 01001 } 01002 01003 ReturnData = &AccountingInfo; 01004 st = STATUS_SUCCESS; 01005 01006 break; 01007 01008 case JobObjectExtendedLimitInformation: 01009 case JobObjectBasicLimitInformation: 01010 01011 // 01012 // Get the Basic Information 01013 // 01014 ExtendedLimitInfo.BasicLimitInformation.LimitFlags = Job->LimitFlags; 01015 ExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize = Job->MinimumWorkingSetSize; 01016 ExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize = Job->MaximumWorkingSetSize; 01017 ExtendedLimitInfo.BasicLimitInformation.ActiveProcessLimit = Job->ActiveProcessLimit; 01018 ExtendedLimitInfo.BasicLimitInformation.PriorityClass = (ULONG)Job->PriorityClass; 01019 ExtendedLimitInfo.BasicLimitInformation.SchedulingClass = Job->SchedulingClass; 01020 ExtendedLimitInfo.BasicLimitInformation.Affinity = (ULONG_PTR)Job->Affinity; 01021 ExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart = Job->PerProcessUserTimeLimit.QuadPart; 01022 ExtendedLimitInfo.BasicLimitInformation.PerJobUserTimeLimit.QuadPart = Job->PerJobUserTimeLimit.QuadPart; 01023 ReturnData = &ExtendedLimitInfo.BasicLimitInformation; 01024 01025 if ( JobObjectInformationClass == JobObjectExtendedLimitInformation ) { 01026 01027 // 01028 // Get Extended Information 01029 // 01030 01031 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 01032 01033 ExtendedLimitInfo.ProcessMemoryLimit = Job->ProcessMemoryLimit << PAGE_SHIFT; 01034 ExtendedLimitInfo.JobMemoryLimit = Job->JobMemoryLimit << PAGE_SHIFT; 01035 ExtendedLimitInfo.PeakJobMemoryUsed = Job->PeakJobMemoryUsed << PAGE_SHIFT; 01036 01037 ExtendedLimitInfo.PeakProcessMemoryUsed = Job->PeakProcessMemoryUsed << PAGE_SHIFT; 01038 01039 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 01040 01041 01042 // 01043 // Zero un-used I/O counters 01044 // 01045 RtlZeroMemory(&ExtendedLimitInfo.IoInfo,sizeof(ExtendedLimitInfo.IoInfo)); 01046 01047 ReturnData = &ExtendedLimitInfo; 01048 } 01049 01050 st = STATUS_SUCCESS; 01051 01052 break; 01053 01054 case JobObjectBasicUIRestrictions: 01055 01056 BasicUIRestrictions.UIRestrictionsClass = Job->UIRestrictionsClass; 01057 01058 ReturnData = &BasicUIRestrictions; 01059 st = STATUS_SUCCESS; 01060 01061 break; 01062 01063 case JobObjectBasicProcessIdList: 01064 01065 IdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)JobObjectInformation; 01066 NextProcessIdSlot = &IdList->ProcessIdList[0]; 01067 WorkingLength = FIELD_OFFSET(JOBOBJECT_BASIC_PROCESS_ID_LIST,ProcessIdList); 01068 01069 AlreadyCopied = TRUE ; 01070 01071 try { 01072 01073 // 01074 // Acounted for in the workinglength = 2*sizeof(ULONG) 01075 // 01076 01077 IdList->NumberOfAssignedProcesses = Job->ActiveProcesses; 01078 IdList->NumberOfProcessIdsInList = 0; 01079 01080 Next = Job->ProcessListHead.Flink; 01081 01082 while ( Next != &Job->ProcessListHead) { 01083 01084 Process = (PEPROCESS)(CONTAINING_RECORD(Next,EPROCESS,JobLinks)); 01085 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 01086 if ( !Process->UniqueProcessId ) { 01087 IdList->NumberOfAssignedProcesses--; 01088 } 01089 else { 01090 if ( (RequiredLength - WorkingLength) >= sizeof(ULONG_PTR) ) { 01091 *NextProcessIdSlot++ = (ULONG_PTR)Process->UniqueProcessId; 01092 WorkingLength += sizeof(ULONG_PTR); 01093 IdList->NumberOfProcessIdsInList++; 01094 } 01095 else { 01096 st = STATUS_BUFFER_OVERFLOW; 01097 ActualReturnLength = WorkingLength; 01098 break; 01099 } 01100 } 01101 } 01102 Next = Next->Flink; 01103 } 01104 ActualReturnLength = WorkingLength; 01105 01106 } 01107 except ( ExSystemExceptionFilter() ) { 01108 st = GetExceptionCode(); 01109 ActualReturnLength = 0; 01110 } 01111 01112 break; 01113 01114 case JobObjectSecurityLimitInformation: 01115 01116 RtlZeroMemory( &SecurityLimitInfo, sizeof( SecurityLimitInfo ) ); 01117 01118 SecurityLimitInfo.SecurityLimitFlags = Job->SecurityLimitFlags ; 01119 01120 ReturnData = &SecurityLimitInfo; 01121 01122 st = STATUS_SUCCESS; 01123 01124 // 01125 // If a filter is present, then we have an ugly marshalling to do. 01126 // 01127 01128 if ( Job->Filter ) 01129 { 01130 01131 // 01132 // Compute size needed: 01133 // 01134 01135 WorkingLength = Job->Filter->CapturedSidsLength + 01136 Job->Filter->CapturedGroupsLength + 01137 Job->Filter->CapturedPrivilegesLength ; 01138 01139 WorkingLength = 0 ; 01140 01141 // 01142 // For each field, if it is present, include the extra stuff 01143 // 01144 01145 if ( Job->Filter->CapturedSidsLength ) 01146 { 01147 WorkingLength += Job->Filter->CapturedSidsLength + 01148 sizeof( ULONG ); 01149 } 01150 01151 if ( Job->Filter->CapturedGroupsLength ) 01152 { 01153 WorkingLength += Job->Filter->CapturedGroupsLength + 01154 sizeof( ULONG ); 01155 01156 } 01157 01158 if ( Job->Filter->CapturedPrivilegesLength ) 01159 { 01160 WorkingLength += Job->Filter->CapturedPrivilegesLength + 01161 sizeof( ULONG ); 01162 } 01163 01164 RequiredLength -= sizeof( SecurityLimitInfo ); 01165 01166 if ( WorkingLength > RequiredLength ) 01167 { 01168 st = STATUS_BUFFER_OVERFLOW ; 01169 ActualReturnLength = WorkingLength + sizeof( SecurityLimitInfo ); 01170 break; 01171 } 01172 01173 CurrentOffset = (PUCHAR) (JobObjectInformation) + sizeof( SecurityLimitInfo ); 01174 01175 try { 01176 01177 // 01178 // 01179 // 01180 01181 if ( Job->Filter->CapturedSidsLength ) 01182 { 01183 WorkingGroup = (PTOKEN_GROUPS) CurrentOffset ; 01184 01185 CurrentOffset += sizeof( ULONG ); 01186 01187 SecurityLimitInfo.RestrictedSids = WorkingGroup ; 01188 01189 WorkingGroup->GroupCount = Job->Filter->CapturedSidCount ; 01190 01191 TargetSidBuffer = (PSID) (CurrentOffset + 01192 sizeof( SID_AND_ATTRIBUTES ) * 01193 Job->Filter->CapturedSidCount ); 01194 01195 st = RtlCopySidAndAttributesArray( 01196 Job->Filter->CapturedSidCount, 01197 Job->Filter->CapturedSids, 01198 WorkingLength, 01199 WorkingGroup->Groups, 01200 TargetSidBuffer, 01201 &RemainingSid, 01202 &RemainingSidBuffer ); 01203 01204 CurrentOffset += Job->Filter->CapturedSidsLength ; 01205 01206 } 01207 01208 if ( !NT_SUCCESS( st ) ) 01209 { 01210 leave ; 01211 } 01212 01213 if ( Job->Filter->CapturedGroupsLength ) 01214 { 01215 WorkingGroup = (PTOKEN_GROUPS) CurrentOffset ; 01216 01217 CurrentOffset += sizeof( ULONG ); 01218 01219 SecurityLimitInfo.SidsToDisable = WorkingGroup ; 01220 01221 WorkingGroup->GroupCount = Job->Filter->CapturedGroupCount ; 01222 01223 TargetSidBuffer = (PSID) (CurrentOffset + 01224 sizeof( SID_AND_ATTRIBUTES ) * 01225 Job->Filter->CapturedGroupCount ); 01226 01227 st = RtlCopySidAndAttributesArray( 01228 Job->Filter->CapturedGroupCount, 01229 Job->Filter->CapturedGroups, 01230 WorkingLength, 01231 WorkingGroup->Groups, 01232 TargetSidBuffer, 01233 &RemainingSid, 01234 &RemainingSidBuffer ); 01235 01236 CurrentOffset += Job->Filter->CapturedGroupsLength ; 01237 01238 } 01239 01240 if ( !NT_SUCCESS( st ) ) 01241 { 01242 leave ; 01243 } 01244 01245 if ( Job->Filter->CapturedPrivilegesLength ) 01246 { 01247 WorkingPrivs = (PTOKEN_PRIVILEGES) CurrentOffset; 01248 01249 CurrentOffset += sizeof( ULONG ); 01250 01251 SecurityLimitInfo.PrivilegesToDelete = WorkingPrivs ; 01252 01253 WorkingPrivs->PrivilegeCount = Job->Filter->CapturedPrivilegeCount ; 01254 01255 RtlCopyMemory( WorkingPrivs->Privileges, 01256 Job->Filter->CapturedPrivileges, 01257 Job->Filter->CapturedPrivilegesLength ); 01258 01259 } 01260 01261 AlreadyCopied = TRUE ; 01262 01263 RtlCopyMemory( JobObjectInformation, 01264 &SecurityLimitInfo, 01265 sizeof( SecurityLimitInfo ) ); 01266 01267 01268 } 01269 except (EXCEPTION_EXECUTE_HANDLER) { 01270 st = GetExceptionCode(); 01271 ActualReturnLength = 0 ; 01272 break; 01273 } 01274 01275 } 01276 01277 01278 break; 01279 01280 default: 01281 01282 st = STATUS_INVALID_INFO_CLASS; 01283 } 01284 01285 ExReleaseResource(&Job->JobLock); 01286 KeLeaveCriticalRegion(); 01287 01288 01289 // 01290 // Finish Up 01291 // 01292 01293 ObDereferenceObject(Job); 01294 01295 01296 if ( NT_SUCCESS(st) ) { 01297 01298 // 01299 // Either of these may cause an access violation. The 01300 // exception handler will return access violation as 01301 // status code. No further cleanup needs to be done. 01302 // 01303 01304 try { 01305 if ( !AlreadyCopied ) { 01306 RtlCopyMemory(JobObjectInformation,ReturnData,RequiredLength); 01307 } 01308 01309 if (ARGUMENT_PRESENT(ReturnLength) ) { 01310 *ReturnLength = ActualReturnLength; 01311 } 01312 } 01313 except(EXCEPTION_EXECUTE_HANDLER) { 01314 return STATUS_SUCCESS; 01315 } 01316 } 01317 01318 return st; 01319 01320 }

NTSTATUS NtSetInformationJobObject IN HANDLE  JobHandle,
IN JOBOBJECTINFOCLASS  JobObjectInformationClass,
IN PVOID  JobObjectInformation,
IN ULONG  JobObjectInformationLength
 

Definition at line 1323 of file psjob.c.

References _EJOB::ActiveProcessLimit, _EJOB::Affinity, _WIN32_JOBCALLOUT_PARAMETERS::CalloutType, _WIN32_JOBCALLOUT_PARAMETERS::Data, ExAcquireFastMutexUnsafe(), ExAcquireResourceExclusive, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), ExReleaseFastMutexUnsafe(), ExReleaseResource, FALSE, Filter, IoCompletionObjectType, IoSetIoCompletion(), IsChild(), _WIN32_JOBCALLOUT_PARAMETERS::Job, JOB_WORKING_SET_CHANGE_RECORD, _EJOB::JobMemoryLimit, _EPROCESS::JobStatus, KeActiveProcessors, KeAttachProcess(), KeClearEvent, KeDetachProcess(), KeEnterCriticalRegion, KeLeaveCriticalRegion, KeMaximumIncrement, KeReadStateProcess(), KernelMode, KPROCESSOR_MODE, _EJOB::LimitFlags, _JOB_WORKING_SET_CHANGE_HEAD::Links, _JOB_WORKING_SET_CHANGE_HEAD::Lock, _JOB_WORKING_SET_CHANGE_HEAD::MaximumWorkingSetSize, _EJOB::MaximumWorkingSetSize, _JOB_WORKING_SET_CHANGE_HEAD::MinimumWorkingSetSize, _EJOB::MinimumWorkingSetSize, MmAdjustWorkingSetSize(), MmDispatchWin32Callout(), MmEnforceWorkingSetLimit(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGE_SHIFT, PAGE_SIZE, PAGED_CODE, _EPROCESS::Pcb, _EJOB::PerJobUserTimeLimit, _EJOB::PerProcessUserTimeLimit, PJOB_WORKING_SET_CHANGE_RECORD, _EJOB::PriorityClass, ProbeForRead, _JOB_WORKING_SET_CHANGE_RECORD::Process, _EJOB::ProcessMemoryLimit, PS_JOB_STATUS_ACCOUNTING_FOLDED, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NEW_PROCESS_REPORTED, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_CLEAR_BITS, PsJobType, PSP_DEFAULT_SCHEDULING_CLASSES, PSP_NUMBER_OF_SCHEDULING_CLASSES, PspApplyJobLimitsToProcessSet(), PspCaptureTokenFilter(), PspFoldProcessAccountingIntoJob(), PspJobInfoAlign, PspJobInfoLengths, PspW32JobCallout, PspWorkingSetChangeHead, PsW32JobCalloutSetInformation, _EJOB::SchedulingClass, SeAssignPrimaryTokenPrivilege, SeCheckPrivilegedObject(), SeIncreaseBasePriorityPrivilege, SeIsChildTokenByPointer(), SeTokenIsAdmin(), SeTokenObjectType, TRUE, _EPROCESS::UniqueProcessId, _KPROCESS::UserTime, and _EPROCESS::Vm.

01329 { 01330 PEJOB Job; 01331 EJOB LocalJob; 01332 KPROCESSOR_MODE PreviousMode; 01333 NTSTATUS st; 01334 JOBOBJECT_EXTENDED_LIMIT_INFORMATION ExtendedLimitInfo; 01335 JOBOBJECT_BASIC_UI_RESTRICTIONS BasicUIRestrictions; 01336 JOBOBJECT_SECURITY_LIMIT_INFORMATION SecurityLimitInfo ; 01337 JOBOBJECT_END_OF_JOB_TIME_INFORMATION EndOfJobInfo; 01338 JOBOBJECT_ASSOCIATE_COMPLETION_PORT AssociateInfo; 01339 ULONG RequiredAccess ; 01340 ULONG RequiredLength, RequiredAlign; 01341 PEPROCESS Process; 01342 BOOLEAN HasPrivilege; 01343 BOOLEAN IsChild ; 01344 PLIST_ENTRY Next; 01345 PPS_JOB_TOKEN_FILTER Filter ; 01346 PVOID IoCompletion; 01347 PACCESS_TOKEN LocalToken ; 01348 ULONG ValidFlags; 01349 ULONG LimitFlags; 01350 BOOLEAN ProcessWorkingSetHead = FALSE; 01351 PJOB_WORKING_SET_CHANGE_RECORD WsChangeRecord; 01352 01353 01354 PAGED_CODE(); 01355 01356 // 01357 // Get previous processor mode and probe output argument if necessary. 01358 // 01359 01360 if ( JobObjectInformationClass >= MaxJobObjectInfoClass || JobObjectInformationClass <= 0) { 01361 return STATUS_INVALID_INFO_CLASS; 01362 } 01363 RequiredLength = PspJobInfoLengths[JobObjectInformationClass-1]; 01364 RequiredAlign = PspJobInfoAlign[JobObjectInformationClass-1]; 01365 01366 PreviousMode = KeGetPreviousMode(); 01367 if (PreviousMode != KernelMode) { 01368 try { 01369 ProbeForRead( 01370 JobObjectInformation, 01371 JobObjectInformationLength, 01372 RequiredAlign 01373 ); 01374 } 01375 except(EXCEPTION_EXECUTE_HANDLER) { 01376 return GetExceptionCode(); 01377 } 01378 } 01379 01380 if ( JobObjectInformationLength != RequiredLength ) { 01381 return STATUS_INFO_LENGTH_MISMATCH; 01382 } 01383 01384 // 01385 // reference the job 01386 // 01387 01388 if ( JobObjectInformationClass == JobObjectSecurityLimitInformation ) 01389 { 01390 RequiredAccess = JOB_OBJECT_SET_SECURITY_ATTRIBUTES ; 01391 } 01392 else 01393 { 01394 RequiredAccess = JOB_OBJECT_SET_ATTRIBUTES ; 01395 } 01396 01397 st = ObReferenceObjectByHandle( 01398 JobHandle, 01399 RequiredAccess, 01400 PsJobType, 01401 PreviousMode, 01402 (PVOID *)&Job, 01403 NULL 01404 ); 01405 if ( !NT_SUCCESS(st) ) { 01406 return st; 01407 } 01408 01409 KeEnterCriticalRegion(); 01410 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 01411 01412 // 01413 // Check argument validity. 01414 // 01415 01416 switch ( JobObjectInformationClass ) { 01417 01418 case JobObjectExtendedLimitInformation: 01419 case JobObjectBasicLimitInformation: 01420 try { 01421 RtlCopyMemory(&ExtendedLimitInfo,JobObjectInformation,RequiredLength); 01422 } 01423 except(EXCEPTION_EXECUTE_HANDLER) { 01424 st = GetExceptionCode(); 01425 } 01426 if ( NT_SUCCESS(st) ) { 01427 // 01428 // sanity check LimitFlags 01429 // 01430 if ( JobObjectInformationClass == JobObjectBasicLimitInformation) { 01431 ValidFlags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS; 01432 } 01433 else { 01434 ValidFlags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS; 01435 } 01436 01437 if ( ExtendedLimitInfo.BasicLimitInformation.LimitFlags & ~ValidFlags ) { 01438 st = STATUS_INVALID_PARAMETER; 01439 } 01440 else { 01441 01442 LimitFlags = ExtendedLimitInfo.BasicLimitInformation.LimitFlags; 01443 01444 // 01445 // Deal with each of the various limit flags 01446 // 01447 01448 LocalJob.LimitFlags = Job->LimitFlags; 01449 01450 01451 // 01452 // ACTIVE PROCESS LIMIT 01453 // 01454 if ( LimitFlags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS ) { 01455 01456 // 01457 // Active Process Limit is NOT retroactive. New processes are denied, 01458 // but existing ones are not killed just because the limit is 01459 // reduced. 01460 // 01461 01462 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS; 01463 LocalJob.ActiveProcessLimit = ExtendedLimitInfo.BasicLimitInformation.ActiveProcessLimit; 01464 } 01465 else { 01466 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_ACTIVE_PROCESS; 01467 LocalJob.ActiveProcessLimit = 0; 01468 } 01469 01470 // 01471 // PRIORITY CLASS LIMIT 01472 // 01473 if ( LimitFlags & JOB_OBJECT_LIMIT_PRIORITY_CLASS ) { 01474 01475 if ( ExtendedLimitInfo.BasicLimitInformation.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL ) { 01476 st = STATUS_INVALID_PARAMETER; 01477 } 01478 else { 01479 if ( ExtendedLimitInfo.BasicLimitInformation.PriorityClass == PROCESS_PRIORITY_CLASS_HIGH || 01480 ExtendedLimitInfo.BasicLimitInformation.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME ) { 01481 01482 // 01483 // Increasing the base priority of a process is a 01484 // privileged operation. Check for the privilege 01485 // here. 01486 // 01487 01488 HasPrivilege = SeCheckPrivilegedObject( 01489 SeIncreaseBasePriorityPrivilege, 01490 JobHandle, 01491 JOB_OBJECT_SET_ATTRIBUTES, 01492 PreviousMode 01493 ); 01494 01495 if (!HasPrivilege) { 01496 st = STATUS_PRIVILEGE_NOT_HELD; 01497 } 01498 } 01499 01500 if ( NT_SUCCESS(st) ) { 01501 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; 01502 LocalJob.PriorityClass = (UCHAR)ExtendedLimitInfo.BasicLimitInformation.PriorityClass; 01503 } 01504 } 01505 } 01506 else { 01507 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_PRIORITY_CLASS; 01508 LocalJob.PriorityClass = 0; 01509 } 01510 01511 // 01512 // SCHEDULING CLASS LIMIT 01513 // 01514 if ( LimitFlags & JOB_OBJECT_LIMIT_SCHEDULING_CLASS ) { 01515 01516 if ( ExtendedLimitInfo.BasicLimitInformation.SchedulingClass >= PSP_NUMBER_OF_SCHEDULING_CLASSES) { 01517 st = STATUS_INVALID_PARAMETER; 01518 } 01519 else { 01520 if ( ExtendedLimitInfo.BasicLimitInformation.SchedulingClass > PSP_DEFAULT_SCHEDULING_CLASSES ) { 01521 01522 // 01523 // Increasing above the default scheduling class 01524 // is a 01525 // privileged operation. Check for the privilege 01526 // here. 01527 // 01528 01529 HasPrivilege = SeCheckPrivilegedObject( 01530 SeIncreaseBasePriorityPrivilege, 01531 JobHandle, 01532 JOB_OBJECT_SET_ATTRIBUTES, 01533 PreviousMode 01534 ); 01535 01536 if (!HasPrivilege) { 01537 st = STATUS_PRIVILEGE_NOT_HELD; 01538 } 01539 } 01540 01541 if ( NT_SUCCESS(st) ) { 01542 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_SCHEDULING_CLASS; 01543 LocalJob.SchedulingClass = ExtendedLimitInfo.BasicLimitInformation.SchedulingClass; 01544 } 01545 } 01546 } 01547 else { 01548 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_SCHEDULING_CLASS; 01549 LocalJob.SchedulingClass = PSP_DEFAULT_SCHEDULING_CLASSES ; 01550 } 01551 01552 // 01553 // AFFINITY LIMIT 01554 // 01555 if ( LimitFlags & JOB_OBJECT_LIMIT_AFFINITY ) { 01556 01557 if ( !ExtendedLimitInfo.BasicLimitInformation.Affinity || 01558 (ExtendedLimitInfo.BasicLimitInformation.Affinity != (ExtendedLimitInfo.BasicLimitInformation.Affinity & KeActiveProcessors)) ) { 01559 st = STATUS_INVALID_PARAMETER; 01560 } 01561 else { 01562 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_AFFINITY; 01563 LocalJob.Affinity = (KAFFINITY)ExtendedLimitInfo.BasicLimitInformation.Affinity; 01564 } 01565 } 01566 else { 01567 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_AFFINITY; 01568 LocalJob.Affinity = 0; 01569 } 01570 01571 // 01572 // PROCESS TIME LIMIT 01573 // 01574 if ( LimitFlags & JOB_OBJECT_LIMIT_PROCESS_TIME ) { 01575 01576 if ( !ExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart ) { 01577 st = STATUS_INVALID_PARAMETER; 01578 } 01579 else { 01580 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_TIME; 01581 LocalJob.PerProcessUserTimeLimit.QuadPart = ExtendedLimitInfo.BasicLimitInformation.PerProcessUserTimeLimit.QuadPart; 01582 } 01583 } 01584 else { 01585 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_PROCESS_TIME; 01586 LocalJob.PerProcessUserTimeLimit.QuadPart = 0; 01587 } 01588 01589 // 01590 // JOB TIME LIMIT 01591 // 01592 if ( LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME ) { 01593 01594 if ( !ExtendedLimitInfo.BasicLimitInformation.PerJobUserTimeLimit.QuadPart ) { 01595 st = STATUS_INVALID_PARAMETER; 01596 } 01597 else { 01598 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_JOB_TIME; 01599 LocalJob.PerJobUserTimeLimit.QuadPart = ExtendedLimitInfo.BasicLimitInformation.PerJobUserTimeLimit.QuadPart; 01600 } 01601 } 01602 else { 01603 if ( LimitFlags & JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME ) { 01604 01605 // 01606 // If we are supposed to preserve existing job time limits, then 01607 // preserve them ! 01608 // 01609 01610 LocalJob.LimitFlags |= (Job->LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME); 01611 LocalJob.PerJobUserTimeLimit.QuadPart = Job->PerJobUserTimeLimit.QuadPart; 01612 } 01613 else { 01614 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_JOB_TIME; 01615 LocalJob.PerJobUserTimeLimit.QuadPart = 0; 01616 } 01617 } 01618 01619 // 01620 // WORKING SET LIMIT 01621 // 01622 if ( LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET ) { 01623 01624 01625 // 01626 // the only issue with this check is that when we enforce through the 01627 // processes, we may find a process that can not handle the new working set 01628 // limit because it will make the process's working set not fluid 01629 // 01630 01631 if ( (ExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize == 0 && 01632 ExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize == 0) || 01633 01634 (ExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize == (SIZE_T)-1 && 01635 ExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize == (SIZE_T)-1) || 01636 01637 (ExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize > 01638 ExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize) ) { 01639 01640 01641 st = STATUS_INVALID_PARAMETER; 01642 } 01643 else { 01644 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_WORKINGSET; 01645 LocalJob.MinimumWorkingSetSize = ExtendedLimitInfo.BasicLimitInformation.MinimumWorkingSetSize; 01646 LocalJob.MaximumWorkingSetSize = ExtendedLimitInfo.BasicLimitInformation.MaximumWorkingSetSize; 01647 } 01648 } 01649 else { 01650 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_WORKINGSET; 01651 LocalJob.MinimumWorkingSetSize = 0; 01652 LocalJob.MaximumWorkingSetSize = 0; 01653 } 01654 01655 if ( JobObjectInformationClass == JobObjectExtendedLimitInformation) { 01656 // 01657 // PROCESS MEMORY LIMIT 01658 // 01659 if ( LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY ) { 01660 if ( ExtendedLimitInfo.ProcessMemoryLimit < PAGE_SIZE ) { 01661 st = STATUS_INVALID_PARAMETER; 01662 } 01663 else { 01664 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_PROCESS_MEMORY; 01665 LocalJob.ProcessMemoryLimit = ExtendedLimitInfo.ProcessMemoryLimit >> PAGE_SHIFT; 01666 } 01667 } 01668 else { 01669 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_PROCESS_MEMORY; 01670 LocalJob.ProcessMemoryLimit = 0; 01671 } 01672 01673 // 01674 // JOB WIDE MEMORY LIMIT 01675 // 01676 if ( LimitFlags & JOB_OBJECT_LIMIT_JOB_MEMORY ) { 01677 if ( ExtendedLimitInfo.JobMemoryLimit < PAGE_SIZE ) { 01678 st = STATUS_INVALID_PARAMETER; 01679 } 01680 else { 01681 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_JOB_MEMORY; 01682 LocalJob.JobMemoryLimit = ExtendedLimitInfo.JobMemoryLimit >> PAGE_SHIFT; 01683 } 01684 } 01685 else { 01686 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_JOB_MEMORY; 01687 LocalJob.JobMemoryLimit = 0; 01688 } 01689 01690 // 01691 // JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 01692 // 01693 if ( LimitFlags & JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION ) { 01694 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; 01695 } 01696 else { 01697 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION; 01698 } 01699 01700 // 01701 // JOB_OBJECT_LIMIT_BREAKAWAY_OK 01702 // 01703 if ( LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK ) { 01704 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK; 01705 } 01706 else { 01707 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_BREAKAWAY_OK; 01708 } 01709 01710 // 01711 // JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 01712 // 01713 if ( LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK ) { 01714 LocalJob.LimitFlags |= JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; 01715 } 01716 else { 01717 LocalJob.LimitFlags &= ~JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; 01718 } 01719 } 01720 01721 if ( NT_SUCCESS(st) ) { 01722 01723 01724 // 01725 // Copy LocalJob to Job 01726 // 01727 01728 Job->LimitFlags = LocalJob.LimitFlags; 01729 Job->MinimumWorkingSetSize = LocalJob.MinimumWorkingSetSize; 01730 Job->MaximumWorkingSetSize = LocalJob.MaximumWorkingSetSize; 01731 Job->ActiveProcessLimit = LocalJob.ActiveProcessLimit; 01732 Job->Affinity = LocalJob.Affinity; 01733 Job->PriorityClass = LocalJob.PriorityClass; 01734 Job->SchedulingClass = LocalJob.SchedulingClass; 01735 Job->PerProcessUserTimeLimit.QuadPart = LocalJob.PerProcessUserTimeLimit.QuadPart; 01736 Job->PerJobUserTimeLimit.QuadPart = LocalJob.PerJobUserTimeLimit.QuadPart; 01737 01738 if ( JobObjectInformationClass == JobObjectExtendedLimitInformation) { 01739 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 01740 Job->ProcessMemoryLimit = LocalJob.ProcessMemoryLimit; 01741 Job->JobMemoryLimit = LocalJob.JobMemoryLimit; 01742 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 01743 } 01744 01745 if ( LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME ) { 01746 01747 // 01748 // Take any signalled processes and fold their accounting 01749 // intothe job. This way a process that exited clean but still 01750 // is open won't impact the next period 01751 // 01752 01753 Next = Job->ProcessListHead.Flink; 01754 01755 while ( Next != &Job->ProcessListHead) { 01756 01757 Process = (PEPROCESS)(CONTAINING_RECORD(Next,EPROCESS,JobLinks)); 01758 01759 // 01760 // see if process has been signalled. 01761 // This indicates that the process has exited. We can't do 01762 // this in the exit path becuase of the lock order problem 01763 // between the process lock and the job lock since in exit 01764 // we hold the process lock for a long time and can't drop 01765 // it until thread termination 01766 // 01767 01768 if ( KeReadStateProcess(&Process->Pcb) ) { 01769 PspFoldProcessAccountingIntoJob(Job,Process); 01770 } 01771 else { 01772 01773 LARGE_INTEGER ProcessTime; 01774 01775 // 01776 // running processes have their current runtime 01777 // added to the programmed limit. This way, you 01778 // can set a limit on a job with processes in the 01779 // job and not have previous runtimes count against 01780 // the limit 01781 // 01782 01783 if ( !(Process->JobStatus & PS_JOB_STATUS_ACCOUNTING_FOLDED) ) { 01784 ProcessTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,KeMaximumIncrement); 01785 Job->PerJobUserTimeLimit.QuadPart += ProcessTime.QuadPart; 01786 } 01787 } 01788 01789 Next = Next->Flink; 01790 } 01791 01792 01793 // 01794 // clear period times and reset the job 01795 // 01796 01797 Job->ThisPeriodTotalUserTime.QuadPart = 0; 01798 Job->ThisPeriodTotalKernelTime.QuadPart = 0; 01799 01800 KeClearEvent(&Job->Event); 01801 01802 } 01803 01804 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET ) { 01805 ExAcquireFastMutexUnsafe(&PspWorkingSetChangeHead.Lock); 01806 PspWorkingSetChangeHead.MinimumWorkingSetSize = Job->MinimumWorkingSetSize; 01807 PspWorkingSetChangeHead.MaximumWorkingSetSize = Job->MaximumWorkingSetSize; 01808 ProcessWorkingSetHead = TRUE; 01809 } 01810 01811 PspApplyJobLimitsToProcessSet(Job); 01812 01813 } 01814 } 01815 01816 } 01817 break; 01818 01819 case JobObjectBasicUIRestrictions: 01820 try { 01821 RtlCopyMemory(&BasicUIRestrictions, JobObjectInformation, RequiredLength); 01822 } 01823 except(EXCEPTION_EXECUTE_HANDLER) { 01824 st = GetExceptionCode(); 01825 } 01826 01827 if ( NT_SUCCESS(st) ) { 01828 // 01829 // sanity check UIRestrictionsClass 01830 // 01831 if ( BasicUIRestrictions.UIRestrictionsClass & ~JOB_OBJECT_UI_VALID_FLAGS ) { 01832 st = STATUS_INVALID_PARAMETER; 01833 } 01834 else { 01835 01836 // 01837 // Check for switching between UI restrictions 01838 // 01839 01840 if ( Job->UIRestrictionsClass ^ BasicUIRestrictions.UIRestrictionsClass ) { 01841 01842 // 01843 // notify ntuser that the UI restrictions have changed 01844 // 01845 WIN32_JOBCALLOUT_PARAMETERS Parms; 01846 01847 Parms.Job = Job; 01848 Parms.CalloutType = PsW32JobCalloutSetInformation; 01849 Parms.Data = ULongToPtr(BasicUIRestrictions.UIRestrictionsClass); 01850 MmDispatchWin32Callout( PspW32JobCallout,NULL, (PVOID)&Parms, &(Job->SessionId) ); 01851 01852 } 01853 01854 01855 // 01856 // save the UI restrictions into the job object 01857 // 01858 01859 Job->UIRestrictionsClass = BasicUIRestrictions.UIRestrictionsClass; 01860 } 01861 } 01862 break; 01863 01864 // 01865 // SECURITY LIMITS 01866 // 01867 01868 case JobObjectSecurityLimitInformation: 01869 01870 try { 01871 RtlCopyMemory( &SecurityLimitInfo, 01872 JobObjectInformation, 01873 RequiredLength ); 01874 } 01875 except(EXCEPTION_EXECUTE_HANDLER) { 01876 st = GetExceptionCode(); 01877 } 01878 01879 if ( NT_SUCCESS(st) ) { 01880 01881 if ( SecurityLimitInfo.SecurityLimitFlags & 01882 (~JOB_OBJECT_SECURITY_VALID_FLAGS)) 01883 { 01884 st = STATUS_INVALID_PARAMETER ; 01885 } 01886 else 01887 { 01888 // 01889 // Deal with specific options. Basic rules: Once a 01890 // flag is on, it is always on (so even with a handle to 01891 // the job, a process could not lift the security 01892 // restrictions). 01893 // 01894 01895 if ( SecurityLimitInfo.SecurityLimitFlags & 01896 JOB_OBJECT_SECURITY_NO_ADMIN ) 01897 { 01898 Job->SecurityLimitFlags |= JOB_OBJECT_SECURITY_NO_ADMIN ; 01899 01900 if ( Job->Token ) 01901 { 01902 if ( SeTokenIsAdmin( Job->Token ) ) 01903 { 01904 Job->SecurityLimitFlags &= (~JOB_OBJECT_SECURITY_NO_ADMIN); 01905 01906 st = STATUS_INVALID_PARAMETER ; 01907 } 01908 } 01909 } 01910 01911 if ( SecurityLimitInfo.SecurityLimitFlags & 01912 JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ) 01913 { 01914 if ( Job->SecurityLimitFlags & 01915 ( JOB_OBJECT_SECURITY_ONLY_TOKEN | JOB_OBJECT_SECURITY_FILTER_TOKENS ) ) 01916 { 01917 st = STATUS_INVALID_PARAMETER ; 01918 } 01919 else 01920 { 01921 Job->SecurityLimitFlags |= JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ; 01922 } 01923 } 01924 01925 // 01926 // The forcible token is a little more interesting. It 01927 // cannot be reset, so if there is a pointer there already, 01928 // fail the call. If a filter is already in place, this is 01929 // not allowed, either. If no-admin is set, it is checked 01930 // at the end, once the token has been ref'd. 01931 // 01932 01933 if ( SecurityLimitInfo.SecurityLimitFlags & 01934 JOB_OBJECT_SECURITY_ONLY_TOKEN ) 01935 { 01936 if ( Job->Token || 01937 (Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_FILTER_TOKENS) ) 01938 { 01939 st = STATUS_INVALID_PARAMETER ; 01940 } 01941 else 01942 { 01943 st = ObReferenceObjectByHandle( 01944 SecurityLimitInfo.JobToken, 01945 TOKEN_ASSIGN_PRIMARY | 01946 TOKEN_IMPERSONATE | 01947 TOKEN_DUPLICATE , 01948 SeTokenObjectType(), 01949 PreviousMode, 01950 &LocalToken, 01951 NULL ); 01952 01953 if ( NT_SUCCESS( st ) ) 01954 { 01955 st = SeIsChildTokenByPointer( LocalToken, 01956 &IsChild ); 01957 01958 if ( !NT_SUCCESS( st ) ) 01959 { 01960 ObDereferenceObject( LocalToken ); 01961 } 01962 } 01963 01964 01965 if ( NT_SUCCESS( st ) ) 01966 { 01967 // 01968 // If the token supplied is not a restricted token 01969 // based on the caller's ID, then they must have 01970 // assign primary privilege in order to associate 01971 // the token with the job. 01972 // 01973 01974 if ( !IsChild ) 01975 { 01976 HasPrivilege = SeCheckPrivilegedObject( 01977 SeAssignPrimaryTokenPrivilege, 01978 JobHandle, 01979 JOB_OBJECT_SET_SECURITY_ATTRIBUTES, 01980 PreviousMode 01981 ); 01982 01983 if ( !HasPrivilege ) 01984 { 01985 st = STATUS_PRIVILEGE_NOT_HELD; 01986 } 01987 } 01988 01989 if ( NT_SUCCESS( st ) ) 01990 { 01991 // 01992 // Grab a reference to the token into the job 01993 // object 01994 // 01995 01996 Job->Token = LocalToken ; 01997 01998 // 01999 // Not surprisingly, specifying no-admin and 02000 // supplying an admin token is a no-no. 02001 // 02002 02003 if ( (Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) && 02004 SeTokenIsAdmin( Job->Token ) ) 02005 { 02006 st = STATUS_INVALID_PARAMETER ; 02007 02008 ObDereferenceObject( Job->Token ); 02009 02010 Job->Token = NULL ; 02011 } 02012 else 02013 { 02014 Job->SecurityLimitFlags |= JOB_OBJECT_SECURITY_ONLY_TOKEN ; 02015 } 02016 02017 } 02018 else 02019 { 02020 // 02021 // This is the token was a child or otherwise ok, 02022 // but assign primary was not held, so the 02023 // request was rejected. 02024 // 02025 02026 ObDereferenceObject( LocalToken ); 02027 } 02028 02029 } 02030 02031 } 02032 } 02033 if ( SecurityLimitInfo.SecurityLimitFlags & 02034 JOB_OBJECT_SECURITY_FILTER_TOKENS ) 02035 { 02036 if ( Job->SecurityLimitFlags & 02037 ( JOB_OBJECT_SECURITY_ONLY_TOKEN | 02038 JOB_OBJECT_SECURITY_FILTER_TOKENS ) ) 02039 { 02040 st = STATUS_INVALID_PARAMETER ; 02041 } 02042 else 02043 { 02044 // 02045 // capture the token restrictions 02046 // 02047 02048 st = PspCaptureTokenFilter( 02049 PreviousMode, 02050 &SecurityLimitInfo, 02051 &Filter 02052 ); 02053 02054 if ( NT_SUCCESS( st ) ) 02055 { 02056 Job->SecurityLimitFlags |= JOB_OBJECT_SECURITY_FILTER_TOKENS ; 02057 Job->Filter = Filter ; 02058 } 02059 02060 } 02061 } 02062 02063 } 02064 } 02065 break; 02066 02067 case JobObjectEndOfJobTimeInformation: 02068 02069 try { 02070 RtlCopyMemory(&EndOfJobInfo,JobObjectInformation,RequiredLength); 02071 } 02072 except(EXCEPTION_EXECUTE_HANDLER) { 02073 st = GetExceptionCode(); 02074 } 02075 02076 if ( NT_SUCCESS(st) ) { 02077 // 02078 // sanity check LimitFlags 02079 // 02080 if ( EndOfJobInfo.EndOfJobTimeAction > JOB_OBJECT_POST_AT_END_OF_JOB ) { 02081 st = STATUS_INVALID_PARAMETER; 02082 } 02083 else { 02084 Job->EndOfJobTimeAction = EndOfJobInfo.EndOfJobTimeAction; 02085 } 02086 } 02087 break; 02088 02089 case JobObjectAssociateCompletionPortInformation: 02090 02091 try { 02092 RtlCopyMemory(&AssociateInfo,JobObjectInformation,RequiredLength); 02093 } 02094 except(EXCEPTION_EXECUTE_HANDLER) { 02095 st = GetExceptionCode(); 02096 } 02097 02098 if ( NT_SUCCESS(st) ) { 02099 if ( !Job->CompletionPort && AssociateInfo.CompletionPort ) { 02100 st = ObReferenceObjectByHandle( 02101 AssociateInfo.CompletionPort, 02102 IO_COMPLETION_MODIFY_STATE, 02103 IoCompletionObjectType, 02104 PreviousMode, 02105 &IoCompletion, 02106 NULL 02107 ); 02108 02109 if (NT_SUCCESS(st)) { 02110 Job->CompletionKey = AssociateInfo.CompletionKey; 02111 Job->CompletionPort = IoCompletion; 02112 02113 // 02114 // Now whip through ALL existing processes in the job 02115 // and send notification messages 02116 // 02117 02118 Next = Job->ProcessListHead.Flink; 02119 02120 while ( Next != &Job->ProcessListHead) { 02121 02122 Process = (PEPROCESS)(CONTAINING_RECORD(Next,EPROCESS,JobLinks)); 02123 02124 02125 // 02126 // If the process is really considered part of the job, has 02127 // been assigned its id, and has not yet checked in, do it now 02128 // 02129 02130 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) 02131 && Process->UniqueProcessId 02132 && !(Process->JobStatus & PS_JOB_STATUS_NEW_PROCESS_REPORTED)) { 02133 02134 PS_SET_CLEAR_BITS (&Process->JobStatus, 02135 PS_JOB_STATUS_NEW_PROCESS_REPORTED, 02136 PS_JOB_STATUS_LAST_REPORT_MEMORY); 02137 02138 IoSetIoCompletion( 02139 Job->CompletionPort, 02140 Job->CompletionKey, 02141 (PVOID)Process->UniqueProcessId, 02142 STATUS_SUCCESS, 02143 JOB_OBJECT_MSG_NEW_PROCESS, 02144 FALSE 02145 ); 02146 02147 } 02148 Next = Next->Flink; 02149 } 02150 } 02151 } 02152 else { 02153 st = STATUS_INVALID_PARAMETER; 02154 } 02155 } 02156 break; 02157 02158 02159 default: 02160 02161 st = STATUS_INVALID_INFO_CLASS; 02162 } 02163 02164 ExReleaseResource(&Job->JobLock); 02165 02166 // 02167 // Working Set Changes are processed outside of the job lock. 02168 // 02169 // calling MmAdjust CAN NOT cause MM to call PsChangeJobMemoryUsage ! 02170 // 02171 02172 if ( ProcessWorkingSetHead ) { 02173 if ( !IsListEmpty(&PspWorkingSetChangeHead.Links) ) { 02174 while ( !IsListEmpty(&PspWorkingSetChangeHead.Links) ) { 02175 Next = RemoveHeadList(&PspWorkingSetChangeHead.Links); 02176 WsChangeRecord = CONTAINING_RECORD(Next,JOB_WORKING_SET_CHANGE_RECORD,Links); 02177 KeAttachProcess(&WsChangeRecord->Process->Pcb); 02178 02179 MmAdjustWorkingSetSize( 02180 PspWorkingSetChangeHead.MinimumWorkingSetSize, 02181 PspWorkingSetChangeHead.MaximumWorkingSetSize, 02182 FALSE 02183 ); 02184 02185 // 02186 // call MM to Enable hard workingset 02187 // 02188 02189 MmEnforceWorkingSetLimit(&WsChangeRecord->Process->Vm, TRUE); 02190 KeDetachProcess(); 02191 ObDereferenceObject(WsChangeRecord->Process); 02192 ExFreePool(WsChangeRecord); 02193 } 02194 } 02195 ExReleaseFastMutexUnsafe(&PspWorkingSetChangeHead.Lock); 02196 } 02197 KeLeaveCriticalRegion(); 02198 02199 02200 // 02201 // Finish Up 02202 // 02203 02204 ObDereferenceObject(Job); 02205 02206 return st; 02207 }

NTSTATUS NtTerminateJobObject IN HANDLE  JobHandle,
IN NTSTATUS  ExitStatus
 

Definition at line 2358 of file psjob.c.

References ExAcquireResourceExclusive, ExReleaseResource, KeEnterCriticalRegion, KeLeaveCriticalRegion, KPROCESSOR_MODE, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PAGED_CODE, PsJobType, PsLockPollOnTimeout, PspTerminateAllProcessesInJob(), and TRUE.

02362 { 02363 PEJOB Job; 02364 NTSTATUS st; 02365 KPROCESSOR_MODE PreviousMode; 02366 02367 PAGED_CODE(); 02368 02369 PreviousMode = KeGetPreviousMode(); 02370 st = ObReferenceObjectByHandle( 02371 JobHandle, 02372 JOB_OBJECT_TERMINATE, 02373 PsJobType, 02374 PreviousMode, 02375 (PVOID *)&Job, 02376 NULL 02377 ); 02378 if ( !NT_SUCCESS(st) ) { 02379 return st; 02380 } 02381 02382 KeEnterCriticalRegion(); 02383 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 02384 02385 PspTerminateAllProcessesInJob(Job,ExitStatus,PsLockPollOnTimeout); 02386 02387 ExReleaseResource(&Job->JobLock); 02388 KeLeaveCriticalRegion(); 02389 02390 ObDereferenceObject(Job); 02391 02392 return st; 02393 }

BOOLEAN PsChangeJobMemoryUsage SSIZE_T  Amount  ) 
 

Definition at line 2823 of file psjob.c.

References _EPROCESS::CommitCharge, _EJOB::CompletionKey, _EJOB::CompletionPort, _EJOB::CurrentJobMemoryUsed, ExAcquireFastMutexUnsafe(), ExReleaseFastMutexUnsafe(), FALSE, IoSetIoCompletion(), _EPROCESS::Job, _EJOB::JobMemoryLimit, _EPROCESS::JobStatus, KeEnterCriticalRegion, KeLeaveCriticalRegion, _EJOB::LimitFlags, _EJOB::MemoryLimitsLock, _EJOB::PeakJobMemoryUsed, _EJOB::PeakProcessMemoryUsed, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NEW_PROCESS_REPORTED, PS_SET_BITS, PsGetCurrentProcess, TRUE, and _EPROCESS::UniqueProcessId.

Referenced by MiInsertVad(), MiRemoveVad(), MiReturnPageTablePageCommitment(), MiSetProtectionOnSection(), MmAssignProcessToJob(), MmCleanProcessAddressSpace(), NtAllocateVirtualMemory(), and NtFreeVirtualMemory().

02826 { 02827 PEPROCESS Process; 02828 PEJOB Job; 02829 SIZE_T CurrentJobMemoryUsed; 02830 BOOLEAN ReturnValue; 02831 02832 ReturnValue = TRUE; 02833 Process = PsGetCurrentProcess(); 02834 Job = Process->Job; 02835 if ( Job ) { 02836 // 02837 // This routine can be called while hoolding the process lock (during 02838 // teb deletion... So instead of using the job lock, we must use the 02839 // memory limits lock. The lock order is always (job lock followed by 02840 // process lock. The memory limits lock never nests or calls other 02841 // code while held. It can be grapped while holding the job lock, or the process 02842 // lock. 02843 // 02844 KeEnterCriticalRegion(); 02845 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 02846 02847 CurrentJobMemoryUsed = Job->CurrentJobMemoryUsed + Amount; 02848 02849 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_JOB_MEMORY && 02850 CurrentJobMemoryUsed > Job->JobMemoryLimit ) { 02851 CurrentJobMemoryUsed = Job->CurrentJobMemoryUsed; 02852 ReturnValue = FALSE; 02853 02854 02855 02856 // 02857 // Tell the job port that commit has been exceeded, and process id x 02858 // was the one that hit it. 02859 // 02860 02861 if ( Job->CompletionPort 02862 && Process->UniqueProcessId 02863 && (Process->JobStatus & PS_JOB_STATUS_NEW_PROCESS_REPORTED) 02864 && (Process->JobStatus & PS_JOB_STATUS_LAST_REPORT_MEMORY) == 0) { 02865 02866 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_LAST_REPORT_MEMORY); 02867 IoSetIoCompletion( 02868 Job->CompletionPort, 02869 Job->CompletionKey, 02870 (PVOID)Process->UniqueProcessId, 02871 STATUS_SUCCESS, 02872 JOB_OBJECT_MSG_JOB_MEMORY_LIMIT, 02873 TRUE 02874 ); 02875 02876 } 02877 } 02878 02879 if ( ReturnValue ) { 02880 // 02881 // update current and peak counters 02882 // 02883 Job->CurrentJobMemoryUsed = CurrentJobMemoryUsed; 02884 if ( CurrentJobMemoryUsed > Job->PeakJobMemoryUsed ) { 02885 Job->PeakJobMemoryUsed = CurrentJobMemoryUsed; 02886 } 02887 02888 if ( Process->CommitCharge + Amount > Job->PeakProcessMemoryUsed ) { 02889 Job->PeakProcessMemoryUsed = Process->CommitCharge + Amount; 02890 } 02891 } 02892 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 02893 KeLeaveCriticalRegion(); 02894 } 02895 02896 return ReturnValue; 02897 }

VOID PsEnforceExecutionTimeLimits VOID   ) 
 

Definition at line 2396 of file psjob.c.

References _EJOB::ActiveProcesses, _EJOB::CompletionKey, _EJOB::CompletionPort, _EJOB::EndOfJobTimeAction, _EJOB::Event, ExAcquireResourceExclusive, ExReleaseResource, FALSE, IoSetIoCompletion(), _EJOB::JobLock, _EPROCESS::JobStatus, KeMaximumIncrement, KeSetEvent(), _EJOB::LimitFlags, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObGetObjectPointerCount(), ObReferenceObject, _EPROCESS::Pcb, _EJOB::PerJobUserTimeLimit, _EJOB::PerProcessUserTimeLimit, _EJOB::ProcessListHead, PS_CLEAR_BITS, PS_JOB_STATUS_ACCOUNTING_FOLDED, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_CLEAR_BITS, PsLockReturnTimeout, PspFoldProcessAccountingIntoJob(), PspJobList, PspJobListLock, PspTerminateAllProcessesInJob(), PspTerminateProcess(), _EJOB::ThisPeriodTotalUserTime, _EJOB::TotalTerminatedProcesses, _EPROCESS::UniqueProcessId, and _KPROCESS::UserTime.

Referenced by KeBalanceSetManager().

02399 { 02400 PLIST_ENTRY NextJob; 02401 PLIST_ENTRY NextProcess; 02402 LARGE_INTEGER RunningJobTime; 02403 LARGE_INTEGER ProcessTime; 02404 PEJOB Job; 02405 PEPROCESS Process; 02406 NTSTATUS st; 02407 02408 ExAcquireFastMutex(&PspJobListLock); 02409 02410 // 02411 // Look at each job. If time limits are set for the job, then enforce them 02412 // 02413 NextJob = PspJobList.Flink; 02414 while ( NextJob != &PspJobList ) { 02415 Job = (PEJOB)(CONTAINING_RECORD(NextJob,EJOB,JobLinks)); 02416 if ( Job->LimitFlags & (JOB_OBJECT_LIMIT_PROCESS_TIME | JOB_OBJECT_LIMIT_JOB_TIME) ) { 02417 02418 // 02419 // Job looks like a candidate for time enforcing. Need to get the 02420 // job lock to be sure, but we don't want to hang waiting for the 02421 // job lock, so skip the job until next time around if we need to 02422 // 02423 // 02424 02425 if ( ExAcquireResourceExclusive(&Job->JobLock, FALSE) ) { 02426 02427 if ( Job->LimitFlags & (JOB_OBJECT_LIMIT_PROCESS_TIME | JOB_OBJECT_LIMIT_JOB_TIME) ) { 02428 02429 // 02430 // Job is setup for time limits 02431 // 02432 02433 RunningJobTime.QuadPart = Job->ThisPeriodTotalUserTime.QuadPart; 02434 02435 NextProcess = Job->ProcessListHead.Flink; 02436 02437 while ( NextProcess != &Job->ProcessListHead) { 02438 02439 Process = (PEPROCESS)(CONTAINING_RECORD(NextProcess,EPROCESS,JobLinks)); 02440 02441 ProcessTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,KeMaximumIncrement); 02442 02443 if ( !(Process->JobStatus & PS_JOB_STATUS_ACCOUNTING_FOLDED) ) { 02444 RunningJobTime.QuadPart += ProcessTime.QuadPart; 02445 } 02446 02447 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_PROCESS_TIME ) { 02448 if ( ProcessTime.QuadPart > Job->PerProcessUserTimeLimit.QuadPart ) { 02449 02450 // 02451 // Process Time Limit has been exceeded. 02452 // 02453 // Reference the process. Assert that it is not in its 02454 // delete routine. If all is OK, then nuke and dereferece 02455 // the process 02456 // 02457 02458 ObReferenceObject(Process); 02459 02460 // 02461 // Avoid double delete since process could be in delete routine during the above ref 02462 // 02463 if ( ObGetObjectPointerCount(Process) > 1 ) { 02464 02465 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 02466 if ( PspTerminateProcess(Process,ERROR_NOT_ENOUGH_QUOTA,PsLockReturnTimeout) == STATUS_SUCCESS ) { 02467 02468 Job->TotalTerminatedProcesses++; 02469 PS_SET_CLEAR_BITS (&Process->JobStatus, 02470 PS_JOB_STATUS_NOT_REALLY_ACTIVE, 02471 PS_JOB_STATUS_LAST_REPORT_MEMORY); 02472 Job->ActiveProcesses--; 02473 02474 if ( Job->CompletionPort ) { 02475 IoSetIoCompletion( 02476 Job->CompletionPort, 02477 Job->CompletionKey, 02478 (PVOID)Process->UniqueProcessId, 02479 STATUS_SUCCESS, 02480 JOB_OBJECT_MSG_END_OF_PROCESS_TIME, 02481 FALSE 02482 ); 02483 } 02484 PspFoldProcessAccountingIntoJob(Job,Process); 02485 02486 } 02487 } 02488 ObDereferenceObject(Process); 02489 } 02490 } 02491 } 02492 02493 NextProcess = NextProcess->Flink; 02494 } 02495 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME ) { 02496 if ( RunningJobTime.QuadPart > Job->PerJobUserTimeLimit.QuadPart ) { 02497 02498 // 02499 // Job Time Limit has been exceeded. 02500 // 02501 // Perform the appropriate action 02502 // 02503 02504 switch ( Job->EndOfJobTimeAction ) { 02505 02506 case JOB_OBJECT_TERMINATE_AT_END_OF_JOB: 02507 if ( PspTerminateAllProcessesInJob(Job,ERROR_NOT_ENOUGH_QUOTA,PsLockReturnTimeout) ) { 02508 if ( Job->ActiveProcesses == 0 ) { 02509 KeSetEvent(&Job->Event,0,FALSE); 02510 if ( Job->CompletionPort ) { 02511 PS_CLEAR_BITS (&Process->JobStatus, PS_JOB_STATUS_LAST_REPORT_MEMORY); 02512 IoSetIoCompletion( 02513 Job->CompletionPort, 02514 Job->CompletionKey, 02515 NULL, 02516 STATUS_SUCCESS, 02517 JOB_OBJECT_MSG_END_OF_JOB_TIME, 02518 FALSE 02519 ); 02520 } 02521 } 02522 } 02523 break; 02524 02525 case JOB_OBJECT_POST_AT_END_OF_JOB: 02526 02527 if ( Job->CompletionPort ) { 02528 PS_CLEAR_BITS (&Process->JobStatus, PS_JOB_STATUS_LAST_REPORT_MEMORY); 02529 st = IoSetIoCompletion( 02530 Job->CompletionPort, 02531 Job->CompletionKey, 02532 NULL, 02533 STATUS_SUCCESS, 02534 JOB_OBJECT_MSG_END_OF_JOB_TIME, 02535 FALSE 02536 ); 02537 if ( NT_SUCCESS(st) ) { 02538 02539 // 02540 // Clear job level time limit 02541 // 02542 02543 Job->LimitFlags &= ~JOB_OBJECT_LIMIT_JOB_TIME; 02544 Job->PerJobUserTimeLimit.QuadPart = 0; 02545 } 02546 } 02547 else { 02548 if ( PspTerminateAllProcessesInJob(Job,ERROR_NOT_ENOUGH_QUOTA,PsLockReturnTimeout) ) { 02549 if ( Job->ActiveProcesses == 0 ) { 02550 KeSetEvent(&Job->Event,0,FALSE); 02551 } 02552 } 02553 } 02554 break; 02555 } 02556 } 02557 02558 } 02559 02560 } 02561 ExReleaseResource(&Job->JobLock); 02562 } 02563 } 02564 NextJob = NextJob->Flink; 02565 } 02566 ExReleaseFastMutex(&PspJobListLock); 02567 }

NTSTATUS PspAddProcessToJob PEJOB  Job,
PEPROCESS  Process
 

Definition at line 439 of file psjob.c.

References _EJOB::ActiveProcesses, _EJOB::ActiveProcessLimit, _EJOB::CompletionKey, _EJOB::CompletionPort, _EJOB::Event, ExAcquireFastMutexUnsafe(), ExAcquireResourceExclusive, ExReleaseFastMutexUnsafe(), ExReleaseResource, FALSE, IoSetIoCompletion(), _EPROCESS::Job, _EPROCESS::JobLinks, _EJOB::JobLock, _EPROCESS::JobStatus, KeAttachProcess(), KeDetachProcess(), KeEnterCriticalRegion, KeLeaveCriticalRegion, KeReadStateEvent(), _EJOB::LimitFlags, _JOB_WORKING_SET_CHANGE_HEAD::Lock, _EJOB::MaximumWorkingSetSize, _EJOB::MinimumWorkingSetSize, MmAdjustWorkingSetSize(), MmAssignProcessToJob(), MmEnforceWorkingSetLimit(), NTSTATUS(), NULL, PAGED_CODE, _EPROCESS::Pcb, _EJOB::ProcessListHead, PS_JOB_STATUS_ACCOUNTING_FOLDED, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NEW_PROCESS_REPORTED, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_BITS, PS_SET_CLEAR_BITS, PspApplyJobLimitsToProcess(), PspWorkingSetChangeHead, Status, _EJOB::TotalProcesses, TRUE, _EPROCESS::UniqueProcessId, and _EPROCESS::Vm.

Referenced by NtAssignProcessToJobObject(), and PspCreateProcess().

00443 { 00444 00445 NTSTATUS Status; 00446 SIZE_T MinWs,MaxWs; 00447 00448 PAGED_CODE(); 00449 00450 00451 KeEnterCriticalRegion(); 00452 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00453 00454 InsertTailList(&Job->ProcessListHead,&Process->JobLinks); 00455 00456 // 00457 // Update relevant ADD accounting info. 00458 // 00459 00460 Job->TotalProcesses++; 00461 Job->ActiveProcesses++; 00462 00463 00464 00465 // 00466 // Test for active process count exceeding limit 00467 // 00468 00469 Status = STATUS_SUCCESS; 00470 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS && 00471 Job->ActiveProcesses > Job->ActiveProcessLimit ) { 00472 00473 PS_SET_CLEAR_BITS (&Process->JobStatus, 00474 PS_JOB_STATUS_NOT_REALLY_ACTIVE | PS_JOB_STATUS_ACCOUNTING_FOLDED, 00475 PS_JOB_STATUS_LAST_REPORT_MEMORY); 00476 00477 Job->ActiveProcesses--; 00478 00479 if ( Job->CompletionPort ) { 00480 IoSetIoCompletion( 00481 Job->CompletionPort, 00482 Job->CompletionKey, 00483 NULL, 00484 STATUS_SUCCESS, 00485 JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT, 00486 TRUE 00487 ); 00488 } 00489 00490 Status = STATUS_QUOTA_EXCEEDED; 00491 } 00492 00493 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_JOB_TIME && KeReadStateEvent(&Job->Event) ) { 00494 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NOT_REALLY_ACTIVE | PS_JOB_STATUS_ACCOUNTING_FOLDED); 00495 00496 Job->ActiveProcesses--; 00497 00498 Status = STATUS_QUOTA_EXCEEDED; 00499 } 00500 00501 if ( Status == STATUS_SUCCESS ) { 00502 00503 PspApplyJobLimitsToProcess(Job,Process); 00504 00505 if ( Process->Job->CompletionPort 00506 && Process->UniqueProcessId 00507 && !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) 00508 && !(Process->JobStatus & PS_JOB_STATUS_NEW_PROCESS_REPORTED)) { 00509 00510 PS_SET_CLEAR_BITS (&Process->JobStatus, 00511 PS_JOB_STATUS_NEW_PROCESS_REPORTED, 00512 PS_JOB_STATUS_LAST_REPORT_MEMORY); 00513 00514 IoSetIoCompletion( 00515 Job->CompletionPort, 00516 Job->CompletionKey, 00517 (PVOID)Process->UniqueProcessId, 00518 STATUS_SUCCESS, 00519 JOB_OBJECT_MSG_NEW_PROCESS, 00520 FALSE 00521 ); 00522 } 00523 00524 } 00525 00526 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET ) { 00527 MinWs = Job->MinimumWorkingSetSize; 00528 MaxWs = Job->MaximumWorkingSetSize; 00529 } 00530 else { 00531 MinWs = 0; 00532 MaxWs = 0; 00533 } 00534 00535 ExReleaseResource(&Job->JobLock); 00536 00537 KeLeaveCriticalRegion(); 00538 00539 if ( Status == STATUS_SUCCESS ) { 00540 00541 if ( MinWs != 0 && MaxWs != 0 ) { 00542 00543 KeEnterCriticalRegion(); 00544 ExAcquireFastMutexUnsafe(&PspWorkingSetChangeHead.Lock); 00545 00546 KeAttachProcess (&Process->Pcb); 00547 MmAdjustWorkingSetSize(MinWs,MaxWs,FALSE); 00548 00549 // 00550 // call MM to Enable hard workingset 00551 // 00552 00553 MmEnforceWorkingSetLimit(&Process->Vm, TRUE); 00554 00555 KeDetachProcess(); 00556 00557 ExReleaseFastMutexUnsafe(&PspWorkingSetChangeHead.Lock); 00558 KeLeaveCriticalRegion(); 00559 00560 } 00561 else { 00562 MmEnforceWorkingSetLimit(&Process->Vm, FALSE); 00563 } 00564 00565 if ( !MmAssignProcessToJob(Process) ) { 00566 Status = STATUS_QUOTA_EXCEEDED; 00567 } 00568 00569 } 00570 00571 return Status; 00572 }

VOID PspApplyJobLimitsToProcess PEJOB  Job,
PEPROCESS  Process
 

Definition at line 2262 of file psjob.c.

References _KPROCESS::Affinity, _EJOB::Affinity, _EPROCESS::CommitChargeLimit, ExAcquireFastMutexUnsafe(), ExReleaseFastMutexUnsafe(), FALSE, KeSetAffinityThread(), KeSetDisableQuantumProcess(), _EJOB::LimitFlags, MEMORY_PRIORITY_FOREGROUND, _EJOB::MemoryLimitsLock, _MMSUPPORT::MemoryPriority, MmEnforceWorkingSetLimit(), NTSTATUS(), PAGED_CODE, _EPROCESS::Pcb, _EPROCESS::PriorityClass, _EJOB::PriorityClass, _EJOB::ProcessMemoryLimit, PsLockPollOnTimeout, PsLockProcess(), PSP_NUMBER_OF_SCHEDULING_CLASSES, PspJobSchedulingClasses, PsProcessPriorityBackground, PsProcessPriorityForeground, PspUseJobSchedulingClasses, PsSetProcessPriorityByClass(), PsUnlockProcess(), _EJOB::SchedulingClass, Status, _ETHREAD::Tcb, _EPROCESS::ThreadListHead, _KPROCESS::ThreadQuantum, TRUE, and _EPROCESS::Vm.

Referenced by PspAddProcessToJob(), and PspApplyJobLimitsToProcessSet().

02266 { 02267 02268 NTSTATUS Status; 02269 PLIST_ENTRY Next; 02270 PETHREAD Thread; 02271 02272 PAGED_CODE(); 02273 02274 // 02275 // The job object is held exclusive by the caller 02276 // 02277 02278 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_PRIORITY_CLASS ) { 02279 Process->PriorityClass = Job->PriorityClass; 02280 02281 PsSetProcessPriorityByClass( 02282 Process, 02283 Process->Vm.MemoryPriority == MEMORY_PRIORITY_FOREGROUND ? 02284 PsProcessPriorityForeground : PsProcessPriorityBackground 02285 ); 02286 } 02287 02288 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_AFFINITY ) { 02289 02290 // 02291 // the following allows this api to properly if 02292 // called while the exiting process is blocked holding the 02293 // createdeletelock. This can happen during debugger/server 02294 // lpc transactions that occur in pspexitthread 02295 // 02296 02297 Status = PsLockProcess(Process,KeGetPreviousMode(),PsLockPollOnTimeout); 02298 02299 if ( Status == STATUS_SUCCESS ) { 02300 Process->Pcb.Affinity = Job->Affinity; 02301 02302 Next = Process->ThreadListHead.Flink; 02303 02304 while ( Next != &Process->ThreadListHead) { 02305 02306 Thread = (PETHREAD)(CONTAINING_RECORD(Next,ETHREAD,ThreadListEntry)); 02307 KeSetAffinityThread(&Thread->Tcb,Job->Affinity); 02308 Next = Next->Flink; 02309 } 02310 02311 PsUnlockProcess(Process); 02312 } 02313 } 02314 02315 if ( !(Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET) ) { 02316 // 02317 // call MM to disable hard workingset 02318 // 02319 02320 MmEnforceWorkingSetLimit(&Process->Vm, FALSE); 02321 } 02322 02323 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 02324 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY ) { 02325 Process->CommitChargeLimit = Job->ProcessMemoryLimit; 02326 } 02327 else { 02328 Process->CommitChargeLimit = 0; 02329 } 02330 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 02331 02332 // 02333 // If the process is NOT IDLE Priority Class, and long fixed quantums 02334 // are in use, use the scheduling class stored in the job object for this process 02335 // 02336 if ( Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE ) { 02337 02338 if ( PspUseJobSchedulingClasses ) { 02339 Process->Pcb.ThreadQuantum = PspJobSchedulingClasses[Job->SchedulingClass]; 02340 } 02341 // 02342 // if the scheduling class is PSP_NUMBER_OF_SCHEDULING_CLASSES-1, then 02343 // give this process non-preemptive scheduling 02344 // 02345 if ( Job->SchedulingClass == PSP_NUMBER_OF_SCHEDULING_CLASSES-1 ) { 02346 KeSetDisableQuantumProcess(&Process->Pcb,TRUE); 02347 } 02348 else { 02349 KeSetDisableQuantumProcess(&Process->Pcb,FALSE); 02350 } 02351 02352 } 02353 02354 02355 }

VOID PspApplyJobLimitsToProcessSet PEJOB  Job  ) 
 

Definition at line 2210 of file psjob.c.

References ExAllocatePoolWithTag, ExFreePool(), _EPROCESS::JobStatus, _EJOB::LimitFlags, _JOB_WORKING_SET_CHANGE_HEAD::Links, ObGetObjectPointerCount(), ObReferenceObject, PAGED_CODE, PagedPool, _EJOB::ProcessListHead, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PspApplyJobLimitsToProcess(), and PspWorkingSetChangeHead.

Referenced by NtSetInformationJobObject().

02213 { 02214 02215 PLIST_ENTRY Next; 02216 PEPROCESS Process; 02217 PJOB_WORKING_SET_CHANGE_RECORD WsChangeRecord; 02218 02219 PAGED_CODE(); 02220 02221 // 02222 // The job object is held exclusive by the caller 02223 // 02224 02225 Next = Job->ProcessListHead.Flink; 02226 02227 while ( Next != &Job->ProcessListHead) { 02228 02229 Process = (PEPROCESS)(CONTAINING_RECORD(Next,EPROCESS,JobLinks)); 02230 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 02231 if ( Job->LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET ) { 02232 WsChangeRecord = ExAllocatePoolWithTag( 02233 PagedPool, 02234 sizeof( *WsChangeRecord ), 02235 'rCsP' 02236 ); 02237 if ( WsChangeRecord ) { 02238 WsChangeRecord->Process = Process; 02239 ObReferenceObject(Process); 02240 // 02241 // Avoid double delete since process could be in delete routine during the above ref 02242 // 02243 if ( ObGetObjectPointerCount(Process) > 1 ) { 02244 InsertTailList(&PspWorkingSetChangeHead.Links,&WsChangeRecord->Links); 02245 } 02246 else { 02247 // 02248 // process is possibly in delete routine waiting to come 02249 // out of job. DON'T Dereference ! 02250 // 02251 ExFreePool(WsChangeRecord); 02252 } 02253 } 02254 } 02255 PspApplyJobLimitsToProcess(Job,Process); 02256 } 02257 Next = Next->Flink; 02258 } 02259 }

NTSTATUS PspCaptureTokenFilter KPROCESSOR_MODE  PreviousMode,
PJOBOBJECT_SECURITY_LIMIT_INFORMATION  SecurityLimitInfo,
PPS_JOB_TOKEN_FILTER TokenFilter
 

Definition at line 2680 of file psjob.c.

References ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, ExFreePool(), Filter, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ProbeForRead, PS_JOB_TOKEN_FILTER, SeCaptureLuidAndAttributesArray(), SeCaptureSidAndAttributesArray(), Status, and TRUE.

Referenced by NtSetInformationJobObject().

02685 { 02686 NTSTATUS Status ; 02687 PPS_JOB_TOKEN_FILTER Filter ; 02688 02689 Filter = ExAllocatePoolWithTag( NonPagedPool, 02690 sizeof( PS_JOB_TOKEN_FILTER ), 02691 'fTsP' ); 02692 02693 if ( !Filter ) 02694 { 02695 *TokenFilter = NULL ; 02696 02697 return STATUS_INSUFFICIENT_RESOURCES ; 02698 } 02699 02700 RtlZeroMemory( Filter, sizeof( PS_JOB_TOKEN_FILTER ) ); 02701 02702 try { 02703 02704 Status = STATUS_SUCCESS ; 02705 02706 // 02707 // Capture Sids to remove 02708 // 02709 02710 if (ARGUMENT_PRESENT( SecurityLimitInfo->SidsToDisable)) { 02711 02712 ProbeForRead( SecurityLimitInfo->SidsToDisable, 02713 sizeof(TOKEN_GROUPS), 02714 sizeof(ULONG) ); 02715 02716 Filter->CapturedGroupCount = SecurityLimitInfo->SidsToDisable->GroupCount; 02717 02718 Status = SeCaptureSidAndAttributesArray( 02719 SecurityLimitInfo->SidsToDisable->Groups, 02720 Filter->CapturedGroupCount, 02721 PreviousMode, 02722 NULL, 0, 02723 NonPagedPool, 02724 TRUE, 02725 &Filter->CapturedGroups, 02726 &Filter->CapturedGroupsLength 02727 ); 02728 02729 } 02730 02731 // 02732 // Capture PrivilegesToDelete 02733 // 02734 02735 if (NT_SUCCESS(Status) && 02736 ARGUMENT_PRESENT(SecurityLimitInfo->PrivilegesToDelete)) { 02737 02738 ProbeForRead( SecurityLimitInfo->PrivilegesToDelete, 02739 sizeof(TOKEN_PRIVILEGES), 02740 sizeof(ULONG) ); 02741 02742 Filter->CapturedPrivilegeCount = SecurityLimitInfo->PrivilegesToDelete->PrivilegeCount; 02743 02744 Status = SeCaptureLuidAndAttributesArray( 02745 SecurityLimitInfo->PrivilegesToDelete->Privileges, 02746 Filter->CapturedPrivilegeCount, 02747 PreviousMode, 02748 NULL, 0, 02749 NonPagedPool, 02750 TRUE, 02751 &Filter->CapturedPrivileges, 02752 &Filter->CapturedPrivilegesLength 02753 ); 02754 02755 } 02756 02757 // 02758 // Capture Restricted Sids 02759 // 02760 02761 if (NT_SUCCESS(Status) && 02762 ARGUMENT_PRESENT(SecurityLimitInfo->RestrictedSids)) { 02763 02764 ProbeForRead( SecurityLimitInfo->RestrictedSids, 02765 sizeof(TOKEN_GROUPS), 02766 sizeof(ULONG) ); 02767 02768 Filter->CapturedSidCount = SecurityLimitInfo->RestrictedSids->GroupCount; 02769 02770 Status = SeCaptureSidAndAttributesArray( 02771 SecurityLimitInfo->RestrictedSids->Groups, 02772 Filter->CapturedSidCount, 02773 PreviousMode, 02774 NULL, 0, 02775 NonPagedPool, 02776 TRUE, 02777 &Filter->CapturedSids, 02778 &Filter->CapturedSidsLength 02779 ); 02780 02781 } 02782 02783 02784 02785 } except(EXCEPTION_EXECUTE_HANDLER) { 02786 02787 Status = GetExceptionCode(); 02788 } // end_try 02789 02790 if ( !NT_SUCCESS( Status ) ) 02791 { 02792 if ( Filter->CapturedSids ) 02793 { 02794 ExFreePool( Filter->CapturedSids ); 02795 } 02796 02797 if ( Filter->CapturedPrivileges ) 02798 { 02799 ExFreePool( Filter->CapturedPrivileges ); 02800 } 02801 02802 if ( Filter->CapturedGroups ) 02803 { 02804 ExFreePool( Filter->CapturedGroups ); 02805 } 02806 02807 ExFreePool( Filter ); 02808 02809 Filter = NULL ; 02810 02811 } 02812 02813 *TokenFilter = Filter ; 02814 02815 return Status ; 02816 02817 02818 }

VOID PspExitProcessFromJob PEJOB  Job,
PEPROCESS  Process
 

Definition at line 608 of file psjob.c.

References _EJOB::ActiveProcesses, ExAcquireResourceExclusive, ExReleaseResource, _EJOB::JobLock, _EPROCESS::JobStatus, KeEnterCriticalRegion, KeLeaveCriticalRegion, PAGED_CODE, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_BITS, PspFoldProcessAccountingIntoJob(), and TRUE.

Referenced by PspExitThread().

00612 { 00613 00614 PAGED_CODE(); 00615 00616 KeEnterCriticalRegion(); 00617 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00618 00619 // 00620 // Update REMOVE accounting info 00621 // 00622 00623 00624 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 00625 Job->ActiveProcesses--; 00626 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NOT_REALLY_ACTIVE); 00627 } 00628 00629 PspFoldProcessAccountingIntoJob(Job,Process); 00630 00631 ExReleaseResource(&Job->JobLock); 00632 KeLeaveCriticalRegion(); 00633 }

VOID PspFoldProcessAccountingIntoJob PEJOB  Job,
PEPROCESS  Process
 

Definition at line 2632 of file psjob.c.

References _EJOB::ActiveProcesses, _EPROCESS::CommitChargePeak, _EJOB::CompletionKey, _EJOB::CompletionPort, FALSE, IoSetIoCompletion(), _EPROCESS::JobStatus, KeMaximumIncrement, _KPROCESS::KernelTime, NULL, _EJOB::OtherOperationCount, _EPROCESS::OtherOperationCount, _EJOB::OtherTransferCount, _EPROCESS::OtherTransferCount, _MMSUPPORT::PageFaultCount, _EPROCESS::Pcb, _EJOB::PeakProcessMemoryUsed, PS_JOB_STATUS_ACCOUNTING_FOLDED, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_SET_CLEAR_BITS, _EJOB::ReadOperationCount, _EPROCESS::ReadOperationCount, _EJOB::ReadTransferCount, _EPROCESS::ReadTransferCount, _EJOB::ThisPeriodTotalKernelTime, _EJOB::ThisPeriodTotalUserTime, _EJOB::TotalKernelTime, _EJOB::TotalPageFaultCount, _EJOB::TotalUserTime, _KPROCESS::UserTime, _EPROCESS::Vm, _EJOB::WriteOperationCount, _EPROCESS::WriteOperationCount, _EJOB::WriteTransferCount, and _EPROCESS::WriteTransferCount.

Referenced by NtSetInformationJobObject(), PsEnforceExecutionTimeLimits(), PspExitProcessFromJob(), PspRemoveProcessFromJob(), and PspTerminateAllProcessesInJob().

02636 { 02637 LARGE_INTEGER UserTime, KernelTime; 02638 02639 if ( !(Process->JobStatus & PS_JOB_STATUS_ACCOUNTING_FOLDED) ) { 02640 UserTime.QuadPart = UInt32x32To64(Process->Pcb.UserTime,KeMaximumIncrement); 02641 KernelTime.QuadPart = UInt32x32To64(Process->Pcb.KernelTime,KeMaximumIncrement); 02642 02643 Job->TotalUserTime.QuadPart += UserTime.QuadPart; 02644 Job->TotalKernelTime.QuadPart += KernelTime.QuadPart; 02645 Job->ThisPeriodTotalUserTime.QuadPart += UserTime.QuadPart; 02646 Job->ThisPeriodTotalKernelTime.QuadPart += KernelTime.QuadPart; 02647 02648 Job->ReadOperationCount += Process->ReadOperationCount.QuadPart; 02649 Job->WriteOperationCount += Process->WriteOperationCount.QuadPart; 02650 Job->OtherOperationCount += Process->OtherOperationCount.QuadPart; 02651 Job->ReadTransferCount += Process->ReadTransferCount.QuadPart; 02652 Job->WriteTransferCount += Process->WriteTransferCount.QuadPart; 02653 Job->OtherTransferCount += Process->OtherTransferCount.QuadPart; 02654 02655 Job->TotalPageFaultCount += Process->Vm.PageFaultCount; 02656 02657 02658 if ( Process->CommitChargePeak > Job->PeakProcessMemoryUsed ) { 02659 Job->PeakProcessMemoryUsed = Process->CommitChargePeak; 02660 } 02661 02662 PS_SET_CLEAR_BITS (&Process->JobStatus, 02663 PS_JOB_STATUS_ACCOUNTING_FOLDED, 02664 PS_JOB_STATUS_LAST_REPORT_MEMORY); 02665 02666 if ( Job->CompletionPort && Job->ActiveProcesses == 0) { 02667 IoSetIoCompletion( 02668 Job->CompletionPort, 02669 Job->CompletionKey, 02670 NULL, 02671 STATUS_SUCCESS, 02672 JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO, 02673 FALSE 02674 ); 02675 } 02676 } 02677 }

VOID PspJobClose IN PEPROCESS  Process,
IN PVOID  Object,
IN ACCESS_MASK  GrantedAccess,
IN ULONG  ProcessHandleCount,
IN ULONG  SystemHandleCount
 

Definition at line 709 of file psjob.c.

References _EJOB::CompletionPort, ExAcquireFastMutexUnsafe(), ExAcquireResourceExclusive, ExReleaseFastMutexUnsafe(), ExReleaseResource, _EJOB::JobLock, KeEnterCriticalRegion, KeLeaveCriticalRegion, _EJOB::MemoryLimitsLock, NULL, ObDereferenceObject, PAGED_CODE, and TRUE.

Referenced by PspInitPhase0().

00718 : 00719 00720 Called by the object manager when a handle is closed to the object. 00721 00722 Arguments: 00723 00724 Process - Process doing the close 00725 Object - Job object being closed 00726 GrantedAccess - Access ranted for this handle 00727 ProcessHandleCount - Unused and unmaintained by OB 00728 SystemHandleCount - Current handle count for this object 00729 00730 Return Value: 00731 00732 None. 00733 00734 --*/ 00735 { 00736 PEJOB Job = Object; 00737 PVOID Port; 00738 00739 PAGED_CODE (); 00740 // 00741 // If this isn't the last handle then do nothing. 00742 // 00743 if (SystemHandleCount > 1) { 00744 return; 00745 } 00746 00747 KeEnterCriticalRegion(); 00748 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00749 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 00750 00751 // 00752 // Release the completion port 00753 // 00754 Port = Job->CompletionPort; 00755 Job->CompletionPort = NULL; 00756 00757 00758 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 00759 ExReleaseResource(&Job->JobLock); 00760 KeLeaveCriticalRegion(); 00761 00762 if (Port != NULL) { 00763 ObDereferenceObject(Port); 00764 } 00765 }

VOID PspJobDelete IN PVOID  Object  ) 
 

Definition at line 636 of file psjob.c.

References _WIN32_JOBCALLOUT_PARAMETERS::CalloutType, _PS_JOB_TOKEN_FILTER::CapturedGroups, _PS_JOB_TOKEN_FILTER::CapturedPrivileges, _PS_JOB_TOKEN_FILTER::CapturedSids, _EJOB::CompletionPort, _WIN32_JOBCALLOUT_PARAMETERS::Data, ExAcquireResourceExclusive, ExDeleteResource, ExFreePool(), ExReleaseResource, _EJOB::Filter, _WIN32_JOBCALLOUT_PARAMETERS::Job, _EJOB::JobLinks, _EJOB::JobLock, KeEnterCriticalRegion, KeLeaveCriticalRegion, _EJOB::LimitFlags, MmDispatchWin32Callout(), NULL, ObDereferenceObject, PAGED_CODE, PspJobListLock, PspW32JobCallout, PsW32JobCalloutTerminate, _EJOB::SessionId, _EJOB::Token, and TRUE.

Referenced by PspInitPhase0().

00639 { 00640 PEJOB Job; 00641 WIN32_JOBCALLOUT_PARAMETERS Parms; 00642 00643 PAGED_CODE(); 00644 00645 Job = (PEJOB) Object; 00646 00647 // 00648 // call ntuser to delete its job structure 00649 // 00650 00651 KeEnterCriticalRegion(); 00652 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00653 00654 00655 Parms.Job = Job; 00656 Parms.CalloutType = PsW32JobCalloutTerminate; 00657 Parms.Data = NULL; 00658 MmDispatchWin32Callout( PspW32JobCallout,NULL, (PVOID)&Parms, &(Job->SessionId)); 00659 00660 ExReleaseResource(&Job->JobLock); 00661 KeLeaveCriticalRegion(); 00662 00663 Job->LimitFlags = 0; 00664 00665 if ( Job->CompletionPort ) { 00666 ObDereferenceObject(Job->CompletionPort); 00667 Job->CompletionPort = NULL; 00668 } 00669 00670 00671 // 00672 // Remove Job on Job List 00673 // 00674 00675 ExAcquireFastMutex(&PspJobListLock); 00676 RemoveEntryList(&Job->JobLinks); 00677 ExReleaseFastMutex(&PspJobListLock); 00678 00679 // 00680 // Free Security clutter: 00681 // 00682 00683 if ( Job->Token ) { 00684 ObDereferenceObject( Job->Token ); 00685 Job->Token = NULL ; 00686 } 00687 00688 if ( Job->Filter ) { 00689 if ( Job->Filter->CapturedSids ) { 00690 ExFreePool( Job->Filter->CapturedSids ); 00691 } 00692 00693 if ( Job->Filter->CapturedPrivileges ) { 00694 ExFreePool( Job->Filter->CapturedPrivileges ); 00695 } 00696 00697 if ( Job->Filter->CapturedGroups ) { 00698 ExFreePool( Job->Filter->CapturedGroups ); 00699 } 00700 00701 ExFreePool( Job->Filter ); 00702 00703 } 00704 00705 ExDeleteResource(&Job->JobLock); 00706 }

VOID PspRemoveProcessFromJob PEJOB  Job,
PEPROCESS  Process
 

Definition at line 579 of file psjob.c.

References _EJOB::ActiveProcesses, ExAcquireResourceExclusive, ExReleaseResource, _EPROCESS::JobLinks, _EJOB::JobLock, _EPROCESS::JobStatus, KeEnterCriticalRegion, KeLeaveCriticalRegion, PAGED_CODE, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_BITS, PspFoldProcessAccountingIntoJob(), and TRUE.

Referenced by PspProcessDelete().

00583 { 00584 PAGED_CODE(); 00585 00586 KeEnterCriticalRegion(); 00587 ExAcquireResourceExclusive(&Job->JobLock, TRUE); 00588 00589 RemoveEntryList(&Process->JobLinks); 00590 00591 // 00592 // Update REMOVE accounting info 00593 // 00594 00595 00596 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 00597 Job->ActiveProcesses--; 00598 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NOT_REALLY_ACTIVE); 00599 } 00600 00601 PspFoldProcessAccountingIntoJob(Job,Process); 00602 00603 ExReleaseResource(&Job->JobLock); 00604 KeLeaveCriticalRegion(); 00605 }

BOOLEAN PspTerminateAllProcessesInJob PEJOB  Job,
NTSTATUS  Status,
PSLOCKPROCESSMODE  LockMode
 

Definition at line 2570 of file psjob.c.

References _EJOB::ActiveProcesses, FALSE, _EPROCESS::JobStatus, ObDereferenceObject, ObGetObjectPointerCount(), ObReferenceObject, PAGED_CODE, _EJOB::ProcessListHead, PS_JOB_STATUS_NOT_REALLY_ACTIVE, PS_SET_BITS, PsLockPollOnTimeout, PspFoldProcessAccountingIntoJob(), PspTerminateProcess(), Status, _EJOB::TotalTerminatedProcesses, and TRUE.

Referenced by NtTerminateJobObject(), and PsEnforceExecutionTimeLimits().

02575 { 02576 PLIST_ENTRY NextProcess; 02577 PEPROCESS Process; 02578 BOOLEAN TerminatedAProcess; 02579 02580 PAGED_CODE(); 02581 02582 TerminatedAProcess = FALSE; 02583 NextProcess = Job->ProcessListHead.Flink; 02584 02585 while ( NextProcess != &Job->ProcessListHead) { 02586 02587 Process = (PEPROCESS)(CONTAINING_RECORD(NextProcess,EPROCESS,JobLinks)); 02588 02589 // 02590 // Reference the process. Assert that it is not in its 02591 // delete routine. If all is OK, then nuke and dereferece 02592 // the process 02593 // 02594 02595 ObReferenceObject(Process); 02596 02597 // 02598 // Avoid double delete since process could be in delete routine during the above ref 02599 // 02600 if ( ObGetObjectPointerCount(Process) > 1 ) { 02601 if ( !(Process->JobStatus & PS_JOB_STATUS_NOT_REALLY_ACTIVE) ) { 02602 02603 if ( PspTerminateProcess(Process,Status,LockMode) == STATUS_SUCCESS ) { 02604 02605 // 02606 // If the lockmode isn't poll, it means we ran out of 02607 // job time, so increment the terminated process count 02608 // for each nuked process 02609 // 02610 if ( LockMode != PsLockPollOnTimeout ) { 02611 Job->TotalTerminatedProcesses++; 02612 } 02613 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_NOT_REALLY_ACTIVE); 02614 Job->ActiveProcesses--; 02615 02616 PspFoldProcessAccountingIntoJob(Job,Process); 02617 02618 TerminatedAProcess = TRUE; 02619 } 02620 } 02621 02622 ObDereferenceObject(Process); 02623 } 02624 02625 NextProcess = NextProcess->Flink; 02626 } 02627 return TerminatedAProcess; 02628 }

VOID PsReportProcessMemoryLimitViolation VOID   ) 
 

Definition at line 2901 of file psjob.c.

References _EJOB::CompletionKey, _EJOB::CompletionPort, ExAcquireFastMutexUnsafe(), ExReleaseFastMutexUnsafe(), IoSetIoCompletion(), _EPROCESS::Job, _EPROCESS::JobStatus, KeEnterCriticalRegion, KeLeaveCriticalRegion, _EJOB::LimitFlags, _EJOB::MemoryLimitsLock, PS_JOB_STATUS_LAST_REPORT_MEMORY, PS_JOB_STATUS_NEW_PROCESS_REPORTED, PS_SET_BITS, PsGetCurrentProcess, TRUE, and _EPROCESS::UniqueProcessId.

Referenced by MiInsertVad(), MiSetProtectionOnSection(), and NtAllocateVirtualMemory().

02904 { 02905 PEPROCESS Process; 02906 PEJOB Job; 02907 02908 Process = PsGetCurrentProcess(); 02909 Job = Process->Job; 02910 if ( Job && (Job->LimitFlags & JOB_OBJECT_LIMIT_PROCESS_MEMORY) ) { 02911 KeEnterCriticalRegion(); 02912 ExAcquireFastMutexUnsafe(&Job->MemoryLimitsLock); 02913 02914 // 02915 // Tell the job port that commit has been exceeded, and process id x 02916 // was the one that hit it. 02917 // 02918 02919 if ( Job->CompletionPort 02920 && Process->UniqueProcessId 02921 && (Process->JobStatus & PS_JOB_STATUS_NEW_PROCESS_REPORTED) 02922 && (Process->JobStatus & PS_JOB_STATUS_LAST_REPORT_MEMORY) == 0) { 02923 02924 PS_SET_BITS (&Process->JobStatus, PS_JOB_STATUS_LAST_REPORT_MEMORY); 02925 IoSetIoCompletion( 02926 Job->CompletionPort, 02927 Job->CompletionKey, 02928 (PVOID)Process->UniqueProcessId, 02929 STATUS_SUCCESS, 02930 JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT, 02931 TRUE 02932 ); 02933 02934 } 02935 ExReleaseFastMutexUnsafe(&Job->MemoryLimitsLock); 02936 KeLeaveCriticalRegion(); 02937 02938 } 02939 }


Variable Documentation

POBJECT_TYPE IoCompletionObjectType
 

Definition at line 43 of file psjob.c.

Referenced by IopCreateObjectTypes(), NtCreateIoCompletion(), NtOpenIoCompletion(), NtQueryIoCompletion(), NtRemoveIoCompletion(), NtSetInformationFile(), NtSetInformationJobObject(), and NtSetIoCompletion().

ULONG PspJobInfoAlign[]
 

Initial value:

{ sizeof(ULONG), sizeof(ULONG), sizeof(ULONG), sizeof(ULONG), sizeof(ULONG), sizeof(ULONG), sizeof(PVOID), sizeof(ULONG), sizeof(ULONG), 0 }

Definition at line 799 of file psjob.c.

Referenced by NtQueryInformationJobObject(), and NtSetInformationJobObject().

ULONG PspJobInfoLengths[]
 

Initial value:

{ sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION), sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION), sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST), sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS), sizeof(JOBOBJECT_SECURITY_LIMIT_INFORMATION), sizeof(JOBOBJECT_END_OF_JOB_TIME_INFORMATION), sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT), sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION), sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION), 0 }

Definition at line 767 of file psjob.c.

Referenced by NtQueryInformationJobObject(), and NtSetInformationJobObject().


Generated on Sat May 15 19:45:23 2004 for test by doxygen 1.3.7