diff --git a/docs/kernel/ipc/index.rst b/docs/kernel/ipc/index.rst index c830c878e..4645f3426 100644 --- a/docs/kernel/ipc/index.rst +++ b/docs/kernel/ipc/index.rst @@ -8,3 +8,4 @@ :maxdepth: 1 signal + ipc_namespace diff --git a/docs/kernel/ipc/ipc_namespace.md b/docs/kernel/ipc/ipc_namespace.md new file mode 100644 index 000000000..15999cc33 --- /dev/null +++ b/docs/kernel/ipc/ipc_namespace.md @@ -0,0 +1,56 @@ +# IPC Namespace + +:::{note} + +Author: longjin + +::: + +本页描述 DragonOS 对 IPC 命名空间(IPC namespace)的当前支持状态与后续计划。目标是对用户暴露与 Linux 一致的语义,并在 DragonOS 现有框架上逐步完善。 + +## 已支持功能 +- IpcNamespace 对象与 NsProxy 集成: + - 新增 `IpcNamespace` 并接入 `NsProxy`,每个任务通过 `nsproxy.ipc_ns` 访问所属 IPC 命名空间。 + - 命名空间的创建/继承遵循 `clone/unshare` 语义: + - 未包含 `CLONE_NEWIPC` 时继承父命名空间; + - 包含 `CLONE_NEWIPC` 时创建独立 IPC 命名空间; + - 与 `CLONE_SYSVSEM` 互斥,行为与 Linux 一致。 + +- SysV SHM(共享内存)按命名空间隔离: + - 将原全局 `SHM_MANAGER` 重构为 per-ns `ShmManager`,所有 `shmget/shmat/shmdt/shmctl` 均在 `current.nsproxy.ipc_ns` 下生效。 + - `shmat`/`shmdt`:VMA 记录 `ShmId`,解除映射时精确维护 `map_count`;`IPC_RMID` 后当 `SHM_DEST && map_count==0` 即完成物理回收。 + - 基本语义与错误码对齐:`IPC_CREAT|IPC_EXCL`、`ENOENT`、拒绝 `SHM_HUGETLB` 等。 + +- 基础测试用例:(在 `test_ipc_ns_shm.rs` 中) + + - `unshare(CLONE_NEWIPC)` 后父/子命名空间的 key 不可见; + - 跨命名空间相同 key 不冲突; + - `IPC_RMID` 后可重新创建同 key; + - 输出 PASS/FAIL 与汇总结果。 + +## 暂未实现/计划中 +- `/proc/[pid]/ns/ipc` 与 `setns`: + - 暂缓,仅规划只读占位与最简 `setns` 路径;后续版本补齐权限校验与切换时序。 + +- SysV IPC 其它子系统: + - `msg/sem` 框架尚未纳入;`sem` 的 UNDO 列表与 `unshare/setns` 的协同需在引入时同步实现。 + +- POSIX mqueue: + - 尚未提供 per-ns mqueuefs 内核挂载、限额与 sysctl。 + +- 权限与配额: + - `ipcperms()`、`ns_capable(user_ns, CAP_IPC_OWNER)`; + - ucounts/RLIMIT 与 `/proc/sys/kernel/shm*` 等 per-ns sysctl。 + +## 兼容性与注意事项 +- 当前阶段仅对 SysV SHM 提供命名空间隔离;其它 IPC 类型仍按全局语义工作。 +- 代码按模块化方式演进:后续加入 `msg/sem/mqueue` 时,保持对用户侧语义的稳定与一致。 + +## 参考 +- 代码位置: + - `kernel/src/process/namespace/ipc_namespace.rs` + - `kernel/src/process/namespace/nsproxy.rs` + - `kernel/src/ipc/syscall/` 内的 `sys_shm*` + - `kernel/src/mm/ucontext.rs`(VMA 与 SHM 计数维护) + + diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 3774d76e4..a1f7a9d5f 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -1,10 +1,7 @@ use crate::{ arch::mm::LockedFrameAllocator, filesystem::vfs::syscall::ModeType, - libs::{ - align::page_align_up, - spinlock::{SpinLock, SpinLockGuard}, - }, + libs::align::page_align_up, mm::{ allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame}, page::{page_manager_lock_irqsave, PageFlags, PageType}, @@ -15,33 +12,14 @@ use crate::{ time::PosixTimeSpec, }; use core::fmt; -use core::sync::atomic::{compiler_fence, Ordering}; use hashbrown::HashMap; use ida::IdAllocator; -use log::info; use num::ToPrimitive; use system_error::SystemError; -pub static mut SHM_MANAGER: Option> = None; /// 用于创建新的私有IPC对象 pub const IPC_PRIVATE: ShmKey = ShmKey::new(0); -/// 初始化SHM_MANAGER -pub fn shm_manager_init() { - info!("shm_manager_init"); - let shm_manager = SpinLock::new(ShmManager::new()); - - compiler_fence(Ordering::SeqCst); - unsafe { SHM_MANAGER = Some(shm_manager) }; - compiler_fence(Ordering::SeqCst); - - info!("shm_manager_init done"); -} - -pub fn shm_manager_lock() -> SpinLockGuard<'static, ShmManager> { - unsafe { SHM_MANAGER.as_ref().unwrap().lock() } -} - int_like!(ShmId, usize); int_like!(ShmKey, usize); @@ -138,6 +116,12 @@ pub struct ShmManager { key2id: HashMap, } +impl Default for ShmManager { + fn default() -> Self { + Self::new() + } +} + impl ShmManager { pub fn new() -> Self { ShmManager { @@ -178,7 +162,7 @@ impl ShmManager { // 创建共享内存page,并添加到PAGE_MANAGER中 let mut page_manager_guard = page_manager_lock_irqsave(); let (paddr, _page) = page_manager_guard.create_pages( - PageType::Shm(shm_id), + PageType::Shm, PageFlags::PG_UNEVICTABLE, &mut LockedFrameAllocator, page_count, diff --git a/kernel/src/ipc/syscall/sys_shmat.rs b/kernel/src/ipc/syscall/sys_shmat.rs index f8a6cccae..440db81c3 100644 --- a/kernel/src/ipc/syscall/sys_shmat.rs +++ b/kernel/src/ipc/syscall/sys_shmat.rs @@ -4,15 +4,16 @@ use crate::syscall::table::FormattedSyscallParam; use crate::{ arch::syscall::nr::SYS_SHMAT, arch::MMArch, - ipc::shm::{shm_manager_lock, ShmFlags, ShmId}, + ipc::shm::{ShmFlags, ShmId}, libs::align::page_align_up, mm::{ allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame}, page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll}, syscall::ProtFlags, - ucontext::{AddressSpace, VMA}, + ucontext::{AddressSpace, PhysmapParams, VMA}, VirtAddr, VmFlags, }, + process::ProcessManager, syscall::{table::Syscall, user_access::UserBufferReader}, }; use syscall_table_macros::declare_syscall; @@ -36,7 +37,8 @@ pub(super) fn do_kernel_shmat( vaddr: VirtAddr, shmflg: ShmFlags, ) -> Result { - let mut shm_manager_guard = shm_manager_lock(); + let ipcns = ProcessManager::current_ipcns(); + let mut shm_manager_guard = ipcns.shm.lock(); let current_address_space = AddressSpace::current()?; let mut address_write_guard = current_address_space.write(); @@ -59,15 +61,15 @@ pub(super) fn do_kernel_shmat( let flusher: PageFlushAll = PageFlushAll::new(); // 将共享内存映射到对应虚拟区域 - let vma = VMA::physmap( + let params = PhysmapParams { phys, destination, count, vm_flags, - page_flags, - &mut address_write_guard.user_mapper.utable, - flusher, - )?; + flags: page_flags, + shm_id: Some(id), + }; + let vma = VMA::physmap(params, &mut address_write_guard.user_mapper.utable, flusher)?; // 将VMA加入到当前进程的VMA列表中 address_write_guard.mappings.insert_vma(vma); @@ -125,7 +127,10 @@ pub(super) fn do_kernel_shmat( } // 更新vma的映射状态 - vma.lock_irqsave().set_mapped(true); + let mut vma_guard = vma.lock_irqsave(); + vma_guard.set_mapped(true); + vma_guard.set_shm_id(Some(id)); + drop(vma_guard); vaddr.data() } diff --git a/kernel/src/ipc/syscall/sys_shmctl.rs b/kernel/src/ipc/syscall/sys_shmctl.rs index 7ac5ea684..44fd769e2 100644 --- a/kernel/src/ipc/syscall/sys_shmctl.rs +++ b/kernel/src/ipc/syscall/sys_shmctl.rs @@ -2,7 +2,8 @@ use crate::alloc::vec::Vec; use crate::arch::interrupt::TrapFrame; use crate::{ arch::syscall::nr::SYS_SHMCTL, - ipc::shm::{shm_manager_lock, ShmCtlCmd, ShmId}, + ipc::shm::{ShmCtlCmd, ShmId}, + process::ProcessManager, syscall::table::{FormattedSyscallParam, Syscall}, }; use syscall_table_macros::declare_syscall; @@ -28,7 +29,9 @@ pub(super) fn do_kernel_shmctl( user_buf: *const u8, from_user: bool, ) -> Result { - let mut shm_manager_guard = shm_manager_lock(); + // per-ns 管理器 + let ipcns = ProcessManager::current_ipcns(); + let mut shm_manager_guard = ipcns.shm.lock(); match cmd { // 查看共享内存元信息 diff --git a/kernel/src/ipc/syscall/sys_shmget.rs b/kernel/src/ipc/syscall/sys_shmget.rs index 0e2675eb0..78ce49dd3 100644 --- a/kernel/src/ipc/syscall/sys_shmget.rs +++ b/kernel/src/ipc/syscall/sys_shmget.rs @@ -3,7 +3,8 @@ use crate::arch::interrupt::TrapFrame; use crate::syscall::table::FormattedSyscallParam; use crate::{ arch::syscall::nr::SYS_SHMGET, - ipc::shm::{shm_manager_lock, ShmFlags, ShmKey, IPC_PRIVATE}, + ipc::shm::{ShmFlags, ShmKey, IPC_PRIVATE}, + process::ProcessManager, syscall::table::Syscall, }; use log::error; @@ -34,7 +35,9 @@ pub(super) fn do_kernel_shmget( return Err(SystemError::ENOSYS); } - let mut shm_manager_guard = shm_manager_lock(); + // 从当前进程的 IPC 命名空间获取 per-ns SHM 管理器 + let ipcns = ProcessManager::current_ipcns(); + let mut shm_manager_guard = ipcns.shm.lock(); match key { // 创建共享内存段 IPC_PRIVATE => shm_manager_guard.add(key, size, shmflg), diff --git a/kernel/src/mm/init.rs b/kernel/src/mm/init.rs index 3fe0e72fb..716c76ecc 100644 --- a/kernel/src/mm/init.rs +++ b/kernel/src/mm/init.rs @@ -6,7 +6,6 @@ use crate::{ arch::MMArch, driver::serial::serial8250::send_to_default_serial8250_port, filesystem::procfs::kmsg::kmsg_init, - ipc::shm::shm_manager_init, libs::printk::PrintkWriter, mm::{ allocator::slab::slab_init, @@ -59,8 +58,6 @@ pub unsafe fn mm_init() { kmsg_init(); // enable PAGE_MANAGER page_manager_init(); - // enable SHM_MANAGER - shm_manager_init(); // enable PAGE_RECLAIMER page_reclaimer_init(); diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index 8253f0016..34c58883f 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -19,7 +19,6 @@ use crate::{ exception::ipi::{IpiKind, IpiTarget}, filesystem::{page_cache::PageCache, vfs::FilePrivateData}, init::initcall::INITCALL_CORE, - ipc::shm::ShmId, libs::{ rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}, spinlock::{SpinLock, SpinLockGuard}, @@ -672,7 +671,7 @@ pub enum PageType { /// 文件映射页,含文件映射相关信息 File(FileMapInfo), /// 共享内存页,记录ShmId - Shm(ShmId), + Shm, } #[derive(Debug, Clone)] diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 14844c6d0..f9d6ac6c9 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -21,7 +21,7 @@ use crate::{ arch::{mm::PageMapper, CurrentIrqArch, MMArch}, exception::InterruptArch, filesystem::vfs::file::File, - ipc::shm::{shm_manager_lock, ShmFlags}, + ipc::shm::{ShmFlags, ShmId}, libs::{ align::page_align_up, rwlock::RwLock, @@ -36,7 +36,7 @@ use super::{ allocator::page_frame::{ deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter, }, - page::{EntryFlags, Flusher, InactiveFlusher, PageFlushAll, PageType}, + page::{EntryFlags, Flusher, InactiveFlusher, PageFlushAll}, syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags}, MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags, }; @@ -1202,10 +1202,11 @@ impl LockedVMA { if let Some((paddr, _flags)) = mapper.translate(guard.region().start()) { // 如果是共享页,执行释放操作 let page = page_manager_guard.get(&paddr).unwrap(); - let page_guard = page.read_irqsave(); - if let PageType::Shm(shm_id) = page_guard.page_type() { - let mut shm_manager_guard = shm_manager_lock(); - if let Some(kernel_shm) = shm_manager_guard.get_mut(shm_id) { + let _page_guard = page.read_irqsave(); + if let Some(shm_id) = guard.shm_id { + let ipcns = ProcessManager::current_ipcns(); + let mut shm_manager_guard = ipcns.shm.lock(); + if let Some(kernel_shm) = shm_manager_guard.get_mut(&shm_id) { // 更新最后一次断开连接时间 kernel_shm.update_dtim(); @@ -1215,7 +1216,7 @@ impl LockedVMA { // 释放shm_id if kernel_shm.map_count() == 0 && kernel_shm.mode().contains(ShmFlags::SHM_DEST) { - shm_manager_guard.free_id(shm_id); + shm_manager_guard.free_id(&shm_id); } } } @@ -1405,6 +1406,17 @@ impl VMASplitResult { } } +/// Parameters for physmap operation +#[derive(Debug)] +pub struct PhysmapParams { + pub phys: PhysPageFrame, + pub destination: VirtPageFrame, + pub count: PageFrameCount, + pub vm_flags: VmFlags, + pub flags: EntryFlags, + pub shm_id: Option, +} + /// @brief 虚拟内存区域 #[derive(Debug)] pub struct VMA { @@ -1425,6 +1437,8 @@ pub struct VMA { file_pgoff: Option, provider: Provider, + /// 关联的 SysV SHM 标识(当此 VMA 来自 shmat 时设置) + shm_id: Option, } impl core::hash::Hash for VMA { @@ -1461,6 +1475,7 @@ impl VMA { provider: Provider::Allocated, vm_file: file, file_pgoff: pgoff, + shm_id: None, } } @@ -1496,6 +1511,11 @@ impl VMA { self.flags = MMArch::vm_get_page_prot(self.vm_flags); } + #[inline(always)] + pub fn set_shm_id(&mut self, shm: Option) { + self.shm_id = shm; + } + /// # 拷贝当前VMA的内容 /// /// ### 安全性 @@ -1512,6 +1532,7 @@ impl VMA { provider: Provider::Allocated, file_pgoff: self.file_pgoff, vm_file: self.vm_file.clone(), + shm_id: self.shm_id, }; } @@ -1526,6 +1547,7 @@ impl VMA { provider: Provider::Allocated, file_pgoff: self.file_pgoff, vm_file: self.vm_file.clone(), + shm_id: self.shm_id, }; } @@ -1589,31 +1611,29 @@ impl VMA { /// 把物理地址映射到虚拟地址 /// - /// @param phys 要映射的物理地址 - /// @param destination 要映射到的虚拟地址 - /// @param count 要映射的页帧数量 - /// @param flags 页面标志位 + /// @param params 物理映射参数 /// @param mapper 页表映射器 /// @param flusher 页表项刷新器 /// /// @return 返回映射后的虚拟内存区域 pub fn physmap( - phys: PhysPageFrame, - destination: VirtPageFrame, - count: PageFrameCount, - vm_flags: VmFlags, - flags: EntryFlags, + params: PhysmapParams, mapper: &mut PageMapper, mut flusher: impl Flusher, ) -> Result, SystemError> { - let mut cur_phy = phys; - let mut cur_dest = destination; + let mut cur_phy = params.phys; + let mut cur_dest = params.destination; - for _ in 0..count.data() { + for _ in 0..params.count.data() { // 将物理页帧映射到虚拟页帧 - let r = - unsafe { mapper.map_phys(cur_dest.virt_address(), cur_phy.phys_address(), flags) } - .expect("Failed to map phys, may be OOM error"); + let r = unsafe { + mapper.map_phys( + cur_dest.virt_address(), + cur_phy.phys_address(), + params.flags, + ) + } + .expect("Failed to map phys, may be OOM error"); // todo: 增加OOM处理 @@ -1625,18 +1645,24 @@ impl VMA { } let r: Arc = LockedVMA::new(VMA::new( - VirtRegion::new(destination.virt_address(), count.data() * MMArch::PAGE_SIZE), - vm_flags, - flags, + VirtRegion::new( + params.destination.virt_address(), + params.count.data() * MMArch::PAGE_SIZE, + ), + params.vm_flags, + params.flags, None, None, true, )); + if let Some(id) = params.shm_id { + r.lock_irqsave().set_shm_id(Some(id)); + } // 将VMA加入到anon_vma中 let mut page_manager_guard = page_manager_lock_irqsave(); - cur_phy = phys; - for _ in 0..count.data() { + cur_phy = params.phys; + for _ in 0..params.count.data() { let paddr = cur_phy.phys_address(); let page = page_manager_guard.get_unwrap(&paddr); page.write_irqsave().insert_vma(r.clone()); diff --git a/kernel/src/process/namespace/ipc_namespace.rs b/kernel/src/process/namespace/ipc_namespace.rs new file mode 100644 index 000000000..cb10d9370 --- /dev/null +++ b/kernel/src/process/namespace/ipc_namespace.rs @@ -0,0 +1,70 @@ +use alloc::sync::{Arc, Weak}; + +use crate::ipc::shm::ShmManager; +use crate::libs::spinlock::SpinLock; +use crate::process::namespace::{ + nsproxy::NsCommon, user_namespace::UserNamespace, NamespaceOps, NamespaceType, +}; +use crate::process::ProcessManager; + +// 根 IPC 命名空间 +lazy_static::lazy_static! { + pub static ref INIT_IPC_NAMESPACE: Arc = IpcNamespace::new_root(); +} + +/// DragonOS 的 IPC 命名空间 +pub struct IpcNamespace { + ns_common: NsCommon, + self_ref: Weak, + /// 关联的 user namespace (权限判断使用) + pub user_ns: Arc, + + /// SysV SHM 管理器(阶段一:仅支持 per-ns shm) + pub shm: SpinLock, +} + +impl NamespaceOps for IpcNamespace { + fn ns_common(&self) -> &NsCommon { + &self.ns_common + } +} + +impl IpcNamespace { + fn new_root() -> Arc { + Arc::new_cyclic(|weak_self| Self { + ns_common: NsCommon::new(0, NamespaceType::Ipc), + self_ref: weak_self.clone(), + user_ns: crate::process::namespace::user_namespace::INIT_USER_NAMESPACE.clone(), + shm: SpinLock::new(ShmManager::new()), + }) + } + + /// 复制/创建 IPC 命名空间 + pub fn copy_ipc_ns( + &self, + clone_flags: &crate::process::fork::CloneFlags, + user_ns: Arc, + ) -> Arc { + use crate::process::fork::CloneFlags; + if !clone_flags.contains(CloneFlags::CLONE_NEWIPC) { + return self.self_ref.upgrade().unwrap(); + } + // 创建新的 IPC 命名空间,SHM 空间独立 + Arc::new_cyclic(|weak_self| IpcNamespace { + ns_common: NsCommon::new(self.ns_common.level + 1, NamespaceType::Ipc), + self_ref: weak_self.clone(), + user_ns, + shm: SpinLock::new(ShmManager::new()), + }) + } +} + +impl ProcessManager { + pub fn current_ipcns() -> Arc { + if Self::initialized() { + ProcessManager::current_pcb().nsproxy.read().ipc_ns.clone() + } else { + INIT_IPC_NAMESPACE.clone() + } + } +} diff --git a/kernel/src/process/namespace/mod.rs b/kernel/src/process/namespace/mod.rs index 0a0a78b7c..9549a3bce 100644 --- a/kernel/src/process/namespace/mod.rs +++ b/kernel/src/process/namespace/mod.rs @@ -1,3 +1,4 @@ +pub mod ipc_namespace; pub mod mnt; pub mod nsproxy; pub mod pid_namespace; diff --git a/kernel/src/process/namespace/nsproxy.rs b/kernel/src/process/namespace/nsproxy.rs index e9b26f5eb..0c5e69b13 100644 --- a/kernel/src/process/namespace/nsproxy.rs +++ b/kernel/src/process/namespace/nsproxy.rs @@ -11,6 +11,7 @@ use crate::process::{ }; use core::{fmt::Debug, intrinsics::likely}; +use super::ipc_namespace::{IpcNamespace, INIT_IPC_NAMESPACE}; use super::{pid_namespace::PidNamespace, user_namespace::UserNamespace, NamespaceType}; /// A structure containing references to all per-process namespaces (filesystem/mount, UTS, network, etc.). @@ -28,9 +29,10 @@ pub struct NsProxy { /// mount namespace(挂载命名空间) pub mnt_ns: Arc, pub uts_ns: Arc, + /// ipc namespace(SysV IPC、POSIX mqueue 等) + pub ipc_ns: Arc, // 其他namespace(为未来扩展预留) // pub net_ns: Option>, - // pub ipc_ns: Option>, // pub cgroup_ns: Option>, // pub time_ns: Option>, } @@ -47,10 +49,12 @@ impl NsProxy { let root_pid_ns = super::pid_namespace::INIT_PID_NAMESPACE.clone(); let root_mnt_ns = root_mnt_namespace(); let root_uts_ns = INIT_UTS_NAMESPACE.clone(); + let root_ipc_ns = INIT_IPC_NAMESPACE.clone(); Arc::new(Self { pid_ns_for_children: root_pid_ns, mnt_ns: root_mnt_ns, uts_ns: root_uts_ns, + ipc_ns: root_ipc_ns, }) } @@ -69,6 +73,7 @@ impl NsProxy { pid_ns_for_children: self.pid_ns_for_children.clone(), mnt_ns: self.mnt_ns.clone(), uts_ns: self.uts_ns.clone(), + ipc_ns: self.ipc_ns.clone(), } } } @@ -149,10 +154,12 @@ pub(super) fn create_new_namespaces( let mnt_ns = nsproxy.mnt_ns.copy_mnt_ns(clone_flags, user_ns.clone())?; let uts_ns = nsproxy.uts_ns.copy_uts_ns(clone_flags, user_ns.clone())?; + let ipc_ns = nsproxy.ipc_ns.copy_ipc_ns(clone_flags, user_ns.clone()); let result = NsProxy { pid_ns_for_children, mnt_ns, uts_ns, + ipc_ns, }; let result = Arc::new(result); diff --git a/user/apps/r_unitest/Cargo.lock b/user/apps/r_unitest/Cargo.lock index cd4590c7d..bc28bdcbc 100644 --- a/user/apps/r_unitest/Cargo.lock +++ b/user/apps/r_unitest/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "futures-sink", "log", "pin-project 0.4.30", - "tokio 0.2.25", + "tokio", "tokio-util", ] @@ -117,7 +117,7 @@ dependencies = [ "futures-channel", "futures-util", "smallvec", - "tokio 0.2.25", + "tokio", ] [[package]] @@ -133,11 +133,11 @@ dependencies = [ "futures-channel", "futures-util", "log", - "mio 0.6.23", + "mio", "mio-uds", "num_cpus", "slab", - "socket2 0.3.19", + "socket2", ] [[package]] @@ -161,7 +161,7 @@ dependencies = [ "actix-server", "actix-service", "log", - "socket2 0.3.19", + "socket2", ] [[package]] @@ -245,7 +245,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "socket2 0.3.19", + "socket2", "time", "tinyvec", "url", @@ -262,21 +262,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -327,21 +312,6 @@ dependencies = [ "serde_urlencoded", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if 1.0.1", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base-x" version = "0.2.11" @@ -552,7 +522,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys", ] [[package]] @@ -690,15 +660,9 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if 1.0.1", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "h2" version = "0.2.7" @@ -713,7 +677,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 0.2.25", + "tokio", "tokio-util", "tracing", "tracing-futures", @@ -891,17 +855,6 @@ dependencies = [ "cfg-if 1.0.1", ] -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags 2.9.1", - "cfg-if 1.0.1", - "libc", -] - [[package]] name = "iovec" version = "0.1.4" @@ -917,7 +870,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" dependencies = [ - "socket2 0.3.19", + "socket2", "widestring", "winapi 0.3.9", "winreg", @@ -1028,15 +981,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" version = "0.6.23" @@ -1056,17 +1000,6 @@ dependencies = [ "winapi 0.2.8", ] -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - [[package]] name = "mio-uds" version = "0.6.8" @@ -1075,7 +1008,7 @@ checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" dependencies = [ "iovec", "libc", - "mio 0.6.23", + "mio", ] [[package]] @@ -1123,15 +1056,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1285,7 +1209,6 @@ dependencies = [ "nix", "sc", "syscalls", - "tokio 1.46.1", ] [[package]] @@ -1388,12 +1311,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - [[package]] name = "rustc_version" version = "0.2.3" @@ -1601,16 +1518,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "spin" version = "0.5.2" @@ -1828,7 +1735,7 @@ dependencies = [ "lazy_static", "libc", "memchr", - "mio 0.6.23", + "mio", "mio-uds", "pin-project-lite 0.1.12", "signal-hook-registry", @@ -1836,35 +1743,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "io-uring", - "libc", - "mio 1.0.4", - "pin-project-lite 0.2.16", - "signal-hook-registry", - "slab", - "socket2 0.5.10", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "tokio-util" version = "0.3.1" @@ -1876,7 +1754,7 @@ dependencies = [ "futures-sink", "log", "pin-project-lite 0.1.12", - "tokio 0.2.25", + "tokio", ] [[package]] @@ -1925,7 +1803,7 @@ dependencies = [ "rand", "smallvec", "thiserror", - "tokio 0.2.25", + "tokio", "url", ] @@ -1944,7 +1822,7 @@ dependencies = [ "resolv-conf", "smallvec", "thiserror", - "tokio 0.2.25", + "tokio", "trust-dns-proto", ] @@ -2010,12 +1888,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2134,47 +2006,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows-targets", ] [[package]] @@ -2183,106 +2021,58 @@ version = "0.53.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - [[package]] name = "windows_aarch64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - [[package]] name = "windows_aarch64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - [[package]] name = "windows_i686_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - [[package]] name = "windows_i686_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - [[package]] name = "windows_i686_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - [[package]] name = "windows_x86_64_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - [[package]] name = "windows_x86_64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - [[package]] name = "windows_x86_64_msvc" version = "0.53.0" diff --git a/user/apps/r_unitest/src/bin/test_ipc_ns_shm.rs b/user/apps/r_unitest/src/bin/test_ipc_ns_shm.rs new file mode 100644 index 000000000..7f0bc43e4 --- /dev/null +++ b/user/apps/r_unitest/src/bin/test_ipc_ns_shm.rs @@ -0,0 +1,206 @@ +extern crate nix; + +use nix::errno::Errno; +use nix::sched::{self, CloneFlags}; +use nix::sys::wait::{waitpid, WaitStatus}; +use nix::unistd::{fork, getpid, pipe, read, write, ForkResult}; + +const IPC_CREAT: i32 = 0o1000; + +fn shmget(key: i32, size: usize, flags: i32) -> Result { + let r = unsafe { libc::shmget(key as libc::key_t, size, flags as libc::c_int) }; + if r < 0 { + return Err(Errno::last_raw()); + } + Ok(r) +} + +fn shmctl(id: i32, cmd: i32) -> Result { + let r = unsafe { libc::shmctl(id, cmd, std::ptr::null_mut()) }; + if r < 0 { + return Err(Errno::last_raw()); + } + Ok(r) +} + +fn shmat(id: i32) -> Result<*mut libc::c_void, i32> { + let r = unsafe { libc::shmat(id, std::ptr::null(), 0) }; + if (r as isize) == -1 { + return Err(Errno::last_raw()); + } + Ok(r) +} + +fn shmdt(addr: *mut libc::c_void) -> Result { + let r = unsafe { libc::shmdt(addr) }; + if r < 0 { + return Err(Errno::last_raw()); + } + Ok(r) +} + +struct Suite { + passed: usize, + failed: usize, +} + +impl Suite { + fn new() -> Self { + Self { + passed: 0, + failed: 0, + } + } + fn ok(&mut self, name: &str) { + self.passed += 1; + println!("[PASS] {}", name); + } + fn fail(&mut self, name: &str, msg: &str) { + self.failed += 1; + println!("[FAIL] {}: {}", name, msg); + } + fn finish(&self) -> i32 { + println!("Summary: passed={}, failed={}", self.passed, self.failed); + if self.failed == 0 { + 0 + } else { + 1 + } + } +} + +fn main() { + let key_parent: i32 = 0x12345; // 仅父命名空间使用 + let key_child: i32 = 0x23456; // 仅子命名空间使用 + let size: usize = 4096; + let mut suite = Suite::new(); + + println!("[parent:{}] create shm in parent ns", getpid()); + let id_parent = shmget(key_parent, size, IPC_CREAT | 0o600).expect("parent shmget failed"); + + let (pr, pw) = pipe().expect("pipe"); + unsafe { + match fork() { + Ok(ForkResult::Parent { child }) => { + // case2: ensure child ns's shm is not visible to parent while child alive + // wait child signals via pipe + let mut buf = [0u8; 1]; + use std::os::fd::AsRawFd; + let _ = read(pr.as_raw_fd(), &mut buf).expect("read pipe"); + match shmget(key_child, size, 0o600) { + Ok(_) => suite.fail( + "parent cannot see child's shm by key_child", + "unexpected shm visible", + ), + Err(e) => { + if e == libc::ENOENT { + suite.ok("parent cannot see child's shm by key_child"); + } else { + suite.fail( + "parent cannot see child's shm by key_child", + &format!("errno={}", e), + ); + } + } + } + + match waitpid(child, None) { + Ok(WaitStatus::Exited(_, status)) => { + if status == 0 { + suite.ok("child exited 0"); + } else { + suite.fail("child exited 0", &format!("status={}", status)); + } + } + Ok(other) => suite.fail("child wait status", &format!("{:?}", other)), + Err(e) => suite.fail("waitpid", &format!("{:?}", e)), + } + + // parent can still attach/detach its own segment and then remove + match shmat(id_parent) { + Ok(addr) => { + let _ = shmdt(addr) + .map_err(|e| suite.fail("parent shmdt", &format!("errno={}", e))); + let _ = shmctl(id_parent, libc::IPC_RMID) + .map_err(|e| suite.fail("parent IPC_RMID", &format!("errno={}", e))); + suite.ok("parent attach/detach and remove"); + } + Err(e) => suite.fail("parent shmat", &format!("errno={}", e)), + } + + std::process::exit(suite.finish()); + } + Ok(ForkResult::Child) => { + println!("[child:{}] unshare CLONE_NEWIPC", getpid()); + if let Err(e) = sched::unshare(CloneFlags::CLONE_NEWIPC) { + eprintln!("unshare failed: {:?}", e); + std::process::exit(2); + } + + // case1: child can't see parent's shm by key + match shmget(key_parent, size, 0o600) { + Ok(_) => { + println!("[FAIL] child cannot see parent's shm by key"); + std::process::exit(3); + } + Err(e) => { + if e == libc::ENOENT { + println!("[PASS] child cannot see parent's shm by key"); + } else { + println!("[FAIL] child cannot see parent's shm by key: errno={}", e); + std::process::exit(3); + } + } + } + + // create its own shm with a different key in new ipc ns + let id_child = match shmget(key_child, size, IPC_CREAT | 0o600) { + Ok(x) => x, + Err(e) => { + eprintln!("child shmget(key_child) failed errno={}", e); + std::process::exit(4); + } + }; + // also create same key as parent in child ns to ensure no conflict across ns + let _id_child_same_key = match shmget(key_parent, size, IPC_CREAT | 0o600) { + Ok(x) => x, + Err(e) => { + eprintln!("child shmget(key_parent in child ns) failed errno={}", e); + std::process::exit(4); + } + }; + // signal parent + let _ = write(pw, &[1u8]).expect("write pipe"); + + // shmat + write, then mark IPC_RMID and ensure we can create new shm with the same key + let addr = match shmat(id_child) { + Ok(p) => p, + Err(e) => { + eprintln!("child shmat failed errno={}", e); + std::process::exit(5); + } + }; + unsafe { + *(addr as *mut u8) = 0xAB; + } + // mark to be removed + let _ = shmctl(id_child, libc::IPC_RMID).expect("IPC_RMID failed"); + // now shmget with same key and EXCL should succeed with a new id + let id2 = shmget(key_child, size, IPC_CREAT | 0o600 | libc::IPC_EXCL) + .expect("child shmget recreate failed"); + if id2 == id_child { + eprintln!("id2 should differ from id_child"); + std::process::exit(6); + } + // detach old mapping + let _ = shmdt(addr).expect("child shmdt failed"); + // cleanup new one + let addr2 = shmat(id2).expect("child shmat id2 failed"); + let _ = shmdt(addr2).expect("child shmdt id2 failed"); + let _ = shmctl(id2, libc::IPC_RMID).expect("child IPC_RMID id2 failed"); + std::process::exit(0); + } + Err(err) => panic!("fork failed: {:?}", err), + } + } +}