caps/
base.rs

1use crate::errors::CapsError;
2use crate::nr;
3use crate::{CapSet, Capability, CapsHashSet};
4use std::io::Error;
5
6#[allow(clippy::unreadable_literal)]
7const CAPS_V3: u32 = 0x20080522;
8
9fn capget(hdr: &mut CapUserHeader, data: &mut CapUserData) -> Result<(), CapsError> {
10    let r = unsafe { libc::syscall(nr::CAPGET, hdr, data) };
11    match r {
12        0 => Ok(()),
13        _ => Err(format!("capget failure: {}", Error::last_os_error()).into()),
14    }
15}
16
17fn capset(hdr: &mut CapUserHeader, data: &CapUserData) -> Result<(), CapsError> {
18    let r = unsafe { libc::syscall(nr::CAPSET, hdr, data) };
19    match r {
20        0 => Ok(()),
21        _ => Err(format!("capset failure: {}", Error::last_os_error()).into()),
22    }
23}
24
25pub fn has_cap(tid: i32, cset: CapSet, cap: Capability) -> Result<bool, CapsError> {
26    let mut hdr = CapUserHeader {
27        version: CAPS_V3,
28        pid: tid,
29    };
30    let mut data: CapUserData = Default::default();
31    capget(&mut hdr, &mut data)?;
32    let caps: u64 = match cset {
33        CapSet::Effective => (u64::from(data.effective_s1) << 32) + u64::from(data.effective_s0),
34        CapSet::Inheritable => {
35            (u64::from(data.inheritable_s1) << 32) + u64::from(data.inheritable_s0)
36        }
37        CapSet::Permitted => (u64::from(data.permitted_s1) << 32) + u64::from(data.permitted_s0),
38        CapSet::Bounding | CapSet::Ambient => return Err("not a base set".into()),
39    };
40    let has_cap = (caps & cap.bitmask()) != 0;
41    Ok(has_cap)
42}
43
44pub fn clear(tid: i32, cset: CapSet) -> Result<(), CapsError> {
45    let mut hdr = CapUserHeader {
46        version: CAPS_V3,
47        pid: tid,
48    };
49    let mut data: CapUserData = Default::default();
50    capget(&mut hdr, &mut data)?;
51    match cset {
52        CapSet::Effective => {
53            data.effective_s0 = 0;
54            data.effective_s1 = 0;
55        }
56        CapSet::Inheritable => {
57            data.inheritable_s0 = 0;
58            data.inheritable_s1 = 0;
59        }
60        CapSet::Permitted => {
61            data.effective_s0 = 0;
62            data.effective_s1 = 0;
63            data.permitted_s0 = 0;
64            data.permitted_s1 = 0;
65        }
66        CapSet::Bounding | CapSet::Ambient => return Err("not a base set".into()),
67    }
68    capset(&mut hdr, &data)
69}
70
71pub fn read(tid: i32, cset: CapSet) -> Result<CapsHashSet, CapsError> {
72    let mut hdr = CapUserHeader {
73        version: CAPS_V3,
74        pid: tid,
75    };
76    let mut data: CapUserData = Default::default();
77    capget(&mut hdr, &mut data)?;
78    let caps: u64 = match cset {
79        CapSet::Effective => (u64::from(data.effective_s1) << 32) + u64::from(data.effective_s0),
80        CapSet::Inheritable => {
81            (u64::from(data.inheritable_s1) << 32) + u64::from(data.inheritable_s0)
82        }
83        CapSet::Permitted => (u64::from(data.permitted_s1) << 32) + u64::from(data.permitted_s0),
84        CapSet::Bounding | CapSet::Ambient => return Err("not a base set".into()),
85    };
86    let mut res = CapsHashSet::new();
87    for c in super::all() {
88        if (caps & c.bitmask()) != 0 {
89            res.insert(c);
90        }
91    }
92    Ok(res)
93}
94
95pub fn set(tid: i32, cset: CapSet, value: &CapsHashSet) -> Result<(), CapsError> {
96    let mut hdr = CapUserHeader {
97        version: CAPS_V3,
98        pid: tid,
99    };
100    let mut data: CapUserData = Default::default();
101    capget(&mut hdr, &mut data)?;
102    {
103        let (s1, s0) = match cset {
104            CapSet::Effective => (&mut data.effective_s1, &mut data.effective_s0),
105            CapSet::Inheritable => (&mut data.inheritable_s1, &mut data.inheritable_s0),
106            CapSet::Permitted => (&mut data.permitted_s1, &mut data.permitted_s0),
107            CapSet::Bounding | CapSet::Ambient => return Err("not a base set".into()),
108        };
109        *s1 = 0;
110        *s0 = 0;
111        for c in value {
112            match c.index() {
113                0..=31 => {
114                    *s0 |= c.bitmask() as u32;
115                }
116                32..=63 => {
117                    *s1 |= (c.bitmask() >> 32) as u32;
118                }
119                _ => return Err(format!("overlarge capability index {}", c.index()).into()),
120            }
121        }
122    }
123    capset(&mut hdr, &data)?;
124    Ok(())
125}
126
127pub fn drop(tid: i32, cset: CapSet, cap: Capability) -> Result<(), CapsError> {
128    let mut caps = read(tid, cset)?;
129    if caps.remove(&cap) {
130        set(tid, cset, &caps)?;
131    };
132    Ok(())
133}
134
135pub fn raise(tid: i32, cset: CapSet, cap: Capability) -> Result<(), CapsError> {
136    let mut caps = read(tid, cset)?;
137    if caps.insert(cap) {
138        set(tid, cset, &caps)?;
139    };
140    Ok(())
141}
142
143#[derive(Debug)]
144#[repr(C)]
145struct CapUserHeader {
146    // Linux capabilities version (runtime kernel support)
147    version: u32,
148    // Process ID (thread)
149    pid: i32,
150}
151
152#[derive(Debug, Default, Clone)]
153#[repr(C)]
154struct CapUserData {
155    effective_s0: u32,
156    permitted_s0: u32,
157    inheritable_s0: u32,
158    effective_s1: u32,
159    permitted_s1: u32,
160    inheritable_s1: u32,
161}