00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include "psp.h"
00022
#include "winerror.h"
00023
00024
#pragma alloc_text(PAGE, PspJobDelete)
00025
#pragma alloc_text(PAGE, PspJobClose)
00026
#pragma alloc_text(PAGE, NtCreateJobObject)
00027
#pragma alloc_text(PAGE, NtOpenJobObject)
00028
#pragma alloc_text(PAGE, NtAssignProcessToJobObject)
00029
#pragma alloc_text(PAGE, PspAddProcessToJob)
00030
#pragma alloc_text(PAGE, PspRemoveProcessFromJob)
00031
#pragma alloc_text(PAGE, PspExitProcessFromJob)
00032
#pragma alloc_text(PAGE, NtQueryInformationJobObject)
00033
#pragma alloc_text(PAGE, NtSetInformationJobObject)
00034
#pragma alloc_text(PAGE, PspApplyJobLimitsToProcessSet)
00035
#pragma alloc_text(PAGE, PspApplyJobLimitsToProcess)
00036
#pragma alloc_text(PAGE, NtTerminateJobObject)
00037
#pragma alloc_text(PAGE, PspTerminateAllProcessesInJob)
00038
#pragma alloc_text(PAGE, PspFoldProcessAccountingIntoJob)
00039
#pragma alloc_text(PAGE, PspCaptureTokenFilter)
00040
00041
00042
00043 extern POBJECT_TYPE IoCompletionObjectType;
00044
00045
00046
NTSTATUS
00047 NTAPI
00048 NtCreateJobObject (
00049 OUT PHANDLE JobHandle,
00050 IN ACCESS_MASK DesiredAccess,
00051 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
00052 )
00053 {
00054
00055
PEJOB Job;
00056 HANDLE
Handle;
00057
KPROCESSOR_MODE PreviousMode;
00058
NTSTATUS Status;
00059
00060
PAGED_CODE();
00061
00062
00063
00064
00065
00066
00067
00068
00069
try {
00070
00071
00072
00073
00074
00075
00076 PreviousMode = KeGetPreviousMode();
00077
if (PreviousMode !=
KernelMode) {
00078
ProbeForWriteHandle(JobHandle);
00079 }
00080
00081
00082
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
00099
00100
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
00111
00112
00113
00114 Job->SessionId =
PsGetCurrentProcess()->SessionId;
00115
00116
00117
00118
00119 Job->SchedulingClass =
PSP_DEFAULT_SCHEDULING_CLASSES;
00120
00121
00122
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
00134
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
00153
00154
00155
00156
00157
00158
00159
if (
NT_SUCCESS(
Status)) {
00160
try {
00161 *JobHandle =
Handle;
00162 }
00163 except(
ExSystemExceptionFilter()) {
00164 }
00165 }
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 }
00175 except(
ExSystemExceptionFilter()) {
00176
return GetExceptionCode();
00177 }
00178
00179
00180
00181
00182
00183
return Status;
00184 }
00185
00186
NTSTATUS
00187 NTAPI
00188 NtOpenJobObject(
00189 OUT PHANDLE JobHandle,
00190 IN ACCESS_MASK DesiredAccess,
00191 IN POBJECT_ATTRIBUTES ObjectAttributes
00192 )
00193 {
00194 HANDLE
Handle;
00195
KPROCESSOR_MODE PreviousMode;
00196
NTSTATUS Status;
00197
00198
PAGED_CODE();
00199
00200
00201
00202
00203
00204
00205
00206
00207
try {
00208
00209
00210
00211
00212
00213
00214 PreviousMode = KeGetPreviousMode();
00215
if (PreviousMode !=
KernelMode) {
00216
ProbeForWriteHandle(JobHandle);
00217 }
00218
00219
00220
00221
00222
00223
Status =
ObOpenObjectByName(
00224
ObjectAttributes,
00225
PsJobType,
00226 PreviousMode,
00227
NULL,
00228 DesiredAccess,
00229
NULL,
00230 &
Handle
00231 );
00232
00233
00234
00235
00236
00237
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
00254
00255
00256
00257
00258
Status = GetExceptionCode();
00259 }
00260
00261
return Status;
00262 }
00263
00264
NTSTATUS
00265 NTAPI
00266 NtAssignProcessToJobObject(
00267 IN HANDLE JobHandle,
00268 IN HANDLE ProcessHandle
00269 )
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
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
00299
00300
00301
if ( Process->Job ) {
00302
ObDereferenceObject(Process);
00303
return STATUS_ACCESS_DENIED;
00304 }
00305
00306
00307
00308
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
00326
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
00354
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
00382
00383
00384
00385
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
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
00428
00429 }
00430 }
00431
00432
ObDereferenceObject(Process);
00433
ObDereferenceObject(Job);
00434
00435
return Status;
00436 }
00437
00438
NTSTATUS
00439 PspAddProcessToJob(
00440
PEJOB Job,
00441
PEPROCESS Process
00442 )
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
00458
00459
00460 Job->
TotalProcesses++;
00461 Job->
ActiveProcesses++;
00462
00463
00464
00465
00466
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
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 }
00573
00574
00575
00576
00577
00578
VOID
00579 PspRemoveProcessFromJob(
00580
PEJOB Job,
00581
PEPROCESS Process
00582 )
00583 {
00584
PAGED_CODE();
00585
00586
KeEnterCriticalRegion();
00587
ExAcquireResourceExclusive(&Job->
JobLock,
TRUE);
00588
00589 RemoveEntryList(&Process->
JobLinks);
00590
00591
00592
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 }
00606
00607
VOID
00608 PspExitProcessFromJob(
00609
PEJOB Job,
00610
PEPROCESS Process
00611 )
00612 {
00613
00614
PAGED_CODE();
00615
00616
KeEnterCriticalRegion();
00617
ExAcquireResourceExclusive(&Job->
JobLock,
TRUE);
00618
00619
00620
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 }
00634
00635
VOID
00636 PspJobDelete(
00637 IN PVOID Object
00638 )
00639 {
00640
PEJOB Job;
00641
WIN32_JOBCALLOUT_PARAMETERS Parms;
00642
00643
PAGED_CODE();
00644
00645 Job = (
PEJOB) Object;
00646
00647
00648
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
00673
00674
00675 ExAcquireFastMutex(&
PspJobListLock);
00676 RemoveEntryList(&Job->
JobLinks);
00677 ExReleaseFastMutex(&
PspJobListLock);
00678
00679
00680
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 }
00707
00708
VOID
00709 PspJobClose (
00710 IN
PEPROCESS Process,
00711 IN PVOID Object,
00712 IN ACCESS_MASK GrantedAccess,
00713 IN ULONG ProcessHandleCount,
00714 IN ULONG SystemHandleCount
00715 )
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735 {
00736
PEJOB Job = Object;
00737 PVOID Port;
00738
00739
PAGED_CODE ();
00740
00741
00742
00743
if (SystemHandleCount > 1) {
00744
return;
00745 }
00746
00747
KeEnterCriticalRegion();
00748
ExAcquireResourceExclusive(&Job->
JobLock,
TRUE);
00749
ExAcquireFastMutexUnsafe(&Job->
MemoryLimitsLock);
00750
00751
00752
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 }
00766
00767 ULONG
PspJobInfoLengths[] = {
00768
sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
00769
sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION),
00770
sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST),
00771
sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS),
00772
sizeof(JOBOBJECT_SECURITY_LIMIT_INFORMATION),
00773
sizeof(JOBOBJECT_END_OF_JOB_TIME_INFORMATION),
00774
sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT),
00775
sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION),
00776
sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION),
00777 0
00778 };
00779
00780
#if defined(_ALPHA_)
00781
00782
00783
00784
00785
00786 ULONG
PspJobInfoAlign[] = {
00787
sizeof(LARGE_INTEGER),
00788
sizeof(LARGE_INTEGER),
00789
sizeof(ULONG),
00790
sizeof(ULONG),
00791
sizeof(ULONG),
00792
sizeof(ULONG),
00793
sizeof(PVOID),
00794
sizeof(LARGE_INTEGER),
00795
sizeof(LARGE_INTEGER),
00796 0
00797 };
00798
#else
00799 ULONG
PspJobInfoAlign[] = {
00800
sizeof(ULONG),
00801
sizeof(ULONG),
00802
sizeof(ULONG),
00803
sizeof(ULONG),
00804
sizeof(ULONG),
00805
sizeof(ULONG),
00806
sizeof(PVOID),
00807
sizeof(ULONG),
00808
sizeof(ULONG),
00809 0
00810 };
00811
#endif // _ALPHA_
00812
00813
NTSTATUS
00814 NtQueryInformationJobObject(
00815 IN HANDLE JobHandle,
00816 IN JOBOBJECTINFOCLASS JobObjectInformationClass,
00817 OUT PVOID JobObjectInformation,
00818 IN ULONG JobObjectInformationLength,
00819 OUT PULONG ReturnLength OPTIONAL
00820 )
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
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
00864
00865
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
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
00920
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
00941
00942
00943
switch ( JobObjectInformationClass ) {
00944
00945
case JobObjectBasicAccountingInformation:
00946
case JobObjectBasicAndIoAccountingInformation:
00947
00948
00949
00950
00951
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
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
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
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
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
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
01126
01127
01128
if ( Job->
Filter )
01129 {
01130
01131
01132
01133
01134
01135 WorkingLength = Job->
Filter->
CapturedSidsLength +
01136 Job->
Filter->
CapturedGroupsLength +
01137 Job->
Filter->
CapturedPrivilegesLength ;
01138
01139 WorkingLength = 0 ;
01140
01141
01142
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
01291
01292
01293
ObDereferenceObject(Job);
01294
01295
01296
if (
NT_SUCCESS(st) ) {
01297
01298
01299
01300
01301
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 }
01321
01322
NTSTATUS
01323 NtSetInformationJobObject(
01324 IN HANDLE JobHandle,
01325 IN JOBOBJECTINFOCLASS JobObjectInformationClass,
01326 IN PVOID JobObjectInformation,
01327 IN ULONG JobObjectInformationLength
01328 )
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
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
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
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
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
01446
01447
01448 LocalJob.
LimitFlags = Job->LimitFlags;
01449
01450
01451
01452
01453
01454
if ( LimitFlags & JOB_OBJECT_LIMIT_ACTIVE_PROCESS ) {
01455
01456
01457
01458
01459
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
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
01484
01485
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
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
01524
01525
01526
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
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
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
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
01607
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
01621
01622
if ( LimitFlags & JOB_OBJECT_LIMIT_WORKINGSET ) {
01623
01624
01625
01626
01627
01628
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
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
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
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
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
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
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
01749
01750
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
01761
01762
01763
01764
01765
01766
01767
01768
if (
KeReadStateProcess(&Process->
Pcb) ) {
01769
PspFoldProcessAccountingIntoJob(Job,Process);
01770 }
01771
else {
01772
01773 LARGE_INTEGER ProcessTime;
01774
01775
01776
01777
01778
01779
01780
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
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
01830
01831
if ( BasicUIRestrictions.UIRestrictionsClass & ~JOB_OBJECT_UI_VALID_FLAGS ) {
01832 st = STATUS_INVALID_PARAMETER;
01833 }
01834
else {
01835
01836
01837
01838
01839
01840
if ( Job->UIRestrictionsClass ^ BasicUIRestrictions.UIRestrictionsClass ) {
01841
01842
01843
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
01857
01858
01859 Job->UIRestrictionsClass = BasicUIRestrictions.UIRestrictionsClass;
01860 }
01861 }
01862
break;
01863
01864
01865
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
01890
01891
01892
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
01927
01928
01929
01930
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
01969
01970
01971
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
01993
01994
01995
01996 Job->Token = LocalToken ;
01997
01998
01999
02000
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
02022
02023
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
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
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
02115
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
02127
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
02168
02169
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
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
02202
02203
02204
ObDereferenceObject(Job);
02205
02206
return st;
02207 }
02208
02209
VOID
02210 PspApplyJobLimitsToProcessSet(
02211
PEJOB Job
02212 )
02213 {
02214
02215 PLIST_ENTRY Next;
02216
PEPROCESS Process;
02217
PJOB_WORKING_SET_CHANGE_RECORD WsChangeRecord;
02218
02219
PAGED_CODE();
02220
02221
02222
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
02242
02243
if (
ObGetObjectPointerCount(Process) > 1 ) {
02244 InsertTailList(&
PspWorkingSetChangeHead.
Links,&WsChangeRecord->Links);
02245 }
02246
else {
02247
02248
02249
02250
02251
ExFreePool(WsChangeRecord);
02252 }
02253 }
02254 }
02255
PspApplyJobLimitsToProcess(Job,Process);
02256 }
02257 Next = Next->Flink;
02258 }
02259 }
02260
02261
VOID
02262 PspApplyJobLimitsToProcess(
02263
PEJOB Job,
02264
PEPROCESS Process
02265 )
02266 {
02267
02268
NTSTATUS Status;
02269 PLIST_ENTRY Next;
02270
PETHREAD Thread;
02271
02272
PAGED_CODE();
02273
02274
02275
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
02292
02293
02294
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
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
02334
02335
02336
if ( Process->
PriorityClass != PROCESS_PRIORITY_CLASS_IDLE ) {
02337
02338
if (
PspUseJobSchedulingClasses ) {
02339 Process->
Pcb.
ThreadQuantum =
PspJobSchedulingClasses[Job->
SchedulingClass];
02340 }
02341
02342
02343
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 }
02356
02357
NTSTATUS
02358 NtTerminateJobObject(
02359 IN HANDLE JobHandle,
02360 IN NTSTATUS ExitStatus
02361 )
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 }
02394
02395
VOID
02396 PsEnforceExecutionTimeLimits(
02397 VOID
02398 )
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
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
02420
02421
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
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
02452
02453
02454
02455
02456
02457
02458
ObReferenceObject(Process);
02459
02460
02461
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
02500
02501
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
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 }
02568
02569 BOOLEAN
02570 PspTerminateAllProcessesInJob(
02571
PEJOB Job,
02572 NTSTATUS Status,
02573 PSLOCKPROCESSMODE LockMode
02574 )
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
02591
02592
02593
02594
02595
ObReferenceObject(Process);
02596
02597
02598
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
02607
02608
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 }
02629
02630
02631
VOID
02632 PspFoldProcessAccountingIntoJob(
02633
PEJOB Job,
02634
PEPROCESS Process
02635 )
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 }
02678
02679
NTSTATUS
02680 PspCaptureTokenFilter(
02681 KPROCESSOR_MODE PreviousMode,
02682 PJOBOBJECT_SECURITY_LIMIT_INFORMATION SecurityLimitInfo,
02683
PPS_JOB_TOKEN_FILTER * TokenFilter
02684 )
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
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
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
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 }
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 }
02819
02820
02821
02822 BOOLEAN
02823 PsChangeJobMemoryUsage(
02824 SSIZE_T Amount
02825 )
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
02838
02839
02840
02841
02842
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
02858
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
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 }
02898
02899
02900
VOID
02901 PsReportProcessMemoryLimitViolation(
02902 VOID
02903 )
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
02916
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 }