diff --git a/bootstrap/src/exec.rs b/bootstrap/src/exec.rs index 4e417f9e66..bed91a03a9 100644 --- a/bootstrap/src/exec.rs +++ b/bootstrap/src/exec.rs @@ -4,11 +4,12 @@ use alloc::vec::Vec; use core::ffi::CStr; use core::str::FromStr; use hashbrown::HashMap; +use redox_scheme::Socket; +use syscall::CallFlags; use syscall::data::{GlobalSchemes, KernelSchemeInfo}; use syscall::flag::{O_CLOEXEC, O_RDONLY, O_STAT}; -use syscall::CallFlags; -use syscall::{Error, EINTR}; +use syscall::{EINTR, Error}; use redox_rt::proc::*; @@ -49,20 +50,15 @@ pub fn main() -> ! { }; let scheme_creation_cap = unsafe { let base_ptr = cursor as *const u8; - let cap = *(base_ptr as *const usize); - cap + FdGuard::new(*(base_ptr as *const usize)) }; - let kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos); + let mut kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos); - let auth = FdGuard::new( - *kernel_schemes - .get(GlobalSchemes::Proc) - .expect("failed to get proc fd"), - ); - let pipe_fd = *kernel_schemes - .get(GlobalSchemes::Pipe) - .expect("failed to get pipe fd"); + let auth = kernel_schemes + .0 + .remove(&GlobalSchemes::Proc) + .expect("failed to get proc fd"); let this_thr_fd = auth .dup(b"cur-context") @@ -75,9 +71,10 @@ pub fn main() -> ! { let mut envs = { let fd = FdGuard::new( syscall::openat( - *kernel_schemes + kernel_schemes .get(GlobalSchemes::Sys) - .expect("failed to get sys fd"), + .expect("failed to get sys fd") + .as_raw_fd(), "env", O_RDONLY | O_CLOEXEC, 0, @@ -126,12 +123,14 @@ pub fn main() -> ! { (*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size }; - let initfs_fd = spawn( + let (scheme_creation_cap, auth, kernel_schemes, initfs_fd) = spawn( "initfs daemon", - &auth, + auth, &this_thr_fd, - pipe_fd, - |write_fd| unsafe { + scheme_creation_cap, + kernel_schemes, + false, + |write_fd, socket, _, _| unsafe { // Creating a reference to NULL is UB. Mask the UB for now using black_box. // FIXME use a raw pointer and inline asm for reading instead for the initfs header. let initfs_start = core::ptr::addr_of!(__initfs_header); @@ -140,45 +139,65 @@ pub fn main() -> ! { crate::initfs::run( core::slice::from_raw_parts(initfs_start, initfs_length), write_fd, - &kernel_schemes, - scheme_creation_cap, + socket, ); }, ); - let proc_fd = spawn( + let (scheme_creation_cap, auth, kernel_schemes, proc_fd) = spawn( "process manager", - &auth, + auth, &this_thr_fd, - pipe_fd, - |write_fd| crate::procmgr::run(write_fd, &auth, &kernel_schemes, scheme_creation_cap), - ); - - let initns_fd = spawn( - "init namespace manager", - &auth, - &this_thr_fd, - pipe_fd, - move |write_fd| { - let mut schemes = HashMap::default(); - for (scheme, fd) in kernel_schemes.0.into_iter() { - schemes.insert(scheme.as_str().to_string(), Arc::new(FdGuard::new(fd))); - } - schemes.insert("proc".to_string(), Arc::new(FdGuard::new(proc_fd))); - schemes.insert("initfs".to_string(), Arc::new(FdGuard::new(initfs_fd))); - - crate::initnsmgr::run(write_fd, schemes, scheme_creation_cap) + scheme_creation_cap, + kernel_schemes, + true, + |write_fd, socket, auth, mut kernel_schemes| { + let event = kernel_schemes + .0 + .remove(&GlobalSchemes::Event) + .expect("failed to get event fd"); + drop(kernel_schemes); + crate::procmgr::run(write_fd, socket, auth, event) }, ); - let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd) }; + let scheme_creation_cap_dup = scheme_creation_cap + .dup(b"") + .expect("failed to dup scheme creation cap"); + let (_, _, _, initns_fd) = spawn( + "init namespace manager", + auth, + &this_thr_fd, + scheme_creation_cap, + kernel_schemes, + false, + |write_fd, socket, _, kernel_schemes| { + let mut schemes = HashMap::default(); + for (scheme, fd) in kernel_schemes.0.into_iter() { + schemes.insert(scheme.as_str().to_string(), Arc::new(fd)); + } + schemes.insert( + "proc".to_string(), + // A bit dirty, but necessary as the parent process still needs access to it. Rust + // doesn't know that the fd got cloned by fork. + Arc::new(FdGuard::new(proc_fd.as_raw_fd())), + ); + schemes.insert("initfs".to_string(), Arc::new(initfs_fd)); + + crate::initnsmgr::run(write_fd, socket, schemes, scheme_creation_cap_dup) + }, + ); + + let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd.take()) }; // from this point, this_thr_fd is no longer valid const CWD: &[u8] = b"/scheme/initfs"; - let cwd_fd = - FdGuard::new(syscall::openat(initfs_fd, "", O_STAT, 0).expect("failed to open cwd fd")) - .to_upper() - .unwrap(); + let cwd_fd = FdGuard::new( + syscall::openat(initns_fd.as_raw_fd(), "/scheme/initfs", O_STAT, 0) + .expect("failed to open cwd fd"), + ) + .to_upper() + .unwrap(); let extrainfo = ExtraInfo { cwd: Some(CWD), sigprocmask: 0, @@ -186,14 +205,15 @@ pub fn main() -> ! { umask: redox_rt::sys::get_umask(), thr_fd: init_thr_fd.as_raw_fd(), proc_fd: init_proc_fd.as_raw_fd(), - ns_fd: Some(initns_fd), + ns_fd: Some(initns_fd.take()), cwd_fd: Some(cwd_fd.as_raw_fd()), }; - let path = "/bin/init"; + let path = "/scheme/initfs/bin/init"; let image_file = FdGuard::new( - syscall::openat(initfs_fd, path, O_RDONLY | O_CLOEXEC, 0).expect("failed to open init"), + syscall::openat(extrainfo.ns_fd.unwrap(), path, O_RDONLY | O_CLOEXEC, 0) + .expect("failed to open init"), ) .to_upper() .unwrap(); @@ -220,7 +240,7 @@ pub fn main() -> ! { let interp_cstr = CStr::from_bytes_with_nul(&interp_path).expect("interpreter not valid C str"); let interp_file = FdGuard::new( syscall::openat( - initns_fd, // initns, not initfs! + extrainfo.ns_fd.unwrap(), // initns, not initfs! interp_cstr.to_str().expect("interpreter not UTF-8"), O_RDONLY | O_CLOEXEC, 0, @@ -247,13 +267,24 @@ pub fn main() -> ! { pub(crate) fn spawn( name: &str, - auth: &FdGuard, + auth: FdGuard, this_thr_fd: &FdGuardUpper, - pipe_fd: usize, - inner: impl FnOnce(FdGuard) -> !, -) -> usize { + scheme_creation_cap: FdGuard, + kernel_schemes: KernelSchemeMap, + nonblock: bool, + inner: impl FnOnce(FdGuard, Socket, FdGuard, KernelSchemeMap) -> !, +) -> (FdGuard, FdGuard, KernelSchemeMap, FdGuard) { let read = FdGuard::new( - syscall::openat(pipe_fd, "", O_CLOEXEC, 0).expect("failed to open sync read pipe"), + syscall::openat( + kernel_schemes + .get(GlobalSchemes::Pipe) + .expect("failed to get pipe fd") + .as_raw_fd(), + "", + O_CLOEXEC, + 0, + ) + .expect("failed to open sync read pipe"), ); // The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later. @@ -261,13 +292,22 @@ pub(crate) fn spawn( syscall::dup(read.as_raw_fd(), b"write").expect("failed to open sync write pipe"), ); - match fork_impl(&ForkArgs::Init { this_thr_fd, auth }) { + match fork_impl(&ForkArgs::Init { + this_thr_fd, + auth: &auth, + }) { Err(err) => { panic!("Failed to fork in order to start {name}: {err}"); } // Continue serving the scheme as the child. Ok(0) => { drop(read); + + let socket = Socket::create_inner(scheme_creation_cap.as_raw_fd(), nonblock) + .expect("failed to open proc scheme socket"); + drop(scheme_creation_cap); + + inner(write, socket, auth, kernel_schemes) } // Return in order to execute init, as the parent. Ok(_) => { @@ -292,8 +332,12 @@ pub(crate) fn spawn( } } - return new_fd; + ( + scheme_creation_cap, + auth, + kernel_schemes, + FdGuard::new(new_fd), + ) } } - inner(write) } diff --git a/bootstrap/src/initfs.rs b/bootstrap/src/initfs.rs index 9340cc2dc2..209e771f37 100644 --- a/bootstrap/src/initfs.rs +++ b/bootstrap/src/initfs.rs @@ -24,8 +24,6 @@ use syscall::error::*; use syscall::flag::*; use syscall::schemev2::NewFdFlags; -use crate::KernelSchemeMap; - enum Handle { Node(Node), SchemeRoot, @@ -384,24 +382,11 @@ impl SchemeSync for InitFsScheme { } } -pub fn run( - bytes: &'static [u8], - sync_pipe: FdGuard, - kernel_schemes: &KernelSchemeMap, - scheme_creation_cap: usize, -) -> ! { +pub fn run(bytes: &'static [u8], sync_pipe: FdGuard, socket: Socket) -> ! { log::info!("bootstrap: starting initfs scheme"); let mut state = SchemeState::new(); let mut scheme = InitFsScheme::new(bytes); - let socket = Socket::create_inner(scheme_creation_cap, false) - .expect("failed to open initfs scheme socket"); - let _ = syscall::close(scheme_creation_cap); - - for fd in kernel_schemes.0.values() { - let _ = syscall::close(*fd); - } - // send open-capability to bootstrap let new_id = scheme.next_id(); scheme.handles.insert(new_id, Handle::SchemeRoot); diff --git a/bootstrap/src/initnsmgr.rs b/bootstrap/src/initnsmgr.rs index 103a5a2d2f..11a8a10405 100644 --- a/bootstrap/src/initnsmgr.rs +++ b/bootstrap/src/initnsmgr.rs @@ -489,14 +489,12 @@ where pub fn run( sync_pipe: FdGuard, + socket: Socket, schemes: HashMap>, - scheme_creation_cap: usize, + scheme_creation_cap: FdGuard, ) -> ! { - let socket = Socket::create_inner(scheme_creation_cap, false) - .expect("failed to open init namespace scheme socket"); - let mut state = SchemeState::new(); - let mut scheme = NamespaceScheme::new(&socket, schemes, FdGuard::new(scheme_creation_cap)); + let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap); // send namespace fd to bootstrap let new_id = scheme.next_id; diff --git a/bootstrap/src/lib.rs b/bootstrap/src/lib.rs index 0c4ec3fe5d..c99076ce8a 100644 --- a/bootstrap/src/lib.rs +++ b/bootstrap/src/lib.rs @@ -29,6 +29,7 @@ extern crate alloc; use core::cell::UnsafeCell; use alloc::collections::btree_map::BTreeMap; +use redox_rt::proc::FdGuard; use syscall::data::Map; use syscall::data::{GlobalSchemes, KernelSchemeInfo}; use syscall::flag::MapFlags; @@ -135,18 +136,18 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator { } } -pub struct KernelSchemeMap(BTreeMap); +pub struct KernelSchemeMap(BTreeMap); impl KernelSchemeMap { fn new(kernel_scheme_infos: &[KernelSchemeInfo]) -> Self { let mut map = BTreeMap::new(); for info in kernel_scheme_infos { if let Some(scheme_id) = GlobalSchemes::try_from_raw(info.scheme_id) { - map.insert(scheme_id, info.fd); + map.insert(scheme_id, FdGuard::new(info.fd)); } } Self(map) } - fn get(&self, scheme: GlobalSchemes) -> Option<&usize> { + fn get(&self, scheme: GlobalSchemes) -> Option<&FdGuard> { self.0.get(&scheme) } } diff --git a/bootstrap/src/procmgr.rs b/bootstrap/src/procmgr.rs index aa7121ab15..5e65a92664 100644 --- a/bootstrap/src/procmgr.rs +++ b/bootstrap/src/procmgr.rs @@ -29,7 +29,6 @@ use redox_scheme::{ Socket, Tag, }; use slab::Slab; -use syscall::data::GlobalSchemes; use syscall::schemev2::NewFdFlags; use syscall::{ CallFlags, ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED, @@ -39,8 +38,6 @@ use syscall::{ sig_bit, }; -use crate::KernelSchemeMap; - #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] enum VirtualId { KernelId(Id), @@ -48,31 +45,12 @@ enum VirtualId { InternalId(u64), } -pub fn run( - write_fd: FdGuard, - auth: &FdGuard, - kernel_schemes: &KernelSchemeMap, - scheme_creation_cap: usize, -) -> ! { - let socket = - Socket::create_inner(scheme_creation_cap, true).expect("failed to open proc scheme socket"); - let _ = syscall::close(scheme_creation_cap); - +pub fn run(write_fd: FdGuard, socket: Socket, auth: FdGuard, event: FdGuard) -> ! { // TODO? let socket_ident = socket.inner().raw(); - let queue = RawEventQueue::new( - *kernel_schemes - .get(GlobalSchemes::Event) - .expect("failed to get event fd"), - ) - .expect("failed to create event queue"); - for (scheme, fd) in kernel_schemes.0.iter() { - if *scheme == GlobalSchemes::Proc { - continue; - } - let _ = syscall::close(*fd); - } + let queue = RawEventQueue::new(event.as_raw_fd()).expect("failed to create event queue"); + drop(event); queue .subscribe(socket.inner().raw(), socket_ident, EventFlags::EVENT_READ) @@ -520,7 +498,7 @@ struct ProcScheme<'a> { next_id: ProcessId, queue: &'a RawEventQueue, - auth: &'a FdGuard, + auth: FdGuard, } #[derive(Debug, Default)] struct Pgrp { @@ -598,7 +576,7 @@ impl RawEventQueue { } impl<'a> ProcScheme<'a> { - pub fn new(auth: &'a FdGuard, queue: &'a RawEventQueue) -> ProcScheme<'a> { + pub fn new(auth: FdGuard, queue: &'a RawEventQueue) -> ProcScheme<'a> { ProcScheme { processes: HashMap::new(), groups: HashMap::new(), @@ -745,7 +723,7 @@ impl<'a> ProcScheme<'a> { })); if let Err(err) = new_process .borrow_mut() - .sync_kernel_attrs(child_pid, self.auth) + .sync_kernel_attrs(child_pid, &self.auth) { log::warn!("Failed to set kernel attrs when forking: {err}"); } @@ -1611,7 +1589,7 @@ impl<'a> ProcScheme<'a> { if let Some(new_sgid) = new_sgid { proc.sgid = new_sgid; } - if let Err(err) = proc.sync_kernel_attrs(pid, self.auth) { + if let Err(err) = proc.sync_kernel_attrs(pid, &self.auth) { log::warn!("Failed to sync proc attrs in setresugid: {err}"); } Ok(()) @@ -2393,7 +2371,7 @@ impl<'a> ProcScheme<'a> { .borrow_mut(); proc.name = ArrayString::from_str(&new_name[..new_name.len().min(NAME_CAPAC)]).unwrap(); - if let Err(err) = proc.sync_kernel_attrs(pid, self.auth) { + if let Err(err) = proc.sync_kernel_attrs(pid, &self.auth) { log::warn!("Failed to set kernel attrs when renaming proc: {err}"); } Ok(())