Job可以被理解为进程的容器,而它又不是单纯的容器,按照书本上所讲的,Job是一个沙盒,它可以为在它里面运行的进程增加一系列的限制。包括每一个进程或者整个Job能够使用的User mode CPU时间,每一个进程或者整个Job最多能使用的内存,Job内的进程能否访问到Job外的用户对象(例如窗口,画刷),能否退出Windows,能否访问剪切板等等。当限制设定之后,我们就可以创建一个进程,并将它放置到Job之中。



需要注意的是:

1、Job对象即使引用数到了0也不会立刻释放,它会等到Job内所有的进程都结束了再释放,但是,在这种情况下,Job的名称将会失效,不能再通过Job的名称和Job的句柄来向Job中增加新的进程。


2、Job可以设置当前可运行进程最大数量。当超过这个最大数量时,任何新进程都将被立刻终止(Terminate)。


3、Job可以在同一进程优先级下设定调度的微调值(SchedulingClass)。微调值高的Job中的线程比微调值低的获得更多的CPU时间。


4、Job可以限制对用户对象以及Windows界面的访问,例如不许退出窗口,不能访问剪切板等。这意味着Job内的进程无法获取到Job外进程的对象,比如HWND,但是Job外的进程可以获得Job内进程的对象。


5、对Job设定了OBOBJECT_SECURITY_LIMIT_INFORMATION后,该设定不能被取消。



6、新建的进程最好使用CREATE_SUSPEND Flag,这样新进程启动后在加入到Job之前它都无法运行,从而避免新进程可以逃出沙盒。在加入到Job之后,继续运行进程即可。

7、当一个进程被加入到Job中后,没有特殊的说明,那么该进程的所有子进程都将被纳入到Job里。当然,通过JOB_OBJECT_LIMIT_BREAKAWAY_OK或者JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK。Job内进程的子进程就可以不被自动纳入到Job中,两者区别在于,后者将所有子进程自动的赶出Job,而前者的子进程需要在CreateProcess时指定CREATE_BREAKAWAY_FROM_JOB。


8、如果Job被强制关闭,那么Job内的所有进程都将被终止(Terminate)


9、当Job所指定的CPU时间耗光后,Job HANDLE将处于Signaled状态,Wait系列函数就可以响应这个事件。



此外,任何Job中重要的事件,例如新进程的产生和终止,进程CPU时间的耗尽等等都可以通过完成端口的形式获得通知。(第五章第五小节)

---------------------------------------------------

Job相关API介绍


1、CreateJobObject,  创建一个具名的Job对象

HANDLE WINAPI CreateJobObject(
  __in_opt  LPSECURITY_ATTRIBUTES lpJobAttributes,
  __in_opt  LPCTSTR lpName
);
该API创建一个Job内核对象,可以为对象的名字前加上"Global\" or "Local\" 来指定名字是全局的还是局部的,该对象名字和其他类型的具名对象同在一个命名空间,如果名字冲突,会导致函数失败。

Job的所有工作机制都是围绕这个内核对象展开的,在内核中所有对Job包含的进程的限制,都是通过获取进程的内核对象中挂接的Job对象,根据Job对象的属性来限制进程所能够完成的操作,Job内核对象在WRK中是这样定义的:

typedef struct _EJOB {
    KEVENT Event;

    //
    // All jobs are chained together via this list.
    // Protected by the global lock PspJobListLock
    //

    LIST_ENTRY JobLinks;//创建一个Job对象的时候,会将其挂入系统Job对象链表中,

    //
    // All processes within this job. Processes are removed from this
    // list at last dereference. Safe object referencing needs to be done.
    // Protected by the joblock.
    //

    LIST_ENTRY ProcessListHead; //进程链表头,AssignProcessToJobObject时,或者Job中的进程创建子进程,把进程内核对象挂入该表
    ERESOURCE JobLock;

    //
    // Accounting Info
    //

    LARGE_INTEGER TotalUserTime;
    LARGE_INTEGER TotalKernelTime;
    LARGE_INTEGER ThisPeriodTotalUserTime;
    LARGE_INTEGER ThisPeriodTotalKernelTime;   //统计已使用的用户和内核时间
    ULONG TotalPageFaultCount;   //统计页错误次数
    ULONG TotalProcesses;         //统计曾属于Job的进程数
    ULONG ActiveProcesses; //目前活动的进程数
    ULONG TotalTerminatedProcesses;//超出时间,终止了的进程数

    //
    // Limitable Attributes
    //

    LARGE_INTEGER PerProcessUserTimeLimit;  进程时间限制
    LARGE_INTEGER PerJobUserTimeLimit;   Job时间限制
    ULONG LimitFlags;          限制标志哪个起作用
    SIZE_T MinimumWorkingSetSize;
    SIZE_T MaximumWorkingSetSize;   //工作集
    ULONG ActiveProcessLimit;   //最大活动进程限制
    KAFFINITY Affinity;  //CPU集限制
    UCHAR PriorityClass;         //优先级
                            //对应JOBOBJECT_BASIC_LIMIT_INFORMATION
    //
    // UI restrictions
    //

    ULONG UIRestrictionsClass;   对应JOBOBJECT_BASIC_UI_RESTRICTIONS

    //
    // Security Limitations:  write once, read always
    //

    ULONG SecurityLimitFlags;
    PACCESS_TOKEN Token;
    PPS_JOB_TOKEN_FILTER Filter;                     对应JOBOBJECT_SECURITY_LIMIT_INFORMATION 
                                   
    //
    // End Of Job Time Limit
    //

    ULONG EndOfJobTimeAction;    对应JOBOBJECT_END_OF_JOB_TIME_INFORMATION
    PVOID CompletionPort;
    PVOID CompletionKey;    //对应JOBOBJECT_ASSOCIATE_COMPLETION_PORT
    ULONG SessionId;

    ULONG SchedulingClass;

    ULONGLONG ReadOperationCount;
    ULONGLONG WriteOperationCount;
    ULONGLONG OtherOperationCount;
    ULONGLONG ReadTransferCount;
    ULONGLONG WriteTransferCount;
    ULONGLONG OtherTransferCount;

    //
    // Extended Limits
    //

    IO_COUNTERS IoInfo;         // not used yet
    SIZE_T ProcessMemoryLimit;
    SIZE_T JobMemoryLimit;
    SIZE_T PeakProcessMemoryUsed;
    SIZE_T PeakJobMemoryUsed;
    SIZE_T CurrentJobMemoryUsed;                          对应JOBOBJECT_EXTENDED_LIMIT_INFORMATION

    KGUARDED_MUTEX MemoryLimitsLock;

    //
    // List of jobs in a job set. Processes within a job in a job set
    // can create processes in the same or higher members of the jobset.
    // Protected by the global lock PspJobListLock
    //

    LIST_ENTRY JobSetLinks;

    //
    // Member level for this job in the jobset.
    //

    ULONG MemberLevel;

    //
    // This job has had its last handle closed.
    //

#define PS_JOB_FLAGS_CLOSE_DONE 0x1UL

    ULONG JobFlags;
} EJOB;
typedef EJOB *PEJOB;


2、AssignProcessToJobObject


BOOL WINAPI AssignProcessToJobObject(
  __in  HANDLE hJob,
  __in  HANDLE hProcess
);

将一个进程与Job关联,进程的行为将受到Job中的限制,在MSDN的描述中有几项需要注意

  • 如果Job设置了时间限制并且时间已经耗尽,调用该函数失败进程也被终止,如果剩余的时间将要超出(剩余的时间小于调用该函数的所消耗的时间)进程终止,JOB将受到一个通知,如果Job设置了进程数限制且已经满了,函数失败进程终止
  • Job设置的内存限制,在调用该函数前对进程是不起作用的
  • 如果Job设置了安全限制,进程不能够满足,该函数调用失败,在将进程加入Job前应该以挂起的方式创建进程
  • 已经存在于一个Job中的进程,调用该函数失败,进程只能同时存在于一个Job中
  • 处于Job中的进程,在创建子进程的时候如果没有指定CREATE_BREAKAWAY_FROM_JOB 标志,那么子进程也处于该Job
  • 在开启UAC的系统中,没有提示权限的进程会被默认加入一个 兼容性Job,该Job是一个系统的,如不想这样使用CREATE_BREAKAWAY_FROM_JOB 创建进程,或者脱离UAC的控制

3、SetInformationJobObject

BOOL WINAPI SetInformationJobObject(
  __in  HANDLE hJob,
  __in  JOBOBJECTINFOCLASS JobObjectInfoClass, //枚举型型标识使用哪类限制
  __in  LPVOID lpJobObjectInfo,     //根据JobObjectInfoClass  ,使用对应的结构
  __in  DWORD cbJobObjectInfoLength //lpJobObjectInfo的大小
);
JOBOBJECTINFOCLASS 枚举值及所对应的lpJobObjectInfo指向的结构体


JobObjectAssociateCompletionPortInformation      The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_ASSOCIATE_COMPLETION_PORT structure. 
 
JobObjectBasicLimitInformation     The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_LIMIT_INFORMATION structure. 
 
JobObjectBasicUIRestrictions     The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_UI_RESTRICTIONS structure. 
 
JobObjectEndOfJobTimeInformation     The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure. 
 
JobObjectExtendedLimitInformation     The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. 
 
JobObjectSecurityLimitInformation    This flag is not supported. Applications must set security limitations individually for each process.


JOBOBJECT_BASIC_LIMIT_INFORMATION  基本的限制(包括每个进程的时间,Job时间,工作集,CPU集,调度优先级)具体参见MSDN

JOBOBJECT_EXTENDED_LIMIT_INFORMATION  在BASIC的基础上加了对内存的限制  参见MSDN

JOBOBJECT_BASIC_UI_RESTRICTIONS     对UI资源的限制,包括(创建桌面,设置显示,关机,原子表,获取窗口句柄,获取剪切板,设置系统参数)参见MSDN


MSDN中关于该函数有这样的描述


You must set security limitations individually for each process associated with a job object, rather than setting them for the job object itself. For information, see Process Security and Access Rights.  必须为每个进程单独的设置安全限制



4、 QueryInformationJobObject

BOOL WINAPI QueryInformationJobObject(
  __in_opt   HANDLE hJob,
  __in       JOBOBJECTINFOCLASS JobObjectInfoClass,
  __out      LPVOID lpJobObjectInfo,
  __in       DWORD cbJobObjectInfoLength,
  __out_opt  LPDWORD lpReturnLength
);


 改函数获取关于Job的限制信息,如果想要对限制的某一项单独设置,可以先用该函数获取之后,修改某项再传给SetInformationJobObject


如果为函数第二个参数传递JobObjectBasicAccountingInformation    对应的lpJobObjectInfo  应该为JOBOBJECT_BASIC_ACCOUNTING_INFORMATION


如果传递JobObjectBasicAndIoAccountingInformation  对应的lpJobObjectInfo  应该为JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION


如果传递JobObjectBasicProcessIdList     对应的lpJobObjectInfo  应该为 JOBOBJECT_BASIC_PROCESS_ID_LIST

具体参见MSDN


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐