2025-08-04 09:01:39 +00:00
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
|
|
use spin::Once;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
2026-02-11 11:18:48 +00:00
|
|
|
fs::{
|
|
|
|
|
path::Path,
|
|
|
|
|
pseudofs::{NsCommonOps, NsFs, NsType},
|
|
|
|
|
},
|
2025-08-04 09:01:39 +00:00
|
|
|
prelude::*,
|
2026-02-11 11:18:48 +00:00
|
|
|
process::{Uid, credentials::capabilities::CapSet, posix_thread::PosixThread},
|
2025-08-04 09:01:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// The user namespace.
|
|
|
|
|
pub struct UserNamespace {
|
|
|
|
|
_private: (),
|
2026-02-11 11:18:48 +00:00
|
|
|
path: Path,
|
2025-08-04 09:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UserNamespace {
|
|
|
|
|
/// Returns a reference to the singleton initial user namespace.
|
|
|
|
|
pub fn get_init_singleton() -> &'static Arc<UserNamespace> {
|
|
|
|
|
static INIT: Once<Arc<UserNamespace>> = Once::new();
|
|
|
|
|
|
2026-02-11 11:18:48 +00:00
|
|
|
INIT.call_once(Self::new)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn new() -> Arc<Self> {
|
|
|
|
|
Arc::new_cyclic(|weak_self| {
|
|
|
|
|
let path = NsFs::new_path(weak_self.clone());
|
|
|
|
|
Self { _private: (), path }
|
|
|
|
|
})
|
2025-08-04 09:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Checks whether the thread has the required capability in this user namespace.
|
|
|
|
|
pub fn check_cap(&self, required: CapSet, posix_thread: &PosixThread) -> Result<()> {
|
|
|
|
|
// Since creating new user namespaces is not supported at the moment,
|
|
|
|
|
// there is effectively only one user namespace in the entire system.
|
|
|
|
|
// Therefore, the thread has a single set of capabilities used for permission checks.
|
|
|
|
|
// FIXME: Once support for creating new user namespaces is added,
|
|
|
|
|
// we should verify the thread's capabilities within the relevant user namespace.
|
|
|
|
|
let cap_set = posix_thread.credentials().effective_capset();
|
|
|
|
|
if cap_set.contains(required) {
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EPERM,
|
|
|
|
|
"the thread does not have the required capability"
|
|
|
|
|
)
|
|
|
|
|
}
|
2026-02-11 11:18:48 +00:00
|
|
|
|
|
|
|
|
/// Returns the owner UID of the user namespace.
|
|
|
|
|
pub fn get_owner_uid(&self) -> Result<Uid> {
|
|
|
|
|
// FIXME: The owner of the user namespace is not yet tracked.
|
|
|
|
|
// Return the correct user ID once ownership tracking is implemented.
|
|
|
|
|
Ok(Uid::new_root())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns whether this namespace is the same as, or an ancestor of, the other namespace.
|
|
|
|
|
pub fn is_same_or_ancestor_of(self: &Arc<Self>, other: &Arc<Self>) -> bool {
|
|
|
|
|
// FIXME: Creating new user namespaces is not yet supported,
|
|
|
|
|
// so we simply check pointer equality.
|
|
|
|
|
// Once user namespace creation is implemented,
|
|
|
|
|
// this should walk up the ancestor chain to verify
|
|
|
|
|
// whether `self` is an ancestor of `other`.
|
|
|
|
|
Arc::ptr_eq(self, other)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl NsCommonOps for UserNamespace {
|
|
|
|
|
const TYPE: NsType = NsType::User;
|
|
|
|
|
|
|
|
|
|
fn get_owner_user_ns(&self) -> Result<&Arc<UserNamespace>> {
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EPERM,
|
|
|
|
|
"a user namespace does not have an owner user namespace"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_parent(&self) -> Result<Arc<Self>> {
|
|
|
|
|
return_errno_with_message!(
|
|
|
|
|
Errno::EPERM,
|
|
|
|
|
"getting the parent of a user namespace is not supported"
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn path(&self) -> &Path {
|
|
|
|
|
&self.path
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
|
|
|
self
|
|
|
|
|
}
|
2025-08-04 09:01:39 +00:00
|
|
|
}
|