From b2ed85ea0defe02576edbb633b2976ae9f7c3a6e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 13 Jul 2026 20:19:49 +0200 Subject: [PATCH 1/7] Deduplicate event trb processing between polling and interrupt reactor --- drivers/usb/xhcid/src/xhci/irq_reactor.rs | 163 +++++++++++----------- 1 file changed, 80 insertions(+), 83 deletions(-) diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs index 53248fb23f..efe8f74610 100644 --- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs +++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs @@ -104,6 +104,12 @@ pub struct IrqReactor { pub type NewPendingTrb = State; +enum EventProcessResult { + NoEvent, + EventRingFull, + RegularEvent, +} + impl IrqReactor { pub fn new(hci: Arc>, irq_file: Option) -> Self { let device_enumerator_sender = hci.device_enumerator_sender.clone(); @@ -139,45 +145,14 @@ impl IrqReactor { let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); - let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - - if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - continue 'trb_loop; - } - - trace!( - "Found event TRB at index {} with type {} and cycle bit {}: {:?}", - event_trb_index, - event_trb.trb_type(), - event_trb.cycle() as u8, - event_trb - ); - - if self.check_event_ring_full(event_trb.clone()) { - info!("Had to resize event TRB, retrying..."); - continue 'trb_loop; - } - - trace!("Handling requests"); - self.handle_requests(); - trace!("Requests handled"); - - match event_trb.trb_type() { - _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { - trace!("Received a port status change!"); - self.handle_port_status_change(event_trb.clone()) - } //TODO Handle the other unprompted events - _ => { - self.acknowledge(event_trb.clone()); + loop { + match self.process_one_event(&mut event_ring, &mut event_trb_index) { + EventProcessResult::NoEvent | EventProcessResult::EventRingFull => { + continue 'trb_loop + } + EventProcessResult::RegularEvent => {} } } - - event_trb.reserved(false); - - self.update_erdp(&*event_ring); - hci_clone.event_handler_finished(); - - event_trb_index = event_ring.ring.next_index(); } } @@ -258,61 +233,83 @@ impl IrqReactor { loop { trace!("count: {}", count); - let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - if count == 0 { - warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") + match self.process_one_event(&mut event_ring, &mut event_trb_index) { + EventProcessResult::NoEvent => { + if count == 0 { + warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") + } + self.unmask_interrupts(); + continue 'trb_loop; } - //hci_clone.event_handler_finished(); - self.unmask_interrupts(); - continue 'trb_loop; - } else { - count += 1 - } - - info!( - "Found event TRB at index {} with type {} and cycle bit {}: {:?}", - event_trb_index, - event_trb.trb_type(), - event_trb.cycle() as u8, - event_trb - ); - - if self.check_event_ring_full(event_trb.clone()) { - info!("Had to resize event TRB, retrying..."); - //hci_clone.event_handler_finished(); - if self.hci.interrupt_is_pending(0) { - warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") - } else { - debug!("The interrupt bit is no longer pending."); + EventProcessResult::EventRingFull => { + if self.hci.interrupt_is_pending(0) { + warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") + } else { + debug!("The interrupt bit is no longer pending."); + } + self.unmask_interrupts(); + continue 'trb_loop; } - self.unmask_interrupts(); - continue 'trb_loop; - } - self.handle_requests(); - - match event_trb.trb_type() { - _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { - trace!("Received a port status change!"); - self.handle_port_status_change(event_trb.clone()) - } //TODO Handle the other unprompted events - _ => { - trace!("Received a non-status trb"); - self.acknowledge(event_trb.clone()); + EventProcessResult::RegularEvent => { + count += 1; } } - - event_trb.reserved(false); - - self.update_erdp(&*event_ring); - self.hci.event_handler_finished(); - - event_trb_index = event_ring.ring.next_index(); } } } + fn process_one_event( + &mut self, + event_ring: &mut EventRing, + event_trb_index: &mut usize, + ) -> EventProcessResult { + let event_trb = &mut event_ring.ring.trbs[*event_trb_index]; + + if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { + //hci_clone.event_handler_finished(); + return EventProcessResult::NoEvent; + } + + trace!( + "Found event TRB at index {} with type {} and cycle bit {}: {:?}", + event_trb_index, + event_trb.trb_type(), + event_trb.cycle() as u8, + event_trb + ); + + if self.check_event_ring_full(event_trb.clone()) { + info!("Had to resize event TRB, retrying..."); + //hci_clone.event_handler_finished(); + return EventProcessResult::EventRingFull; + } + + trace!("Handling requests"); + self.handle_requests(); + trace!("Requests handled"); + + match event_trb.trb_type() { + _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { + trace!("Received a port status change!"); + self.handle_port_status_change(event_trb.clone()) + } //TODO Handle the other unprompted events + _ => { + trace!("Received a non-status trb"); + self.acknowledge(event_trb.clone()); + } + } + + event_trb.reserved(false); + + self.update_erdp(&*event_ring); + self.hci.event_handler_finished(); + + *event_trb_index = event_ring.ring.next_index(); + + EventProcessResult::RegularEvent + } + /// Handles device attach/detach events as indicated by a PortStatusChange fn handle_port_status_change(&mut self, trb: Trb) { if let Some(root_hub_port_num) = trb.port_status_change_port_id() { From a01d3ce6e5248ee612d73ae7dffb0627a51fa410 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 13 Jul 2026 20:23:20 +0200 Subject: [PATCH 2/7] Fix a race condition when receiving events before unmasking interrupts --- drivers/usb/xhcid/src/xhci/irq_reactor.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs index efe8f74610..1b27479527 100644 --- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs +++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs @@ -240,9 +240,20 @@ impl IrqReactor { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } self.unmask_interrupts(); + + // Process any events received between the NoEvent and unmasking interrupts + loop { + match self.process_one_event(&mut event_ring, &mut event_trb_index) { + EventProcessResult::NoEvent => break, + EventProcessResult::EventRingFull + | EventProcessResult::RegularEvent => {} + } + } + continue 'trb_loop; } EventProcessResult::EventRingFull => { + // FIXME can this use the RegularEvent path? if self.hci.interrupt_is_pending(0) { warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") } else { From e26db606d11df5ffcbc3337d31ca6ebbb0b3d387 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Jul 2026 18:19:44 +0200 Subject: [PATCH 3/7] randd: Significantly simplify file permission handling There isn't really a need to support chown/chmod of the rand scheme. It adds a fair bit of complexity without adding any security over unconditionally allowing reads by anyone and writes by root. If we want to restore support for chown/chmod, we should probably do so in a generic way that covers all device schemes. --- randd/src/main.rs | 200 +++------------------------------------------- 1 file changed, 11 insertions(+), 189 deletions(-) diff --git a/randd/src/main.rs b/randd/src/main.rs index a77057a379..37c179a4f1 100644 --- a/randd/src/main.rs +++ b/randd/src/main.rs @@ -3,11 +3,6 @@ use std::arch::asm; use rand_chacha::ChaCha20Rng; use rand_core::RngCore; -pub const MODE_PERM: u16 = 0x0FFF; -pub const MODE_EXEC: u16 = 0o1; -pub const MODE_WRITE: u16 = 0o2; -pub const MODE_READ: u16 = 0o4; - #[cfg(target_arch = "x86_64")] use raw_cpuid::CpuId; @@ -27,8 +22,6 @@ use sha2::{Digest, Sha256}; // We do not implement blocking reads as per linux /dev/random for the reasons outlined // here: https://www.2uo.de/myths-about-urandom/ -// Default file access mode for PRNG -const DEFAULT_PRNG_MODE: u16 = 0o644; // Rand crate recommends at least 256 bits of entropy to seed the RNG const SEED_BYTES: usize = 32; @@ -90,33 +83,9 @@ fn create_rdrand_seed() -> [u8; SEED_BYTES] { /// Contains information about an open file struct OpenFileInfo { o_flags: usize, - /// Flags used when opening file. - uid: u32, - gid: u32, - file_stat: Stat, } impl OpenFileInfo { - /// Tests if the current user has enough permissions to view the file, op is the operation, - /// like read and write, these modes are MODE_EXEC, MODE_READ, and MODE_WRITE - /// Copied from redoxfs - fn permission(&self, op: u16) -> bool { - let mut perm = self.file_stat.st_mode & 0o7; - if self.uid == self.file_stat.st_uid { - // If self.mode is 101100110, >> 6 would be 000000101 - // 0o7 is octal for 111, or, when expanded to 9 digits is 000000111 - perm |= (self.file_stat.st_mode >> 6) & 0o7; - // Since we erased the GID and OTHER bits when >>6'ing, |= will keep those bits in place. - } - if self.gid == self.file_stat.st_gid || self.file_stat.st_gid == 0 { - perm |= (self.file_stat.st_mode >> 3) & 0o7; - } - if self.uid == 0 { - //set the `other` bits to 111 - perm |= 0o7; - } - perm & op == op - } fn o_flag_set(&self, f: usize) -> bool { return (f & self.o_flags) == f; } @@ -142,7 +111,6 @@ struct RandScheme { // ChaCha20 is a Cryptographically Secure PRNG // https://docs.rs/rand/0.5.0/rand/prng/chacha/struct.ChaChaRng.html // Allows 2^64 streams of random numbers, which we will equate with file numbers - prng_stat: Stat, handles: HandleMap, } @@ -151,12 +119,6 @@ impl RandScheme { fn new() -> RandScheme { RandScheme { prng: ChaCha20Rng::from_seed(create_rdrand_seed()), - prng_stat: Stat { - st_mode: MODE_CHR | DEFAULT_PRNG_MODE, - st_gid: 0, - st_uid: 0, - ..Default::default() - }, handles: HandleMap::new(), } } @@ -170,12 +132,11 @@ impl RandScheme { /// Checks to see if the op (MODE_READ, MODE_WRITE) can be performed on the open file /// descriptor - Will return the open file info if successful, and error if the file /// descriptor is invalid, or the permission is denied. - fn can_perform_op_on_fd(&self, fd: usize, op: u16) -> Result<&OpenFileInfo> { - let file_info = self.get_fd(fd)?; - if !file_info.permission(op) { + fn can_perform_op_on_fd(&self, fd: usize, f: usize) -> Result<()> { + if !self.get_fd(fd)?.o_flag_set(f) { return Err(Error::new(EPERM)); } - Ok(file_info) + Ok(()) } /// Reseed the CSPRNG with the supplied entropy. /// TODO add this to an entropy pool and give a limited estimate to the amount of entropy @@ -202,20 +163,10 @@ impl RandScheme { return Err(Error::new(EEXIST)); } - let open_file_info = OpenFileInfo { - o_flags: flags, - file_stat: self.prng_stat, - uid: ctx.uid, - gid: ctx.gid, - }; + let open_file_info = OpenFileInfo { o_flags: flags }; - if (open_file_info.o_flag_set(O_RDONLY) || open_file_info.o_flag_set(O_RDWR)) - && !open_file_info.permission(MODE_READ) - { - return Err(Error::new(EPERM)); - } if (open_file_info.o_flag_set(O_WRONLY) || open_file_info.o_flag_set(O_RDWR)) - && !open_file_info.permission(MODE_WRITE) + && ctx.uid != 0 { return Err(Error::new(EPERM)); } @@ -228,109 +179,6 @@ impl RandScheme { }) } } -#[test] -fn test_scheme_perms() { - use libredox::protocol::O_CLOEXEC; - use syscall::O_STAT; - - let mut ctx = CallerCtx { - pid: 0, - uid: 1, - gid: 1, - id: unsafe { std::mem::zeroed() }, // Id doesn't have a public constructor - }; - - let mut scheme = RandScheme::new(); - scheme.prng_stat.st_mode = MODE_CHR | 0o200; - scheme.prng_stat.st_uid = 1; - scheme.prng_stat.st_gid = 1; - assert!(scheme.open_inner("/", O_RDWR, &ctx).is_err()); - assert!(scheme.open_inner("/", O_RDONLY, &ctx).is_err()); - - scheme.prng_stat.st_mode = MODE_CHR | 0o400; - let mut fd = match scheme.open("", O_RDONLY, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err()); - scheme.on_close(fd); - - assert!(scheme.open_inner("", O_WRONLY, &ctx).is_err()); - assert!(scheme.open_inner("", O_RDWR, &ctx).is_err()); - - scheme.prng_stat.st_mode = MODE_CHR | 0o600; - fd = match scheme.open_inner("", O_RDWR, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok()); - scheme.on_close(fd); - - ctx.uid = 2; - ctx.gid = 2; - fd = match scheme.open_inner("", O_STAT, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err()); - scheme.on_close(fd); - fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err()); - scheme.on_close(fd); - - // Try another user in group (no group perms) - ctx.uid = 2; - ctx.gid = 1; - fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err()); - scheme.on_close(fd); - scheme.prng_stat.st_mode = MODE_CHR | 0o660; - fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok()); - scheme.on_close(fd); - - // Check root can do anything - scheme.prng_stat.st_mode = MODE_CHR | 0o000; - ctx.uid = 0; - ctx.gid = 0; - fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok()); - scheme.on_close(fd); - - // Check the rand:/urandom URL (Equivalent to rand:/) - scheme.prng_stat.st_mode = MODE_CHR | 0o660; - ctx.uid = 2; - ctx.gid = 1; - fd = match scheme - .open_inner("/urandom", O_STAT | O_CLOEXEC, &ctx) - .unwrap() - { - OpenResult::ThisScheme { number, .. } => number, - _ => panic!(), - }; - assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok()); - assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok()); - scheme.on_close(fd); -} impl SchemeSync for RandScheme { fn scheme_root(&mut self) -> Result { @@ -362,7 +210,7 @@ impl SchemeSync for RandScheme { _ctx: &CallerCtx, ) -> Result { // Check fd and permissions - self.can_perform_op_on_fd(id, MODE_READ)?; + self.can_perform_op_on_fd(id, O_RDONLY)?; // Setting the stream will ensure that if two clients are reading concurrently, they won't get the same numbers self.prng.set_stream(id as u64); // Should probably find a way to re-instate the counter for this stream, but @@ -381,7 +229,7 @@ impl SchemeSync for RandScheme { _ctx: &CallerCtx, ) -> Result { // Check fd and permissions - self.can_perform_op_on_fd(id, MODE_WRITE)?; + self.can_perform_op_on_fd(id, O_WRONLY)?; // TODO - when we support other entropy sources, just add this to an entropy pool // TODO - consider having trusted and untrusted entropy writing paths @@ -399,31 +247,6 @@ impl SchemeSync for RandScheme { Ok(buf.len()) } - fn fchmod(&mut self, id: usize, mode: u16, ctx: &CallerCtx) -> Result<()> { - // Check fd and permissions - let file_info = self.get_fd(id)?; - // only root and owner can chmod - if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 { - return Err(Error::new(EPERM)); - } - - self.prng_stat.st_mode = MODE_CHR | (mode & MODE_PERM); // Apply mask - Ok(()) - } - - fn fchown(&mut self, id: usize, uid: u32, gid: u32, ctx: &CallerCtx) -> Result<()> { - // Check fd and permissions - let file_info = self.get_fd(id)?; - // only root and owner can fchown - if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 { - return Err(Error::new(EPERM)); - } - - self.prng_stat.st_uid = uid; - self.prng_stat.st_gid = gid; - Ok(()) - } - fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { // Just ignore this. Ok(0) @@ -436,11 +259,10 @@ impl SchemeSync for RandScheme { FpathWriter::with(buf, "rand", |_| Ok(())) } - fn fstat(&mut self, file: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - // Check fd and permissions - self.can_perform_op_on_fd(file, MODE_READ)?; - - *stat = self.prng_stat.clone(); + fn fstat(&mut self, _file: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { + stat.st_mode = 0o644 | MODE_CHR; + stat.st_uid = 0; + stat.st_gid = 0; Ok(()) } From add972864e8f98ab4932ea0894def27ab6c5643b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:00:01 +0200 Subject: [PATCH 4/7] Add /dev/ptmx symlink This is the standard location for ptmx across unixes though POSIX doesn't strictly mandate it to exist. It only mandates posix_openpt() to work. --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index cd652607b5..3b984d1e20 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,7 @@ install-base: base $(SYSROOT)/bin/redoxfs # Device file symlinks @mkdir -pv "$(DESTDIR)/dev" ln -sf /scheme/null $(DESTDIR)/dev/null + ln -sf /scheme/pty/ptmx $(DESTDIR)/dev/ptmx ln -sf /scheme/rand $(DESTDIR)/dev/random ln -sf /scheme/rand $(DESTDIR)/dev/urandom ln -sf /scheme/zero $(DESTDIR)/dev/zero From 5c6f460bbb5e98527f4c6f436f81c9fee49eac97 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:16:35 +0200 Subject: [PATCH 5/7] Stop using the legacy path format in fpath For fbbootlog, fbcon and the disk drivers there is no load bearing use of the fpath output. And for chan relibc already handles both the legacy and new format. --- drivers/graphics/fbbootlogd/src/scheme.rs | 2 +- drivers/graphics/fbcond/src/scheme.rs | 2 +- drivers/storage/driver-block/src/lib.rs | 2 +- ipcd/src/chan.rs | 2 +- scheme-utils/src/lib.rs | 11 ----------- 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/graphics/fbbootlogd/src/scheme.rs b/drivers/graphics/fbbootlogd/src/scheme.rs index 67bcede4d7..3c4455232e 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -197,7 +197,7 @@ impl SchemeSync for FbbootlogScheme { } fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, "fbbootlog", |_| Ok(())) + FpathWriter::with(buf, "fbbootlog", |_| Ok(())) } fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { diff --git a/drivers/graphics/fbcond/src/scheme.rs b/drivers/graphics/fbcond/src/scheme.rs index a8a497831c..dcbde34633 100644 --- a/drivers/graphics/fbcond/src/scheme.rs +++ b/drivers/graphics/fbcond/src/scheme.rs @@ -163,7 +163,7 @@ impl SchemeSync for FbconScheme { } fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, "fbcon", |w| { + FpathWriter::with(buf, "fbcon", |w| { let handle = self.get_vt_handle_mut(id)?; write!(w, "{}", handle.vt_i.0).unwrap(); Ok(()) diff --git a/drivers/storage/driver-block/src/lib.rs b/drivers/storage/driver-block/src/lib.rs index 315aa659d1..183bc90fc1 100644 --- a/drivers/storage/driver-block/src/lib.rs +++ b/drivers/storage/driver-block/src/lib.rs @@ -559,7 +559,7 @@ impl SchemeAsync for DiskSchemeInner { } async fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, &self.scheme_name, |w| { + FpathWriter::with(buf, &self.scheme_name, |w| { match *self.handles.get(id)? { Handle::List(_) => (), Handle::Disk(number) => { diff --git a/ipcd/src/chan.rs b/ipcd/src/chan.rs index ec19751283..d4a195e237 100644 --- a/ipcd/src/chan.rs +++ b/ipcd/src/chan.rs @@ -331,7 +331,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> { } } fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, "chan", |w| { + FpathWriter::with(buf, "chan", |w| { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Extra::SchemeRoot = handle.extra { return Ok(()); diff --git a/scheme-utils/src/lib.rs b/scheme-utils/src/lib.rs index b262939c6b..08e2380e19 100644 --- a/scheme-utils/src/lib.rs +++ b/scheme-utils/src/lib.rs @@ -92,17 +92,6 @@ impl<'a> FpathWriter<'a> { Ok(w.written) } - pub fn with_legacy( - buf: &'a mut [u8], - scheme_name: &str, - f: impl FnOnce(&mut Self) -> Result<()>, - ) -> Result { - let mut w = FpathWriter { buf, written: 0 }; - write!(w, "{scheme_name}:").unwrap(); - f(&mut w)?; - Ok(w.written) - } - pub fn push_str(&mut self, s: &str) { let count = core::cmp::min(s.len(), self.buf.len() - self.written); self.buf[self.written..self.written + count].copy_from_slice(&s.as_bytes()[..count]); From 4abaae000bfeba58106f2da049a3c8b1bf1fe637 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Fri, 17 Jul 2026 03:31:40 +0700 Subject: [PATCH 6/7] nvmed: Use correct TimeSpec for timeout --- drivers/storage/nvmed/src/main.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/storage/nvmed/src/main.rs b/drivers/storage/nvmed/src/main.rs index 658af32731..acf0953b2f 100644 --- a/drivers/storage/nvmed/src/main.rs +++ b/drivers/storage/nvmed/src/main.rs @@ -40,19 +40,14 @@ impl Disk for NvmeDisk { } fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> { - let mut time_buf = [0_u8; core::mem::size_of::()]; + let mut time_buf = syscall::TimeSpec::default(); if time_handle.read(&mut time_buf)? < time_buf.len() { return Err(io::Error::new( io::ErrorKind::InvalidData, "time read too small", )); } - - match libredox::data::timespec_from_mut_bytes(&mut time_buf) { - time => { - time.tv_sec += secs; - } - } + time_buf.tv_sec += secs; time_handle.write(&time_buf)?; Ok(()) } From 01018feece95bd15aab3d5de006bb1b569cd3d0e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 18 Jul 2026 10:54:07 +0200 Subject: [PATCH 7/7] Fix support for dynamically linked init --- Makefile | 2 +- bootstrap/src/exec.rs | 19 +++---------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 3b984d1e20..b0d26983a6 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ base: --manifest-path "$(SRC_DIR)/Cargo.toml" \ $(INITFS_CARGO_ARGS) $(INITFS_DRIVERS_CARGO_ARGS) # Build bootstrap - cd "$(SRC_DIR)/bootstrap" && $(CARGO) rustc $(BUILD_FLAGS) \ + cd "$(SRC_DIR)/bootstrap" && RUSTFLAGS= $(CARGO) rustc $(BUILD_FLAGS) \ -- -Ctarget-feature=+crt-static -Clinker="$(LINKER)" install-base: base $(SYSROOT)/bin/redoxfs diff --git a/bootstrap/src/exec.rs b/bootstrap/src/exec.rs index 610a3442d1..d593988725 100644 --- a/bootstrap/src/exec.rs +++ b/bootstrap/src/exec.rs @@ -238,8 +238,6 @@ pub fn main() -> ! { .openat_into_upper(exe_reference, O_RDONLY | O_CLOEXEC, 0) .expect("failed to open init"); - drop(initfs_root_fd); - let FexecResult::Interp { path: interp_path, interp_override, @@ -261,24 +259,13 @@ pub fn main() -> ! { // null-terminated. Violating this should therefore give the "format error" ENOEXEC. let interp_cstr = CStr::from_bytes_with_nul(&interp_path).expect("interpreter not valid C str"); let interp_path = interp_cstr.to_str().expect("interpreter not UTF-8"); - let root_fd = FdGuard::new( - redox_rt::sys::openat_into_upper( - extrainfo.ns_fd.unwrap(), // initns, not initfs! - interp_path, - O_RDONLY | O_CLOEXEC, - 0, - ) - .expect("failed to open root fd"), - ) - .to_upper() - .unwrap(); let redox_path = redox_path::RedoxPath::from_absolute(interp_path) .expect("interpreter path is not a Scheme-rooted path"); - let (_, reference) = redox_path + let (_, interp_reference) = redox_path .as_parts() .expect("redox_path is not scheme root path"); - let interp_file = root_fd - .openat_into_upper(reference.as_ref(), O_RDONLY | O_CLOEXEC, 0) + let interp_file = initfs_root_fd + .openat_into_upper(interp_reference.as_ref(), O_RDONLY | O_CLOEXEC, 0) .expect("failed to open dynamic linker"); fexec_impl(