feat: 完成扩展资源验收与同步服务部署
This commit is contained in:
@@ -60,13 +60,43 @@ impl Profile {
|
||||
/// 并须在整个启动期间持有已验证的包句柄。这里不使用递归继承,每个目录和文件都要分别检查、授权。
|
||||
/// 此操作只会添加一条 ACE,不会清理已有权限。
|
||||
pub fn grant_package_read_execute(&self, object: &std::fs::File) -> Result<()> {
|
||||
self.update_package_access(object, false)
|
||||
use windows_sys::Win32::Storage::FileSystem::{FILE_GENERIC_EXECUTE, FILE_GENERIC_READ};
|
||||
self.update_access(
|
||||
object,
|
||||
false,
|
||||
FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
|
||||
0,
|
||||
true,
|
||||
)
|
||||
}
|
||||
/// 授予当前实例修改其专用 scratch 目录及新建子对象的权限。
|
||||
pub fn grant_scratch_modify(&self, object: &std::fs::File) -> Result<()> {
|
||||
use windows_sys::Win32::{
|
||||
Security::SUB_CONTAINERS_AND_OBJECTS_INHERIT,
|
||||
Storage::FileSystem::{
|
||||
DELETE, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ, FILE_GENERIC_WRITE,
|
||||
},
|
||||
};
|
||||
self.update_access(
|
||||
object,
|
||||
false,
|
||||
FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE,
|
||||
SUB_CONTAINERS_AND_OBJECTS_INHERIT,
|
||||
false,
|
||||
)
|
||||
}
|
||||
/// 使用最初持有的对象句柄,仅移除这个新实例对应的允许 ACE;其他安全主体的 ACL 保持不变。
|
||||
pub fn revoke_package_access(&self, object: &std::fs::File) -> Result<()> {
|
||||
self.update_package_access(object, true)
|
||||
self.update_access(object, true, 0, 0, false)
|
||||
}
|
||||
fn update_package_access(&self, object: &std::fs::File, revoke: bool) -> Result<()> {
|
||||
fn update_access(
|
||||
&self,
|
||||
object: &std::fs::File,
|
||||
revoke: bool,
|
||||
permissions: u32,
|
||||
inheritance: u32,
|
||||
reject_hardlinks: bool,
|
||||
) -> Result<()> {
|
||||
// 跨并发实例序列化 Host 读/合并/写操作。
|
||||
let _lock = PACKAGE_ACL_LOCK
|
||||
.lock()
|
||||
@@ -77,7 +107,7 @@ impl Profile {
|
||||
Security::{Authorization::*, DACL_SECURITY_INFORMATION},
|
||||
Storage::FileSystem::{
|
||||
GetFileInformationByHandle, BY_HANDLE_FILE_INFORMATION,
|
||||
FILE_ATTRIBUTE_REPARSE_POINT, FILE_GENERIC_EXECUTE, FILE_GENERIC_READ,
|
||||
FILE_ATTRIBUTE_REPARSE_POINT,
|
||||
},
|
||||
};
|
||||
struct LocalAllocation(*mut core::ffi::c_void);
|
||||
@@ -99,7 +129,7 @@ impl Profile {
|
||||
{
|
||||
return Err(HostError::new("EXTENSION_CONTAINER_ACL_OBJECT_INVALID"));
|
||||
}
|
||||
if metadata.is_file() && !revoke {
|
||||
if metadata.is_file() && !revoke && reject_hardlinks {
|
||||
let mut info = BY_HANDLE_FILE_INFORMATION::default();
|
||||
if unsafe { GetFileInformationByHandle(object.as_raw_handle(), &mut info) } == 0
|
||||
|| info.nNumberOfLinks != 1
|
||||
@@ -127,9 +157,9 @@ impl Profile {
|
||||
return Err(HostError::new("EXTENSION_CONTAINER_ACL_FAILED"));
|
||||
}
|
||||
let entry = EXPLICIT_ACCESS_W {
|
||||
grfAccessPermissions: FILE_GENERIC_READ | FILE_GENERIC_EXECUTE,
|
||||
grfAccessPermissions: permissions,
|
||||
grfAccessMode: if revoke { REVOKE_ACCESS } else { GRANT_ACCESS },
|
||||
grfInheritance: 0,
|
||||
grfInheritance: inheritance,
|
||||
Trustee: TRUSTEE_W {
|
||||
TrusteeForm: TRUSTEE_IS_SID,
|
||||
TrusteeType: TRUSTEE_IS_UNKNOWN,
|
||||
@@ -973,7 +1003,7 @@ mod tests {
|
||||
mcp_modes.push("mcp_deadline");
|
||||
}
|
||||
if resources {
|
||||
mcp_modes.extend(["mcp_cpu", "mcp_memory", "mcp_processes"]);
|
||||
mcp_modes.extend(["mcp_cpu", "mcp_memory", "mcp_processes", "mcp_scratch"]);
|
||||
}
|
||||
for mode in mcp_modes {
|
||||
use std::sync::{
|
||||
@@ -1093,10 +1123,11 @@ mod tests {
|
||||
);
|
||||
assert!(session.take_tools_changed());
|
||||
}
|
||||
"mcp_cpu" | "mcp_memory" | "mcp_processes" => {
|
||||
"mcp_cpu" | "mcp_memory" | "mcp_processes" | "mcp_scratch" => {
|
||||
let expected = match mode {
|
||||
"mcp_memory" => "EXTENSION_RESOURCE_MEMORY_EXCEEDED",
|
||||
"mcp_processes" => "EXTENSION_RESOURCE_PROCESSES_EXCEEDED",
|
||||
"mcp_scratch" => "EXTENSION_RESOURCE_SCRATCH_EXCEEDED",
|
||||
_ => "EXTENSION_RESOURCE_CPU_EXCEEDED",
|
||||
};
|
||||
assert_eq!(result.unwrap_err().code, expected);
|
||||
|
||||
Reference in New Issue
Block a user