Skip to content

Commit a55f12d

Browse files
committed
Rework namespace functions and types
- Add set_namespaces function. - Deprecate move_into_link_name_space and move_into_thread_name_spaces functions. - Add NamespaceType. - Deprecate ThreadNameSpaceType and LinkNameSpaceType. - Add nsfs ioctls. - Add NoArgGetter ioctl pattern.
1 parent e5b793b commit a55f12d

File tree

3 files changed

+200
-34
lines changed

3 files changed

+200
-34
lines changed

src/ioctl/patterns.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,50 @@ unsafe impl<const OPCODE: Opcode> Ioctl for NoArg<OPCODE> {
5252
}
5353
}
5454

55+
/// Implements an `ioctl` with no real arguments.
56+
///
57+
/// To compute a value for the `OPCODE` argument, see the functions in the
58+
/// [`opcode`] module.
59+
///
60+
/// [`opcode`]: rustix::ioctl::opcode
61+
pub struct NoArgGetter<const OPCODE: Opcode> {}
62+
impl<const OPCODE: Opcode> fmt::Debug for NoArgGetter<OPCODE> {
63+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64+
f.debug_tuple("NoArgGetter").field(&OPCODE).finish()
65+
}
66+
}
67+
impl<const OPCODE: Opcode> NoArgGetter<OPCODE> {
68+
/// Create a new no-argument-getter `ioctl` object.
69+
///
70+
/// # Safety
71+
///
72+
/// - `OPCODE` must provide a valid opcode.
73+
#[inline]
74+
pub const unsafe fn new() -> Self {
75+
Self {}
76+
}
77+
}
78+
unsafe impl<const OPCODE: Opcode> Ioctl for NoArgGetter<OPCODE> {
79+
type Output = IoctlOutput;
80+
81+
const IS_MUTATING: bool = false;
82+
83+
fn opcode(&self) -> self::Opcode {
84+
OPCODE
85+
}
86+
87+
fn as_ptr(&mut self) -> *mut core::ffi::c_void {
88+
core::ptr::null_mut()
89+
}
90+
91+
unsafe fn output_from_ptr(
92+
output: IoctlOutput,
93+
_: *mut core::ffi::c_void,
94+
) -> Result<Self::Output> {
95+
Ok(output)
96+
}
97+
}
98+
5599
/// Implements the traditional “getter” pattern for `ioctl`s.
56100
///
57101
/// Some `ioctl`s just read data into the userspace. As this is a popular

src/thread/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ mod libcap;
1111
#[cfg(linux_kernel)]
1212
mod membarrier;
1313
#[cfg(linux_kernel)]
14+
mod ns;
15+
#[cfg(linux_kernel)]
1416
mod prctl;
1517
#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
1618
mod sched;
1719
mod sched_yield;
18-
#[cfg(linux_kernel)]
19-
mod setns;
2020

2121
#[cfg(not(target_os = "redox"))]
2222
pub use clock::*;
@@ -29,9 +29,9 @@ pub use libcap::{capabilities, set_capabilities, CapabilityFlags, CapabilitySet,
2929
#[cfg(linux_kernel)]
3030
pub use membarrier::*;
3131
#[cfg(linux_kernel)]
32+
pub use ns::*;
33+
#[cfg(linux_kernel)]
3234
pub use prctl::*;
3335
#[cfg(any(freebsdlike, linux_kernel, target_os = "fuchsia"))]
3436
pub use sched::*;
3537
pub use sched_yield::sched_yield;
36-
#[cfg(linux_kernel)]
37-
pub use setns::*;

src/thread/setns.rs renamed to src/thread/ns.rs

Lines changed: 152 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,80 @@ use linux_raw_sys::general::{
33
CLONE_FILES, CLONE_FS, CLONE_NEWCGROUP, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID,
44
CLONE_NEWTIME, CLONE_NEWUSER, CLONE_NEWUTS, CLONE_SYSVSEM,
55
};
6+
use linux_raw_sys::ioctl::{NS_GET_NSTYPE, NS_GET_OWNER_UID, NS_GET_PARENT, NS_GET_USERNS};
67

78
use crate::backend::c::c_int;
89
use crate::backend::thread::syscalls;
910
use crate::fd::BorrowedFd;
11+
use crate::fd::{AsFd, FromRawFd, OwnedFd};
1012
use crate::io;
13+
use crate::ioctl;
14+
15+
use super::{RawUid, Uid};
16+
17+
bitflags! {
18+
/// Namespace type.
19+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20+
#[repr(transparent)]
21+
pub struct NamespaceType: u32 {
22+
/// Control group (CGroup) namespace.
23+
const CGROUP = CLONE_NEWCGROUP;
24+
/// System V IPC and POSIX message queue namespace.
25+
const IPC = CLONE_NEWIPC;
26+
/// Mount namespace.
27+
const MOUNT = CLONE_NEWNS;
28+
/// Network namespace.
29+
const NETWORK = CLONE_NEWNET;
30+
/// Process ID namespace.
31+
const PID = CLONE_NEWPID;
32+
/// Time namespace.
33+
const TIME = CLONE_NEWTIME;
34+
/// User and group ID namespace.
35+
const USER = CLONE_NEWUSER;
36+
/// `Host name` and `NIS domain name` (UTS) namespace.
37+
const UTS = CLONE_NEWUTS;
38+
39+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
40+
const _ = !0;
41+
}
42+
}
43+
44+
bitflags! {
45+
/// `CLONE_*` for use with [`unshare`].
46+
#[repr(transparent)]
47+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
48+
pub struct UnshareFlags: u32 {
49+
/// `CLONE_FILES`
50+
const FILES = CLONE_FILES;
51+
/// `CLONE_FS`
52+
const FS = CLONE_FS;
53+
/// `CLONE_NEWCGROUP`
54+
const NEWCGROUP = CLONE_NEWCGROUP;
55+
/// `CLONE_NEWIPC`
56+
const NEWIPC = CLONE_NEWIPC;
57+
/// `CLONE_NEWNET`
58+
const NEWNET = CLONE_NEWNET;
59+
/// `CLONE_NEWNS`
60+
const NEWNS = CLONE_NEWNS;
61+
/// `CLONE_NEWPID`
62+
const NEWPID = CLONE_NEWPID;
63+
/// `CLONE_NEWTIME`
64+
const NEWTIME = CLONE_NEWTIME;
65+
/// `CLONE_NEWUSER`
66+
const NEWUSER = CLONE_NEWUSER;
67+
/// `CLONE_NEWUTS`
68+
const NEWUTS = CLONE_NEWUTS;
69+
/// `CLONE_SYSVSEM`
70+
const SYSVSEM = CLONE_SYSVSEM;
71+
72+
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
73+
const _ = !0;
74+
}
75+
}
1176

1277
bitflags! {
1378
/// Thread name space type.
79+
#[deprecated(since = "1.1.0", note = "Use NamespaceType instead")]
1480
#[repr(transparent)]
1581
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1682
pub struct ThreadNameSpaceType: u32 {
@@ -37,6 +103,7 @@ bitflags! {
37103
}
38104

39105
/// Type of name space referred to by a link.
106+
#[deprecated(since = "1.1.0", note = "Use NamespaceType instead")]
40107
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
41108
#[repr(u32)]
42109
pub enum LinkNameSpaceType {
@@ -58,37 +125,28 @@ pub enum LinkNameSpaceType {
58125
Network = CLONE_NEWNET,
59126
}
60127

61-
bitflags! {
62-
/// `CLONE_*` for use with [`unshare`].
63-
#[repr(transparent)]
64-
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
65-
pub struct UnshareFlags: u32 {
66-
/// `CLONE_FILES`
67-
const FILES = CLONE_FILES;
68-
/// `CLONE_FS`
69-
const FS = CLONE_FS;
70-
/// `CLONE_NEWCGROUP`
71-
const NEWCGROUP = CLONE_NEWCGROUP;
72-
/// `CLONE_NEWIPC`
73-
const NEWIPC = CLONE_NEWIPC;
74-
/// `CLONE_NEWNET`
75-
const NEWNET = CLONE_NEWNET;
76-
/// `CLONE_NEWNS`
77-
const NEWNS = CLONE_NEWNS;
78-
/// `CLONE_NEWPID`
79-
const NEWPID = CLONE_NEWPID;
80-
/// `CLONE_NEWTIME`
81-
const NEWTIME = CLONE_NEWTIME;
82-
/// `CLONE_NEWUSER`
83-
const NEWUSER = CLONE_NEWUSER;
84-
/// `CLONE_NEWUTS`
85-
const NEWUTS = CLONE_NEWUTS;
86-
/// `CLONE_SYSVSEM`
87-
const SYSVSEM = CLONE_SYSVSEM;
128+
/// Move the calling thread into different namespaces
129+
///
130+
/// This function has two different semantics depending on the `fd` argument.
131+
///
132+
/// - If `fd` refers to one of the magic links in a `/proc/[pid]/ns/` directory
133+
/// or a bind mount to such a link, the calling thread is moved to the namespaces
134+
/// referred to by `fd`. `namespace_type` must either be [`NamespaceType::empty()`]
135+
/// in which case all namespace types can be joined or a single [`NamespaceType`]
136+
/// bit in which case only namespaces of this type can be joined.
137+
/// - If `fd` refers to a pidfd, the calling thread is moved to all namespaces of this
138+
/// process that are specified in `namespace_type`.
139+
///
140+
/// # References
141+
/// - [Linux]
142+
///
143+
/// [Linux]: https://man7.org/linux/man-pages/man2/setns.2.html
144+
#[deprecated(since = "1.1.0", note = "Use setns instead")]
145+
#[doc(alias = "setns")]
146+
pub fn set_namespace(fd: BorrowedFd<'_>, namespace_type: NamespaceType) -> io::Result<()> {
147+
syscalls::setns(fd, namespace_type.bits() as c_int)?;
88148

89-
/// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
90-
const _ = !0;
91-
}
149+
Ok(())
92150
}
93151

94152
/// Reassociate the calling thread with the namespace associated with link
@@ -101,7 +159,9 @@ bitflags! {
101159
/// - [Linux]
102160
///
103161
/// [Linux]: https://man7.org/linux/man-pages/man2/setns.2.html
162+
#[deprecated(since = "1.1.0", note = "Use setns instead")]
104163
#[doc(alias = "setns")]
164+
#[allow(deprecated)]
105165
pub fn move_into_link_name_space(
106166
fd: BorrowedFd<'_>,
107167
allowed_type: Option<LinkNameSpaceType>,
@@ -119,7 +179,9 @@ pub fn move_into_link_name_space(
119179
/// - [Linux]
120180
///
121181
/// [Linux]: https://man7.org/linux/man-pages/man2/setns.2.html
182+
#[deprecated(since = "1.1.0", note = "Use setns instead")]
122183
#[doc(alias = "setns")]
184+
#[allow(deprecated)]
123185
pub fn move_into_thread_name_spaces(
124186
fd: BorrowedFd<'_>,
125187
allowed_types: ThreadNameSpaceType,
@@ -137,3 +199,63 @@ pub fn move_into_thread_name_spaces(
137199
pub fn unshare(flags: UnshareFlags) -> io::Result<()> {
138200
syscalls::unshare(flags)
139201
}
202+
203+
/// `ioctl(ns_fd, NS_GET_USERNS)`
204+
///
205+
/// # Safety
206+
///
207+
/// `fd` must refer to a `/proc/pid/ns/*` file.
208+
#[inline]
209+
#[doc(alias = "NS_GET_USERNS")]
210+
pub fn ioctl_ns_get_userns<FD: AsFd>(fd: FD) -> io::Result<OwnedFd> {
211+
#[allow(unsafe_code)]
212+
unsafe {
213+
let ctl = ioctl::NoArgGetter::<{ NS_GET_USERNS }>::new();
214+
ioctl::ioctl(fd, ctl).map(|fd| OwnedFd::from_raw_fd(fd))
215+
}
216+
}
217+
218+
/// `ioctl(ns_fd, NS_GET_PARENT)`
219+
///
220+
/// # Safety
221+
///
222+
/// `fd` must refer to a `/proc/pid/ns/*` file.
223+
#[inline]
224+
#[doc(alias = "NS_GET_PARENT")]
225+
pub fn ioctl_ns_get_parent<FD: AsFd>(fd: FD) -> io::Result<OwnedFd> {
226+
#[allow(unsafe_code)]
227+
unsafe {
228+
let ctl = ioctl::NoArgGetter::<{ NS_GET_PARENT }>::new();
229+
ioctl::ioctl(fd, ctl).map(|fd| OwnedFd::from_raw_fd(fd))
230+
}
231+
}
232+
233+
/// `ioctl(ns_fd, NS_GET_NSTYPE)`
234+
///
235+
/// # Safety
236+
///
237+
/// `fd` must refer to a `/proc/pid/ns/*` file.
238+
#[inline]
239+
#[doc(alias = "NS_GET_NSTYPE")]
240+
pub fn ioctl_ns_get_nstype<FD: AsFd>(fd: FD) -> io::Result<NamespaceType> {
241+
#[allow(unsafe_code)]
242+
unsafe {
243+
let ctl = ioctl::NoArgGetter::<{ NS_GET_NSTYPE }>::new();
244+
ioctl::ioctl(fd, ctl).map(|ns| NamespaceType::from_bits_retain(ns as u32))
245+
}
246+
}
247+
248+
/// `ioctl(ns_fd, NS_GET_OWNER_UID)`
249+
///
250+
/// # Safety
251+
///
252+
/// `fd` must refer to a `/proc/pid/ns/*` file.
253+
#[inline]
254+
#[doc(alias = "NS_GET_OWNER_UID")]
255+
pub fn ioctl_ns_get_owner_uid<FD: AsFd>(fd: FD) -> io::Result<Uid> {
256+
#[allow(unsafe_code)]
257+
unsafe {
258+
let ctl = ioctl::Getter::<{ NS_GET_OWNER_UID }, RawUid>::new();
259+
ioctl::ioctl(fd, ctl).map(Uid::from_raw)
260+
}
261+
}

0 commit comments

Comments
 (0)