Compare commits

...

1 Commits

Author SHA1 Message Date
David Wiesen
a85ad7bdc8 Fix Windows sandbox workspace SID restriction 2026-04-13 09:12:30 -07:00

View File

@@ -26,8 +26,10 @@ use windows_sys::Win32::Security::SetTokenInformation;
use windows_sys::Win32::Security::TokenDefaultDacl;
use windows_sys::Win32::Security::TokenGroups;
use windows_sys::Win32::Security::TokenUser;
use windows_sys::Win32::Security::ACL;
use windows_sys::Win32::Security::SID_AND_ATTRIBUTES;
use windows_sys::Win32::Security::TOKEN_USER;
use windows_sys::Win32::Security::TOKEN_ADJUST_DEFAULT;
use windows_sys::Win32::Security::TOKEN_ADJUST_PRIVILEGES;
use windows_sys::Win32::Security::TOKEN_ADJUST_SESSIONID;
@@ -250,6 +252,60 @@ pub unsafe fn get_logon_sid_bytes(h_token: HANDLE) -> Result<Vec<u8>> {
Err(anyhow!("Logon SID not present on token"))
}
pub unsafe fn get_user_sid_bytes(h_token: HANDLE) -> Result<Vec<u8>> {
let mut needed: u32 = 0;
GetTokenInformation(h_token, TokenUser, std::ptr::null_mut(), 0, &mut needed);
if needed == 0 {
return Err(anyhow!("TokenUser size query failed"));
}
let mut buf: Vec<u8> = vec![0u8; needed as usize];
let ok = GetTokenInformation(
h_token,
TokenUser,
buf.as_mut_ptr() as *mut c_void,
needed,
&mut needed,
);
if ok == 0 {
return Err(anyhow!("GetTokenInformation(TokenUser) failed"));
}
let user = std::ptr::read_unaligned(buf.as_ptr() as *const TOKEN_USER);
let sid_len = GetLengthSid(user.User.Sid);
if sid_len == 0 {
return Err(anyhow!("TokenUser SID length was zero"));
}
let mut out = vec![0u8; sid_len as usize];
if CopySid(sid_len, out.as_mut_ptr() as *mut c_void, user.User.Sid) == 0 {
return Err(anyhow!("CopySid(TokenUser) failed"));
}
Ok(out)
}
fn build_restricting_sid_order<'a>(
psid_capabilities: &'a [*mut c_void],
psid_logon: *mut c_void,
psid_user: *mut c_void,
) -> Vec<*mut c_void> {
let mut sids = Vec::with_capacity(psid_capabilities.len() + 2);
sids.extend_from_slice(psid_capabilities);
sids.push(psid_logon);
sids.push(psid_user);
sids
}
fn build_default_dacl_sid_order<'a>(
psid_capabilities: &'a [*mut c_void],
psid_logon: *mut c_void,
psid_user: *mut c_void,
) -> Vec<*mut c_void> {
let mut sids = Vec::with_capacity(psid_capabilities.len() + 2);
sids.push(psid_logon);
sids.push(psid_user);
sids.extend_from_slice(psid_capabilities);
sids
}
unsafe fn enable_single_privilege(h_token: HANDLE, name: &str) -> Result<()> {
let mut luid = LUID {
LowPart: 0,
@@ -335,21 +391,16 @@ unsafe fn create_token_with_caps_from(
}
let mut logon_sid_bytes = get_logon_sid_bytes(base_token)?;
let psid_logon = logon_sid_bytes.as_mut_ptr() as *mut c_void;
let mut everyone = world_sid()?;
let psid_everyone = everyone.as_mut_ptr() as *mut c_void;
let mut user_sid_bytes = get_user_sid_bytes(base_token)?;
let psid_user = user_sid_bytes.as_mut_ptr() as *mut c_void;
// Exact order: Capabilities..., Logon, Everyone
let mut entries: Vec<SID_AND_ATTRIBUTES> =
vec![std::mem::zeroed(); psid_capabilities.len() + 2];
for (i, psid) in psid_capabilities.iter().enumerate() {
// Exact order: Capabilities..., Logon, User
let restricting_sids = build_restricting_sid_order(psid_capabilities, psid_logon, psid_user);
let mut entries: Vec<SID_AND_ATTRIBUTES> = vec![std::mem::zeroed(); restricting_sids.len()];
for (i, psid) in restricting_sids.iter().enumerate() {
entries[i].Sid = *psid;
entries[i].Attributes = 0;
}
let logon_idx = psid_capabilities.len();
entries[logon_idx].Sid = psid_logon;
entries[logon_idx].Attributes = 0;
entries[logon_idx + 1].Sid = psid_everyone;
entries[logon_idx + 1].Attributes = 0;
let mut new_token: HANDLE = 0;
let flags = DISABLE_MAX_PRIVILEGE | LUA_TOKEN | WRITE_RESTRICTED;
@@ -368,12 +419,30 @@ unsafe fn create_token_with_caps_from(
return Err(anyhow!("CreateRestrictedToken failed: {}", GetLastError()));
}
let mut dacl_sids: Vec<*mut c_void> = Vec::with_capacity(psid_capabilities.len() + 2);
dacl_sids.push(psid_logon);
dacl_sids.push(psid_everyone);
dacl_sids.extend_from_slice(psid_capabilities);
let dacl_sids = build_default_dacl_sid_order(psid_capabilities, psid_logon, psid_user);
set_default_dacl(new_token, &dacl_sids)?;
enable_single_privilege(new_token, "SeChangeNotifyPrivilege")?;
Ok(new_token)
}
#[cfg(test)]
mod tests {
use super::build_default_dacl_sid_order;
use super::build_restricting_sid_order;
use std::ffi::c_void;
#[test]
fn restricted_sid_order_uses_user_instead_of_everyone() {
let capability_a = 0x1usize as *mut c_void;
let capability_b = 0x2usize as *mut c_void;
let logon = 0x3usize as *mut c_void;
let user = 0x4usize as *mut c_void;
let restricting = build_restricting_sid_order(&[capability_a, capability_b], logon, user);
let dacl = build_default_dacl_sid_order(&[capability_a, capability_b], logon, user);
assert_eq!(restricting, vec![capability_a, capability_b, logon, user]);
assert_eq!(dacl, vec![logon, user, capability_a, capability_b]);
}
}