Support setns via nsfs

This commit is contained in:
Jianfeng Jiang 2026-02-11 11:19:06 +00:00
parent 9c023db7b5
commit 9fdb63800b
13 changed files with 104 additions and 8 deletions

View File

@ -502,6 +502,10 @@ impl FileIo for EvdevFile {
Ok(0)
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Drop for EvdevFile {

View File

@ -517,6 +517,10 @@ impl FileIo for FbHandle {
}
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(super) fn init_in_first_kthread() {

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::vec;
use core::any::Any;
use ostd::mm::{FallibleVmWrite, VmReader, VmWriter};
@ -150,4 +151,8 @@ impl FileIo for MemFile {
fn is_offset_aware(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -170,6 +170,10 @@ impl FileIo for TdxGuestFile {
_ => return_errno_with_message!(Errno::ENOTTY, "the ioctl command is unknown"),
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub fn tdx_get_quote(inblob: &[u8]) -> Result<Box<[u8]>> {

View File

@ -91,4 +91,8 @@ impl FileIo for PtySlaveFile {
fn is_offset_aware(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
}

View File

@ -252,6 +252,10 @@ impl FileIo for PtyMaster {
Ok(0)
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Drop for PtyMaster {

View File

@ -151,6 +151,10 @@ impl FileIo for OpenBlockFile {
),
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(super) fn lookup(id: DeviceId) -> Option<Arc<dyn Device>> {

View File

@ -185,6 +185,10 @@ impl<D: TtyDriver> FileIo for TtyFile<D> {
fn is_offset_aware(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
}
static TTY1: Once<Arc<Tty<VtDriver>>> = Once::new();

View File

@ -14,6 +14,7 @@ use crate::{
file_table::FdFlags,
path::Path,
pipe::PipeHandle,
pseudofs::{NsCommonOps, NsFile},
utils::{
AccessMode, AtomicStatusFlags, CreationFlags, DirentVisitor, FallocMode, FileRange,
FlockItem, InodeType, OFFSET_MAX, RangeLockItem, RangeLockType, SeekFrom, StatusFlags,
@ -215,6 +216,11 @@ impl InodeHandle {
Ok(())
}
pub fn as_ns_file<T: NsCommonOps>(&self) -> Option<&NsFile<T>> {
let file_io = self.file_io.as_ref()?;
file_io.as_any().downcast_ref::<NsFile<T>>()
}
}
impl Pollable for InodeHandle {
@ -519,6 +525,8 @@ pub trait FileIo: Pollable + InodeIo + Any + Send + Sync + 'static {
fn ioctl(&self, _raw_ioctl: RawIoctl) -> Result<i32> {
return_errno_with_message!(Errno::ENOTTY, "ioctl is not supported");
}
fn as_any(&self) -> &dyn Any;
}
fn do_seek_util(offset: &Mutex<usize>, pos: SeekFrom, end: Option<usize>) -> Result<usize> {

View File

@ -136,6 +136,10 @@ impl FileIo for PipeHandle {
fn is_offset_aware(&self) -> bool {
false
}
fn as_any(&self) -> &dyn Any {
self
}
}
/// A pipe (FIFO) that provides inter-process communication.

View File

@ -11,7 +11,10 @@
//! 2. A `PidFile` opened by `pidfd_open` or by opening `/proc/[pid]` directory.
use crate::{
fs::{file_table::FileDesc, path::MountNamespace},
fs::{
file_handle::FileLike, file_table::FileDesc, inode_handle::InodeHandle,
path::MountNamespace, pseudofs::NsCommonOps,
},
net::uts_ns::UtsNamespace,
prelude::*,
process::{
@ -34,13 +37,8 @@ pub fn sys_setns(fd: FileDesc, flags: u32, ctx: &Context) -> Result<SyscallRetur
let new_ns_proxy = if let Some(pid_file) = file.downcast_ref::<PidFile>() {
build_proxy_from_pid_file(pid_file, ns_type_flags, ctx)?
}
// TODO: Support setting namespaces from `/proc/[pid]/ns`.
else {
return_errno_with_message!(
Errno::EINVAL,
"the FD does not refer to a supported namespace file"
);
} else {
build_proxy_from_ns_file(file.as_ref(), ns_type_flags, ctx)?
};
// Install the newly created `NsProxy`.
@ -105,6 +103,56 @@ fn build_proxy_from_pid_file(
Ok(builder.build())
}
fn build_proxy_from_ns_file(
file: &dyn FileLike,
flags: CloneFlags,
ctx: &Context,
) -> Result<NsProxy> {
check_unsupported_ns_flags(flags)?;
let inode_handle = file
.downcast_ref::<InodeHandle>()
.ok_or_else(|| Error::with_message(Errno::EINVAL, "the file is not a ns file"))?;
let current_proxy = ctx.thread_local.borrow_ns_proxy();
let current_proxy = current_proxy.unwrap();
let mut builder = NsProxyBuilder::new(current_proxy);
let applied = try_apply_ns::<UtsNamespace>(inode_handle, flags, |ns| {
builder.uts_ns(ns);
})? || try_apply_ns::<MountNamespace>(inode_handle, flags, |ns| {
builder.mnt_ns(ns);
})?;
// TODO: Support setting other namespaces from the ns file.
if !applied {
return_errno_with_message!(Errno::EINVAL, "invalid flags are specified with a ns file");
}
Ok(builder.build())
}
fn try_apply_ns<T: NsCommonOps>(
inode_handle: &InodeHandle,
flags: CloneFlags,
apply: impl FnOnce(Arc<T>),
) -> Result<bool> {
let Some(ns_file) = inode_handle.as_ns_file::<T>() else {
return Ok(false);
};
if !flags.is_empty() && flags != T::TYPE.into() {
return_errno_with_message!(
Errno::EINVAL,
"the flags do not match the type of the ns file"
);
}
apply(ns_file.ns().clone());
Ok(true)
}
fn set_uts_ns(
builder: &mut NsProxyBuilder,
target_ns: &Arc<UtsNamespace>,

View File

@ -52,6 +52,7 @@ TESTS ?= \
sched_yield_test \
semaphore_test \
sendfile_test \
setns_test \
sigaction_test \
sigaltstack_test \
signalfd_test \

View File

@ -0,0 +1,2 @@
SetnsTest.ChangeIPCNamespace
SetnsTest.ChangePIDNamespace