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 version: u32,
148 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}