diff --git a/src/context/context.rs b/src/context/context.rs index 943ba0c9e9..0a2701a253 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -169,6 +169,12 @@ pub struct Context { /// Bytes written that were cancelled (Linux cancelled_write_bytes). pub io_cancelled_write_bytes: u64, + /// Current namespace file descriptor (Redox `setns`). `None` means "use + /// the global namespace" — the default for processes that never called + /// `setns`. Set by `SYS_SETNS`; read by `openat`/`dup`/etc. to route + /// scheme lookups through the chosen namespace fd. + pub ns_fd: Option, + // TODO: id can reappear after wraparound? pub owner_proc_id: Option, @@ -248,6 +254,7 @@ impl Context { io_read_bytes: 0, io_write_bytes: 0, io_cancelled_write_bytes: 0, + ns_fd: None, #[cfg(feature = "syscall_debug")] syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(), diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index b2f93d8e4f..bfd638354b 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -275,6 +275,8 @@ pub fn syscall( SYS_MPROTECT => mprotect(b, c, MapFlags::from_bits_truncate(d), token).map(|()| 0), SYS_MREMAP => mremap(b, c, d, e, f, token), + SYS_MKNS => sys_mkns(UserSlice::ro(b, c)?, token).map(FileHandle::into), + SYS_SETNS => sys_setns(fd, token).map(|()| 0), _ => { println!("KERNEL: unimplemented syscall a={:#x} b={:#x} c={:#x} d={:#x}", a, b, c, d); diff --git a/src/syscall/process.rs b/src/syscall/process.rs index e83da427b4..6d8943f245 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -93,6 +93,49 @@ pub fn mprotect( AddrSpace::current()?.mprotect(span, flags, token) } +/// Create a new namespace containing the named schemes (space-separated in `names`). +/// +/// Returns a file handle that refers to the new namespace; the caller is expected to +/// pass it to `sys_setns` to switch into it, or to `redox-rt::sys::setns` for a +/// pure-userspace swap of the per-thread dynamic proc info `ns_fd`. +/// +/// Implementation: dups the calling context's namespace fd with the caller-supplied +/// buffer (which contains `NsDup::ForkNs` followed by scheme names). The dup is +/// handled by the bootstrap's userspace namespace manager daemon (`initnsmgr`), +/// which creates the new namespace and returns a new fd. +pub fn sys_mkns( + names: UserSliceRo, + token: &mut CleanLockToken, +) -> Result { + let ns_fd_opt = { + let ctx_lock = context::current(); + let ctx = ctx_lock.read(token.token()); + ctx.ns_fd + }; + let ns_fd = ns_fd_opt.ok_or(Error::new(EBADF))?; + crate::syscall::fs::dup(FileHandle::from(ns_fd), names, token) +} + +/// Switch the calling context to the namespace referenced by `fd`. +/// +/// The fd must have been produced by `sys_mkns` (or by the bootstrap's namespace +/// manager). After this syscall returns, all scheme lookups in the calling +/// context resolve against the new namespace. +pub fn sys_setns( + fd: FileHandle, + token: &mut CleanLockToken, +) -> Result<()> { + let ns_fd = fd.get(); + if ns_fd == 0 || ns_fd == usize::MAX { + return Err(Error::new(EBADF)); + } + + let ctx_lock = context::current(); + let mut ctx = ctx_lock.write(token.token()); + ctx.ns_fd = Some(ns_fd); + Ok(()) +} + const KERNEL_METADATA_BASE: usize = crate::USER_END_OFFSET - syscall::KERNEL_METADATA_SIZE; const KERNEL_METADATA_PAGE_COUNT: usize = syscall::KERNEL_METADATA_SIZE / PAGE_SIZE + { if syscall::KERNEL_METADATA_SIZE.is_multiple_of(PAGE_SIZE) {