本篇主要说下沙箱的job:
一、JobLevel
// The Job level specifies a set of decreasing security profiles for the
// Job object that the target process will be placed into.
// This table summarizes the security associated with each level:
//
// JobLevel |General |Quota |
// |restrictions |restrictions |
// -----------------|---------------------------------- |--------------------|
// kUnprotected | None | *Kill on Job close.|
// -----------------|---------------------------------- |--------------------|
// kInteractive | *Forbid system-wide changes using | |
// | SystemParametersInfo(). | *Kill on Job close.|
// | *Forbid the creation/switch of | |
// | Desktops. | |
// | *Forbids calls to ExitWindows(). | |
// -----------------|---------------------------------- |--------------------|
// kLimitedUser | Same as kInteractive plus: | *One active process|
// | *Forbid changes to the display | limit. |
// | settings. | *Kill on Job close.|
// -----------------|---------------------------------- |--------------------|
// kLockdown | Same as kLimitedUser plus: | *One active process|
// | * No read/write to the clipboard. | limit. |
// | * No access to User Handles that | *Kill on Job close.|
// | belong to other processes. | *Kill on unhandled |
// | * Forbid message broadcasts. | exception. |
// | * Forbid setting global hooks. | |
// | * No access to the global atoms | |
// | table. | |
// -----------------|-----------------------------------|--------------------|
//
// In the context of the above table, 'user handles' refers to the handles of
// windows, bitmaps, menus, etc. Files, treads and registry handles are kernel
// handles and are not affected by the job level settings.
enum class JobLevel { kLockdown = 0, kLimitedUser, kInteractive, kUnprotected };
二、job策略实现:
sandbox\win\src\job.h
sandbox\win\src\job.cc
例子:
// Job job;
// job.Init(JobLevel::kLockdown, 0, 0);
namespace sandbox {
Job::Job() = default;
Job::~Job() = default;
DWORD Job::Init(JobLevel security_level,
DWORD ui_exceptions,
size_t memory_limit) {
if (job_handle_.is_valid())
return ERROR_ALREADY_INITIALIZED;
job_handle_.Set(::CreateJobObject(nullptr, nullptr));
if (!job_handle_.is_valid())
return ::GetLastError();
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {};
// Set the settings for the different security levels. Note: The higher levels
// inherit from the lower levels.
switch (security_level) {
case JobLevel::kLockdown: {
jeli.BasicLimitInformation.LimitFlags |=
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_READCLIPBOARD;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_GLOBALATOMS;
[[fallthrough]];
}
case JobLevel::kLimitedUser: {
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DISPLAYSETTINGS;
jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
jeli.BasicLimitInformation.ActiveProcessLimit = 1;
[[fallthrough]];
}
case JobLevel::kInteractive: {
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_DESKTOP;
jbur.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_EXITWINDOWS;
[[fallthrough]];
}
case JobLevel::kUnprotected: {
if (memory_limit) {
jeli.BasicLimitInformation.LimitFlags |=
JOB_OBJECT_LIMIT_PROCESS_MEMORY;
jeli.ProcessMemoryLimit = memory_limit;
}
jeli.BasicLimitInformation.LimitFlags |=
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
break;
}
}
if (!::SetInformationJobObject(job_handle_.Get(),
JobObjectExtendedLimitInformation, &jeli,
sizeof(jeli))) {
return ::GetLastError();
}
jbur.UIRestrictionsClass = jbur.UIRestrictionsClass & (~ui_exceptions);
if (!::SetInformationJobObject(job_handle_.Get(),
JobObjectBasicUIRestrictions, &jbur,
sizeof(jbur))) {
return ::GetLastError();
}
return ERROR_SUCCESS;
}
bool Job::IsValid() {
return job_handle_.is_valid();
}
HANDLE Job::GetHandle() {
return job_handle_.get();
}
DWORD Job::SetActiveProcessLimit(DWORD processes) {
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};
if (!job_handle_.is_valid())
return ERROR_NO_DATA;
if (!::QueryInformationJobObject(job_handle_.get(),
JobObjectExtendedLimitInformation, &jeli,
sizeof(jeli), nullptr)) {
return ::GetLastError();
}
jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS;
jeli.BasicLimitInformation.ActiveProcessLimit = processes;
if (!::SetInformationJobObject(job_handle_.get(),
JobObjectExtendedLimitInformation, &jeli,
sizeof(jeli))) {
return ::GetLastError();
}
return ERROR_SUCCESS;
}
} // namespace sandbox
三、初始化job流程:
1、使用CrateJobObject函数,创建一个作业
2、使用SetInformationJobObject函数,为作业添加限制条件。
BOOL SetInformationJobObject(
[in] HANDLE hJob,
[in] JOBOBJECTINFOCLASS JobObjectInformationClass,
[in] LPVOID lpJobObjectInformation,
[in] DWORD cbJobObjectInformationLength
);
更多参考:SetInformationJobObject 函数 (jobapi2.h) - Win32 apps | Microsoft Learn
3、设置作业限制内容:
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {};【定义见 “附”】
JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {}; 【定义见 “附”】
SetInformationJobObject(job_handle_.Get(),
JobObjectExtendedLimitInformation, &jeli,
sizeof(jeli));//包含作业对象的基本限制信
::SetInformationJobObject(job_handle_.Get(),
JobObjectBasicUIRestrictions, &jbur,
sizeof(jbur)) ;//包含作业对象的基本用户界面限制。
这样根据策略规则设置好job即可,应用到进程创建:
四、附:
1)、JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; //包含作业对象的基本限制信息。
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
LARGE_INTEGER PerProcessUserTimeLimit;
LARGE_INTEGER PerJobUserTimeLimit;
DWORD LimitFlags;
SIZE_T MinimumWorkingSetSize;
SIZE_T MaximumWorkingSetSize;
DWORD ActiveProcessLimit;
ULONG_PTR Affinity;
DWORD PriorityClass;
DWORD SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;
值 | 含义 |
---|---|
JOB_OBJECT_LIMIT_ACTIVE_PROCESS 0x00000008 | 建立与作业关联的同时活动进程的最大数目。 ActiveProcessLimit 成员包含其他信息。 |
JOB_OBJECT_LIMIT_AFFINITY 0x00000010 | 导致与作业关联的所有进程使用相同的处理器相关性。 Affinity 成员包含其他信息。 如果作业是嵌套的,则指定的处理器相关性必须是父作业有效相关性的子集。 如果指定的相关性是父作业相关性的超集,则忽略该关联并使用父作业的相关性。 |
JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800 | 如果与此限制生效时,与作业关联的任何进程使用 CREATE_BREAKAWAY_FROM_JOB 标志创建子进程,则子进程不与作业关联。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 |
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400 | 对与作业关联的每个进程强制调用具有 SEM_NOGPFAULTERRORBOX 标志的 SetErrorMode 函数。 如果发生异常,并且系统调用 UnhandledExceptionFilter 函数,则调试器将有机会执行操作。如果没有调试器,则函数返回 EXCEPTION_EXECUTE_HANDLER。 通常,这将导致进程终止,异常代码为退出状态。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 |
JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200 | 使与作业关联的所有进程限制其已提交内存的作业范围总和。 当进程尝试提交超出作业范围限制的内存时,它将失败。 如果作业对象与完成端口相关联, 则会将JOB_OBJECT_MSG_JOB_MEMORY_LIMIT 消息发送到完成端口。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 若要在允许进程继续提交内存的情况下注册超过此限制时的通知,请将 SetInformationJobObject 函数与 JobObjectNotificationLimitInformation 信息类一起使用。 |
JOB_OBJECT_LIMIT_JOB_TIME 0x00000004 | 为作业建立用户模式执行时间限制。 PerJobUserTimeLimit 成员包含其他信息。 此标志不能与 JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME一起使用。 |
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000 | 导致与作业关联的所有进程在关闭作业的最后一个句柄时终止。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 |
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME 0x00000040 | 保留之前设置的任何作业时间限制。 只要设置了此标志,就可以建立每个作业的时间限制一次,然后在后续调用中更改其他限制。 此标志不能与 JOB_OBJECT_LIMIT_JOB_TIME一起使用。 |
JOB_OBJECT_LIMIT_PRIORITY_CLASS 0x00000020 | 使与作业关联的所有进程使用相同的优先级类。 有关详细信息,请参阅 计划优先级。 PriorityClass 成员包含其他信息。 如果作业是嵌套的,则有效优先级类是作业链中优先级最低的类。 |
JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100 | 使与作业关联的所有进程限制其提交的内存。 当进程尝试提交超出每个进程限制的内存时,它将失败。 如果作业对象与完成端口相关联, 则会将JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT 消息发送到完成端口。 如果作业是嵌套的,则有效内存限制是作业链中限制最严格的内存限制。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 |
JOB_OBJECT_LIMIT_PROCESS_TIME 0x00000002 | 为每个当前处于活动状态的进程以及与作业关联的所有未来进程建立用户模式执行时间限制。 PerProcessUserTimeLimit 成员包含其他信息。 |
JOB_OBJECT_LIMIT_SCHEDULING_CLASS 0x00000080 | 使作业中的所有进程都使用相同的计划类。 SchedulingClass 成员包含其他信息。 如果作业是嵌套的,则有效的计划类是作业链中最低的计划类。 |
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000 | 允许与作业关联的任何进程创建不与作业关联的子进程。 如果作业是嵌套的,并且其直接作业对象允许分离,则子进程会脱离直接作业对象和父作业链中的每个作业,向上移动层次结构,直到到达不允许分离的作业。 如果直接作业对象不允许分离,即使父作业链中的作业允许它,子进程也不会中断。 此限制需要使用 JOBOBJECT_EXTENDED_LIMIT_INFORMATION 结构。 其 BasicLimitInformation 成员是 JOBOBJECT_BASIC_LIMIT_INFORMATION 结构。 |
JOB_OBJECT_LIMIT_SUBSET_AFFINITY 0x00004000 | 允许进程对与作业关联的所有进程使用处理器相关性的子集。 此值必须与 JOB_OBJECT_LIMIT_AFFINITY 组合使用。 Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP: 从 Windows 7 和 Windows Server 2008 R2 开始支持此标志。 |
JOB_OBJECT_LIMIT_WORKINGSET 0x00000001 | 导致与作业关联的所有进程使用相同的最小和最大工作集大小。 MinimumWorkingSetSize 和 MaximumWorkingSetSize 成员包含其他信息。 如果作业是嵌套的,则有效工作集大小是作业链中最小的工作集大小。 |
更多参考:JOBOBJECT_BASIC_LIMIT_INFORMATION (winnt.h) - Win32 apps | Microsoft Learn
2)、JOBOBJECT_BASIC_UI_RESTRICTIONS jbur = {}; //包含作业对象的基本用户界面限制。
typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS {
DWORD UIRestrictionsClass;
} JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;
JOB_OBJECT_UILIMIT_DESKTOP 0x00000040 | 防止与作业关联的进程使用 CreateDesktop 和 SwitchDesktop 函数创建桌面和切换桌面。 |
JOB_OBJECT_UILIMIT_DISPLAYSETTINGS 0x00000010 | 阻止与作业关联的进程调用 ChangeDisplaySettings 函数。 |
JOB_OBJECT_UILIMIT_EXITWINDOWS 0x00000080 | 阻止与作业关联的进程调用 ExitWindows 或 ExitWindowsEx 函数。 |
JOB_OBJECT_UILIMIT_GLOBALATOMS 0x00000020 | 阻止与作业关联的进程访问全局原子。 使用此标志时,每个作业都有自己的 atom 表。 |
JOB_OBJECT_UILIMIT_HANDLES 0x00000001 | 防止与作业关联的进程使用不与同一作业关联的进程拥有的 USER 句柄。 |
JOB_OBJECT_UILIMIT_READCLIPBOARD 0x00000002 | 防止与作业关联的进程从剪贴板读取数据。 |
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS 0x00000008 | 防止与作业关联的进程使用 SystemParametersInfo 函数更改系统参数。 |
JOB_OBJECT_UILIMIT_WRITECLIPBOARD 0x00000004 | 防止与作业关联的进程将数据写入剪贴板。 |
更多参考:JOBOBJECT_BASIC_UI_RESTRICTIONS (winnt.h) - Win32 apps | Microsoft Learn
五、看下浏览器进程的作业情况截图:
1、net进程收沙箱控制有job限制:
2、主进程不受沙箱控制无job限制:
3、GPU进程受沙箱控制有job限制:
限制了 进程内存 激活进程权限
4、storage service进程受沙箱job限制:
限制了 桌面 激活进程 内存大小 退出系统 读写剪切板 管理员权限等内容。
5、备用渲染进程受沙箱job限制:
限制了 桌面 激活进程 内存大小 退出系统 读写剪切板 管理员权限等内容。
6、新标签进程受沙箱job限制:
限制了 桌面 激活进程 内存大小 退出系统 读写剪切板 管理员权限等内容。
7、辅助框架进程受沙箱job限制:
限制了 桌面 激活进程 内存大小 退出系统 读写剪切板 管理员权限等内容。
六、总结:
主要是利用SetInformationJobObject设置作业对象的基本限制信和作业对象的基本用户界面限制。最后在创建进程的时候将作业信息与子进程绑定。
标签:job,OBJECT,作业,JOB,Sandbox,源码,LIMIT,进程,沙盒 From: https://blog.csdn.net/jangdong/article/details/143159058