Skip to content

Commit d9429b5

Browse files
authored
Add cap{get,set} syscalls (#514)
Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
1 parent 2a721e2 commit d9429b5

File tree

7 files changed

+279
-84
lines changed

7 files changed

+279
-84
lines changed

src/backend/libc/thread/syscalls.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::super::c;
44
use super::super::conv::ret;
55
#[cfg(any(target_os = "android", target_os = "linux"))]
6-
use super::super::conv::{borrowed_fd, ret_c_int};
6+
use super::super::conv::{borrowed_fd, ret_c_int, syscall_ret};
77
use super::super::time::types::LibcTimespec;
88
#[cfg(any(target_os = "android", target_os = "linux"))]
99
use crate::fd::BorrowedFd;
@@ -299,3 +299,23 @@ pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
299299
pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
300300
unsafe { ret(c::unshare(flags.bits() as i32)) }
301301
}
302+
303+
#[cfg(any(target_os = "android", target_os = "linux"))]
304+
#[inline]
305+
pub(crate) fn capget(
306+
header: &mut linux_raw_sys::general::__user_cap_header_struct,
307+
data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
308+
) -> io::Result<()> {
309+
let header: *mut _ = header;
310+
unsafe { syscall_ret(c::syscall(c::SYS_capget, header, data.as_mut_ptr())) }
311+
}
312+
313+
#[cfg(any(target_os = "android", target_os = "linux"))]
314+
#[inline]
315+
pub(crate) fn capset(
316+
header: &mut linux_raw_sys::general::__user_cap_header_struct,
317+
data: &[linux_raw_sys::general::__user_cap_data_struct],
318+
) -> io::Result<()> {
319+
let header: *mut _ = header;
320+
unsafe { syscall_ret(c::syscall(c::SYS_capset, header, data.as_ptr())) }
321+
}

src/backend/linux_raw/thread/syscalls.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,23 @@ pub(crate) fn setns(fd: BorrowedFd, nstype: c::c_int) -> io::Result<c::c_int> {
294294
pub(crate) fn unshare(flags: crate::thread::UnshareFlags) -> io::Result<()> {
295295
unsafe { ret(syscall_readonly!(__NR_unshare, c_uint(flags.bits()))) }
296296
}
297+
298+
#[cfg(any(target_os = "android", target_os = "linux"))]
299+
#[inline]
300+
pub(crate) fn capget(
301+
header: &mut linux_raw_sys::general::__user_cap_header_struct,
302+
data: &mut [MaybeUninit<linux_raw_sys::general::__user_cap_data_struct>],
303+
) -> io::Result<()> {
304+
let header: *mut _ = header;
305+
unsafe { ret(syscall!(__NR_capget, header, data.as_mut_ptr())) }
306+
}
307+
308+
#[cfg(any(target_os = "android", target_os = "linux"))]
309+
#[inline]
310+
pub(crate) fn capset(
311+
header: &mut linux_raw_sys::general::__user_cap_header_struct,
312+
data: &[linux_raw_sys::general::__user_cap_data_struct],
313+
) -> io::Result<()> {
314+
let header: *mut _ = header;
315+
unsafe { ret(syscall!(__NR_capset, header, data.as_ptr())) }
316+
}

src/thread/libcap.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
use bitflags::bitflags;
2+
use core::mem::MaybeUninit;
3+
4+
use crate::process::Pid;
5+
use crate::{backend, io};
6+
7+
/// `__user_cap_data_struct`
8+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9+
pub struct CapabilitySets {
10+
/// `__user_cap_data_struct.effective`
11+
pub effective: CapabilityFlags,
12+
/// `__user_cap_data_struct.permitted`
13+
pub permitted: CapabilityFlags,
14+
/// `__user_cap_data_struct.inheritable`
15+
pub inheritable: CapabilityFlags,
16+
}
17+
18+
bitflags! {
19+
/// `CAP_*` constants.
20+
pub struct CapabilityFlags: u64 {
21+
/// `CAP_CHOWN`
22+
const CHOWN = 1 << linux_raw_sys::general::CAP_CHOWN;
23+
/// `CAP_DAC_OVERRIDE`
24+
const DAC_OVERRIDE = 1 << linux_raw_sys::general::CAP_DAC_OVERRIDE;
25+
/// `CAP_DAC_READ_SEARCH`
26+
const DAC_READ_SEARCH = 1 << linux_raw_sys::general::CAP_DAC_READ_SEARCH;
27+
/// `CAP_FOWNER`
28+
const FOWNER = 1 << linux_raw_sys::general::CAP_FOWNER;
29+
/// `CAP_FSETID`
30+
const FSETID = 1 << linux_raw_sys::general::CAP_FSETID;
31+
/// `CAP_KILL`
32+
const KILL = 1 << linux_raw_sys::general::CAP_KILL;
33+
/// `CAP_SETGID`
34+
const SETGID = 1 << linux_raw_sys::general::CAP_SETGID;
35+
/// `CAP_SETUID`
36+
const SETUID = 1 << linux_raw_sys::general::CAP_SETUID;
37+
/// `CAP_SETPCAP`
38+
const SETPCAP = 1 << linux_raw_sys::general::CAP_SETPCAP;
39+
/// `CAP_LINUX_IMMUTABLE`
40+
const LINUX_IMMUTABLE = 1 << linux_raw_sys::general::CAP_LINUX_IMMUTABLE;
41+
/// `CAP_NET_BIND_SERVICE`
42+
const NET_BIND_SERVICE = 1 << linux_raw_sys::general::CAP_NET_BIND_SERVICE;
43+
/// `CAP_NET_BROADCAST`
44+
const NET_BROADCAST = 1 << linux_raw_sys::general::CAP_NET_BROADCAST;
45+
/// `CAP_NET_ADMIN`
46+
const NET_ADMIN = 1 << linux_raw_sys::general::CAP_NET_ADMIN;
47+
/// `CAP_NET_RAW`
48+
const NET_RAW = 1 << linux_raw_sys::general::CAP_NET_RAW;
49+
/// `CAP_IPC_LOCK`
50+
const IPC_LOCK = 1 << linux_raw_sys::general::CAP_IPC_LOCK;
51+
/// `CAP_IPC_OWNER`
52+
const IPC_OWNER = 1 << linux_raw_sys::general::CAP_IPC_OWNER;
53+
/// `CAP_SYS_MODULE`
54+
const SYS_MODULE = 1 << linux_raw_sys::general::CAP_SYS_MODULE;
55+
/// `CAP_SYS_RAWIO`
56+
const SYS_RAWIO = 1 << linux_raw_sys::general::CAP_SYS_RAWIO;
57+
/// `CAP_SYS_CHROOT`
58+
const SYS_CHROOT = 1 << linux_raw_sys::general::CAP_SYS_CHROOT;
59+
/// `CAP_SYS_PTRACE`
60+
const SYS_PTRACE = 1 << linux_raw_sys::general::CAP_SYS_PTRACE;
61+
/// `CAP_SYS_PACCT`
62+
const SYS_PACCT = 1 << linux_raw_sys::general::CAP_SYS_PACCT;
63+
/// `CAP_SYS_ADMIN`
64+
const SYS_ADMIN = 1 << linux_raw_sys::general::CAP_SYS_ADMIN;
65+
/// `CAP_SYS_BOOT`
66+
const SYS_BOOT = 1 << linux_raw_sys::general::CAP_SYS_BOOT;
67+
/// `CAP_SYS_NICE`
68+
const SYS_NICE = 1 << linux_raw_sys::general::CAP_SYS_NICE;
69+
/// `CAP_SYS_RESOURCE`
70+
const SYS_RESOURCE = 1 << linux_raw_sys::general::CAP_SYS_RESOURCE;
71+
/// `CAP_SYS_TIME`
72+
const SYS_TIME = 1 << linux_raw_sys::general::CAP_SYS_TIME;
73+
/// `CAP_SYS_TTY_CONFIG`
74+
const SYS_TTY_CONFIG = 1 << linux_raw_sys::general::CAP_SYS_TTY_CONFIG;
75+
/// `CAP_MKNOD`
76+
const MKNOD = 1 << linux_raw_sys::general::CAP_MKNOD;
77+
/// `CAP_LEASE`
78+
const LEASE = 1 << linux_raw_sys::general::CAP_LEASE;
79+
/// `CAP_AUDIT_WRITE`
80+
const AUDIT_WRITE = 1 << linux_raw_sys::general::CAP_AUDIT_WRITE;
81+
/// `CAP_AUDIT_CONTROL`
82+
const AUDIT_CONTROL = 1 << linux_raw_sys::general::CAP_AUDIT_CONTROL;
83+
/// `CAP_SETFCAP`
84+
const SETFCAP = 1 << linux_raw_sys::general::CAP_SETFCAP;
85+
/// `CAP_MAC_OVERRIDE`
86+
const MAC_OVERRIDE = 1 << linux_raw_sys::general::CAP_MAC_OVERRIDE;
87+
/// `CAP_MAC_ADMIN`
88+
const MAC_ADMIN = 1 << linux_raw_sys::general::CAP_MAC_ADMIN;
89+
/// `CAP_SYSLOG`
90+
const SYSLOG = 1 << linux_raw_sys::general::CAP_SYSLOG;
91+
/// `CAP_WAKE_ALARM`
92+
const WAKE_ALARM = 1 << linux_raw_sys::general::CAP_WAKE_ALARM;
93+
/// `CAP_BLOCK_SUSPEND`
94+
const BLOCK_SUSPEND = 1 << linux_raw_sys::general::CAP_BLOCK_SUSPEND;
95+
/// `CAP_AUDIT_READ`
96+
const AUDIT_READ = 1 << linux_raw_sys::general::CAP_AUDIT_READ;
97+
/// `CAP_PERFMON`
98+
const PERFMON = 1 << linux_raw_sys::general::CAP_PERFMON;
99+
/// `CAP_BPF`
100+
const BPF = 1 << linux_raw_sys::general::CAP_BPF;
101+
/// `CAP_CHECKPOINT_RESTORE`
102+
const CHECKPOINT_RESTORE = 1 << linux_raw_sys::general::CAP_CHECKPOINT_RESTORE;
103+
}
104+
}
105+
106+
/// `capget(_LINUX_CAPABILITY_VERSION_3, pid)`
107+
///
108+
/// # References
109+
/// - [Linux]
110+
///
111+
/// [Linux]: https://man7.org/linux/man-pages/man2/capget.2.html
112+
#[inline]
113+
#[doc(alias = "capget")]
114+
pub fn capabilities(pid: Option<Pid>) -> io::Result<CapabilitySets> {
115+
capget(pid)
116+
}
117+
118+
/// `capset(_LINUX_CAPABILITY_VERSION_3, pid, effective, permitted, inheritable)`
119+
///
120+
/// # References
121+
/// - [Linux]
122+
///
123+
/// [Linux]: https://man7.org/linux/man-pages/man2/capget.2.html
124+
#[inline]
125+
#[doc(alias = "capset")]
126+
pub fn set_capabilities(pid: Option<Pid>, sets: CapabilitySets) -> io::Result<()> {
127+
capset(pid, sets)
128+
}
129+
130+
#[inline]
131+
#[allow(unsafe_code)]
132+
fn capget(pid: Option<Pid>) -> io::Result<CapabilitySets> {
133+
let mut data = [MaybeUninit::<linux_raw_sys::general::__user_cap_data_struct>::uninit(); 2];
134+
135+
let data = {
136+
let mut header = linux_raw_sys::general::__user_cap_header_struct {
137+
version: linux_raw_sys::general::_LINUX_CAPABILITY_VERSION_3,
138+
pid: Pid::as_raw(pid) as backend::c::c_int,
139+
};
140+
141+
backend::thread::syscalls::capget(&mut header, &mut data)?;
142+
// SAFETY: v3 is a 64-bit implementation, so the kernel filled in both data structs.
143+
unsafe { (data[0].assume_init(), data[1].assume_init()) }
144+
};
145+
146+
{
147+
// TODO: With Rust 1.53, we can use u32::BITS in the shifts.
148+
const BITS: u32 = 32;
149+
let effective = u64::from(data.0.effective) | (u64::from(data.1.effective) << BITS);
150+
let permitted = u64::from(data.0.permitted) | (u64::from(data.1.permitted) << BITS);
151+
let inheritable = u64::from(data.0.inheritable) | (u64::from(data.1.inheritable) << BITS);
152+
153+
// SAFETY: the kernel returns a partitioned bitset that we just combined above
154+
Ok(CapabilitySets {
155+
effective: unsafe { CapabilityFlags::from_bits_unchecked(effective) },
156+
permitted: unsafe { CapabilityFlags::from_bits_unchecked(permitted) },
157+
inheritable: unsafe { CapabilityFlags::from_bits_unchecked(inheritable) },
158+
})
159+
}
160+
}
161+
162+
#[inline]
163+
fn capset(pid: Option<Pid>, sets: CapabilitySets) -> io::Result<()> {
164+
// TODO: With Rust 1.53, we can use u32::BITS in the shifts.
165+
const BITS: u32 = 32;
166+
167+
let mut header = linux_raw_sys::general::__user_cap_header_struct {
168+
version: linux_raw_sys::general::_LINUX_CAPABILITY_VERSION_3,
169+
pid: Pid::as_raw(pid) as backend::c::c_int,
170+
};
171+
let data = [
172+
linux_raw_sys::general::__user_cap_data_struct {
173+
effective: sets.effective.bits() as u32,
174+
permitted: sets.permitted.bits() as u32,
175+
inheritable: sets.inheritable.bits() as u32,
176+
},
177+
linux_raw_sys::general::__user_cap_data_struct {
178+
effective: (sets.effective.bits() >> BITS) as u32,
179+
permitted: (sets.permitted.bits() >> BITS) as u32,
180+
inheritable: (sets.inheritable.bits() >> BITS) as u32,
181+
},
182+
];
183+
184+
backend::thread::syscalls::capset(&mut header, &data)
185+
}

src/thread/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ mod futex;
77
#[cfg(any(target_os = "android", target_os = "linux"))]
88
mod id;
99
#[cfg(any(target_os = "android", target_os = "linux"))]
10+
mod libcap;
11+
#[cfg(any(target_os = "android", target_os = "linux"))]
1012
mod prctl;
1113
#[cfg(any(target_os = "android", target_os = "linux"))]
1214
mod setns;
@@ -30,6 +32,8 @@ pub use futex::{futex, FutexFlags, FutexOperation};
3032
#[cfg(any(target_os = "android", target_os = "linux"))]
3133
pub use id::gettid;
3234
#[cfg(any(target_os = "android", target_os = "linux"))]
35+
pub use libcap::{capabilities, set_capabilities, CapabilityFlags, CapabilitySets};
36+
#[cfg(any(target_os = "android", target_os = "linux"))]
3337
pub use prctl::*;
3438
#[cfg(any(target_os = "android", target_os = "linux"))]
3539
pub use setns::*;

0 commit comments

Comments
 (0)