use alloc::sync::Arc;
use linux_raw_sys::general::{
CAP_CHOWN, CAP_FOWNER, CAP_LAST_CAP, CAP_NET_RAW, CAP_SETGID, CAP_SETPCAP, CAP_SETUID,
CAP_SYS_ADMIN, CAP_SYS_NICE, CAP_SYS_RESOURCE,
};
const CAP_MASK: u64 = (1u64 << (CAP_LAST_CAP + 1)) - 1;
fn cap_bit(cap: u32) -> u64 {
if cap <= CAP_LAST_CAP { 1u64 << cap } else { 0 }
}
#[derive(Clone, Debug)]
pub struct Cred {
pub uid: u32,
pub gid: u32,
pub euid: u32,
pub egid: u32,
pub suid: u32,
pub sgid: u32,
pub fsuid: u32,
pub fsgid: u32,
pub groups: Arc<[u32]>,
pub cap_inheritable: u64,
pub cap_permitted: u64,
pub cap_effective: u64,
pub cap_bounding: u64,
pub cap_ambient: u64,
}
impl Cred {
pub const fn cap_mask() -> u64 {
CAP_MASK
}
pub fn root() -> Self {
Self {
uid: 0,
gid: 0,
euid: 0,
egid: 0,
suid: 0,
sgid: 0,
fsuid: 0,
fsgid: 0,
groups: Arc::from([].as_slice()),
cap_inheritable: 0,
cap_permitted: CAP_MASK,
cap_effective: CAP_MASK,
cap_bounding: CAP_MASK,
cap_ambient: 0,
}
}
pub fn unprivileged(uid: u32, gid: u32) -> Self {
Self {
uid,
gid,
euid: uid,
egid: gid,
suid: uid,
sgid: gid,
fsuid: uid,
fsgid: gid,
groups: Arc::from([].as_slice()),
cap_inheritable: 0,
cap_permitted: 0,
cap_effective: 0,
cap_bounding: CAP_MASK,
cap_ambient: 0,
}
}
pub fn has_cap(&self, cap: u32) -> bool {
self.cap_effective & cap_bit(cap) != 0
}
pub fn apply_id_change_capability_rules(&mut self, old: &Self) {
let old_all_root = old.uid == 0 && old.euid == 0 && old.suid == 0;
let new_all_nonroot = self.uid != 0 && self.euid != 0 && self.suid != 0;
if old_all_root && new_all_nonroot {
self.cap_permitted = 0;
self.cap_effective = 0;
self.cap_ambient = 0;
} else if old.euid == 0 && self.euid != 0 {
self.cap_effective = 0;
self.cap_ambient = 0;
} else if old.euid != 0 && self.euid == 0 {
self.cap_effective = self.cap_permitted;
}
self.cap_permitted &= CAP_MASK;
self.cap_effective &= self.cap_permitted;
self.cap_inheritable &= CAP_MASK;
self.cap_bounding &= CAP_MASK;
self.cap_ambient &= self.cap_permitted & self.cap_inheritable;
}
pub fn sanitize_capabilities(&mut self) {
self.cap_inheritable &= CAP_MASK;
self.cap_permitted &= CAP_MASK;
self.cap_effective &= self.cap_permitted;
self.cap_bounding &= CAP_MASK;
self.cap_ambient &= self.cap_permitted & self.cap_inheritable;
}
pub fn has_cap_setuid(&self) -> bool {
self.has_cap(CAP_SETUID)
}
pub fn has_cap_setgid(&self) -> bool {
self.has_cap(CAP_SETGID)
}
pub fn has_cap_net_raw(&self) -> bool {
self.has_cap(CAP_NET_RAW)
}
pub fn has_cap_sys_nice(&self) -> bool {
self.has_cap(CAP_SYS_NICE)
}
pub fn has_cap_sys_resource(&self) -> bool {
self.has_cap(CAP_SYS_RESOURCE)
}
pub fn has_cap_sys_admin(&self) -> bool {
self.has_cap(CAP_SYS_ADMIN)
}
pub fn has_cap_sys_ptrace(&self) -> bool {
self.euid == 0
}
pub fn has_cap_chown(&self) -> bool {
self.has_cap(CAP_CHOWN)
}
pub fn has_cap_fowner(&self) -> bool {
self.has_cap(CAP_FOWNER)
}
pub fn has_cap_setpcap(&self) -> bool {
self.has_cap(CAP_SETPCAP)
}
pub fn in_group(&self, gid: u32) -> bool {
self.fsgid == gid || self.groups.contains(&gid)
}
}
impl Default for Cred {
fn default() -> Self {
Self::root()
}
}