add a default dacl to restricted token to enable reading of pipes (#8280)

this fixes sandbox errors (legacy and elevated) for commands that
include pipes, which the model often favors.
This commit is contained in:
iceweasel-oai
2025-12-18 12:59:52 -08:00
committed by GitHub
parent df46ea48a2
commit 6395430220

View File

@@ -4,17 +4,29 @@ use anyhow::Result;
use std::ffi::c_void;
use windows_sys::Win32::Foundation::CloseHandle;
use windows_sys::Win32::Foundation::GetLastError;
use windows_sys::Win32::Foundation::LocalFree;
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Foundation::HLOCAL;
use windows_sys::Win32::Foundation::LUID;
use windows_sys::Win32::Security::AdjustTokenPrivileges;
use windows_sys::Win32::Security::Authorization::SetEntriesInAclW;
use windows_sys::Win32::Security::Authorization::EXPLICIT_ACCESS_W;
use windows_sys::Win32::Security::Authorization::GRANT_ACCESS;
use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_SID;
use windows_sys::Win32::Security::Authorization::TRUSTEE_IS_UNKNOWN;
use windows_sys::Win32::Security::Authorization::TRUSTEE_W;
use windows_sys::Win32::Security::CopySid;
use windows_sys::Win32::Security::CreateRestrictedToken;
use windows_sys::Win32::Security::CreateWellKnownSid;
use windows_sys::Win32::Security::GetLengthSid;
use windows_sys::Win32::Security::GetTokenInformation;
use windows_sys::Win32::Security::LookupPrivilegeValueW;
use windows_sys::Win32::Security::SetTokenInformation;
use windows_sys::Win32::Security::TokenDefaultDacl;
use windows_sys::Win32::Security::TokenGroups;
use windows_sys::Win32::Security::ACL;
use windows_sys::Win32::Security::SID_AND_ATTRIBUTES;
use windows_sys::Win32::Security::TOKEN_ADJUST_DEFAULT;
use windows_sys::Win32::Security::TOKEN_ADJUST_PRIVILEGES;
@@ -28,9 +40,71 @@ use windows_sys::Win32::System::Threading::GetCurrentProcess;
const DISABLE_MAX_PRIVILEGE: u32 = 0x01;
const LUA_TOKEN: u32 = 0x04;
const WRITE_RESTRICTED: u32 = 0x08;
const GENERIC_ALL: u32 = 0x1000_0000;
const WIN_WORLD_SID: i32 = 1;
const SE_GROUP_LOGON_ID: u32 = 0xC0000000;
#[repr(C)]
struct TokenDefaultDaclInfo {
default_dacl: *mut ACL,
}
/// Sets a permissive default DACL so sandboxed processes can create pipes/IPC objects
/// without hitting ACCESS_DENIED when PowerShell builds pipelines.
unsafe fn set_default_dacl(h_token: HANDLE, sids: &[*mut c_void]) -> Result<()> {
if sids.is_empty() {
return Ok(());
}
let entries: Vec<EXPLICIT_ACCESS_W> = sids
.iter()
.map(|sid| EXPLICIT_ACCESS_W {
grfAccessPermissions: GENERIC_ALL,
grfAccessMode: GRANT_ACCESS,
grfInheritance: 0,
Trustee: TRUSTEE_W {
pMultipleTrustee: std::ptr::null_mut(),
MultipleTrusteeOperation: 0,
TrusteeForm: TRUSTEE_IS_SID,
TrusteeType: TRUSTEE_IS_UNKNOWN,
ptstrName: *sid as *mut u16,
},
})
.collect();
let mut p_new_dacl: *mut ACL = std::ptr::null_mut();
let res = SetEntriesInAclW(
entries.len() as u32,
entries.as_ptr(),
std::ptr::null_mut(),
&mut p_new_dacl,
);
if res != ERROR_SUCCESS {
return Err(anyhow!("SetEntriesInAclW failed: {}", res));
}
let mut info = TokenDefaultDaclInfo {
default_dacl: p_new_dacl,
};
let ok = SetTokenInformation(
h_token,
TokenDefaultDacl,
&mut info as *mut _ as *mut c_void,
std::mem::size_of::<TokenDefaultDaclInfo>() as u32,
);
if ok == 0 {
let err = GetLastError();
if !p_new_dacl.is_null() {
LocalFree(p_new_dacl as HLOCAL);
}
return Err(anyhow!(
"SetTokenInformation(TokenDefaultDacl) failed: {}",
err
));
}
if !p_new_dacl.is_null() {
LocalFree(p_new_dacl as HLOCAL);
}
Ok(())
}
pub unsafe fn world_sid() -> Result<Vec<u8>> {
let mut size: u32 = 0;
CreateWellKnownSid(
@@ -267,6 +341,7 @@ pub unsafe fn create_workspace_write_token_with_cap_from(
if ok == 0 {
return Err(anyhow!("CreateRestrictedToken failed: {}", GetLastError()));
}
set_default_dacl(new_token, &[psid_logon, psid_everyone, psid_capability])?;
enable_single_privilege(new_token, "SeChangeNotifyPrivilege")?;
Ok((new_token, psid_capability))
}
@@ -305,6 +380,7 @@ pub unsafe fn create_readonly_token_with_cap_from(
if ok == 0 {
return Err(anyhow!("CreateRestrictedToken failed: {}", GetLastError()));
}
set_default_dacl(new_token, &[psid_logon, psid_everyone, psid_capability])?;
enable_single_privilege(new_token, "SeChangeNotifyPrivilege")?;
Ok((new_token, psid_capability))
}