From d5ff91f24852c5f37b65a135692565e776d28bcb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Dec 2025 21:45:10 +0100 Subject: [PATCH 1/2] Support mmap in initfs --- bootstrap/src/initfs.rs | 40 +++++++++++++++++++++++++++++--- bootstrap/src/lib.rs | 2 +- initfs/Cargo.toml | 2 +- initfs/archive-common/src/lib.rs | 9 +++++-- initfs/src/lib.rs | 8 ++++++- initfs/src/types.rs | 1 + initfs/tests/archive_and_read.rs | 5 ++-- initfs/tools/src/bin/dump.rs | 2 +- 8 files changed, 58 insertions(+), 11 deletions(-) diff --git a/bootstrap/src/initfs.rs b/bootstrap/src/initfs.rs index 062068d313..0fcfbe98dd 100644 --- a/bootstrap/src/initfs.rs +++ b/bootstrap/src/initfs.rs @@ -6,10 +6,10 @@ use core::str; use alloc::string::String; use hashbrown::HashMap; -use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct, types::Timespec}; +use redox_initfs::{types::Timespec, InitFs, Inode, InodeDir, InodeKind, InodeStruct}; use redox_path::canonicalize_to_standard; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, scheme::SchemeSync}; +use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, RequestKind}; use redox_scheme::{SignalBehavior, Socket}; use syscall::data::Stat; @@ -19,6 +19,7 @@ use syscall::dirent::DirentKind; use syscall::error::*; use syscall::flag::*; use syscall::schemev2::NewFdFlags; +use syscall::PAGE_SIZE; struct Handle { inode: Inode, @@ -37,7 +38,8 @@ impl InitFsScheme { Self { handles: HashMap::default(), next_id: 0, - fs: InitFs::new(bytes).expect("failed to parse initfs"), + fs: InitFs::new(bytes, Some(PAGE_SIZE.try_into().unwrap())) + .expect("failed to parse initfs"), } } @@ -303,6 +305,38 @@ impl SchemeSync for InitFsScheme { Ok(()) } + + fn mmap_prep( + &mut self, + id: usize, + offset: u64, + size: usize, + flags: MapFlags, + _ctx: &CallerCtx, + ) -> syscall::Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let data = match Self::get_inode(&self.fs, handle.inode)?.kind() { + InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?, + InodeKind::Dir(_) => return Err(Error::new(EISDIR)), + InodeKind::Link(link) => return Err(Error::new(ELOOP)), + InodeKind::Unknown => return Err(Error::new(EIO)), + }; + + if flags.contains(MapFlags::PROT_WRITE) { + return Err(Error::new(EPERM)); + } + + let Some(last_addr) = offset.checked_add(size as u64) else { + return Err(Error::new(EINVAL)); + }; + + if last_addr > data.len().next_multiple_of(PAGE_SIZE) as u64 { + return Err(Error::new(EINVAL)); + } + + Ok(data.as_ptr() as usize) + } } pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! { diff --git a/bootstrap/src/lib.rs b/bootstrap/src/lib.rs index 6ed7505f9c..f319b2e97e 100644 --- a/bootstrap/src/lib.rs +++ b/bootstrap/src/lib.rs @@ -1,6 +1,6 @@ #![no_std] #![allow(internal_features)] -#![feature(core_intrinsics, let_chains, iter_intersperse, str_from_raw_parts)] +#![feature(core_intrinsics, iter_intersperse, str_from_raw_parts)] #[cfg(target_arch = "aarch64")] #[path = "aarch64.rs"] diff --git a/initfs/Cargo.toml b/initfs/Cargo.toml index 250ddd3bd2..7fd8f3c4cc 100644 --- a/initfs/Cargo.toml +++ b/initfs/Cargo.toml @@ -2,7 +2,7 @@ name = "redox-initfs" version = "0.2.0" authors = ["4lDO2 <4lDO2@protonmail.com>", "Kamil Koczurek "] -edition = "2021" +edition = "2024" license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/initfs/archive-common/src/lib.rs b/initfs/archive-common/src/lib.rs index 97dc8d3347..7733a39324 100644 --- a/initfs/archive-common/src/lib.rs +++ b/initfs/archive-common/src/lib.rs @@ -19,6 +19,9 @@ pub const DEFAULT_MAX_SIZE: u64 = 128 * MEBIBYTE; #[cfg(not(debug_assertions))] pub const DEFAULT_MAX_SIZE: u64 = 64 * MEBIBYTE; +// FIXME make this configurable to handle systems with 16k and 64k pages. +const PAGE_SIZE: u16 = 4096; + enum EntryKind { File(File), Dir(Dir), @@ -153,9 +156,10 @@ fn read_directory(state: &mut State, path: &Path, root_path: &Path) -> Result Result { - if state.offset + size <= state.max_size { + let end = (state.offset + size).next_multiple_of(PAGE_SIZE.into()); + if end <= state.max_size { let offset = state.offset; - state.offset += size; + state.offset = end; log::debug!("Allocating range {}..{} in {}", offset, state.offset, why); Ok(offset) } else { @@ -559,6 +563,7 @@ pub fn archive( .context("failed to get initfs size")? .len() .into(), + page_size: PAGE_SIZE.into(), }; write_all_at(&state.file, &header_bytes, header_offset, "writing header") .context("failed to write header")?; diff --git a/initfs/src/lib.rs b/initfs/src/lib.rs index 0e77a0dcc7..328bbc27bc 100644 --- a/initfs/src/lib.rs +++ b/initfs/src/lib.rs @@ -182,7 +182,7 @@ impl<'initfs> InodeStruct<'initfs> { } impl<'initfs> InitFs<'initfs> { - pub fn new(base: &'initfs [u8]) -> Result { + pub fn new(base: &'initfs [u8], required_page_size: Option) -> Result { let this = Self { base }; if base.len() < core::mem::size_of::
() { @@ -214,6 +214,12 @@ impl<'initfs> InitFs<'initfs> { return Err(Error); } + if let Some(required_page_size) = required_page_size + && header.page_size.get() != required_page_size + { + return Err(Error); + } + // From now on, we can be completely sure that the header and inode tables offsets are // valid, and thus continue based on that assumption. diff --git a/initfs/src/types.rs b/initfs/src/types.rs index 6951bd86dc..e1c6cb8936 100644 --- a/initfs/src/types.rs +++ b/initfs/src/types.rs @@ -73,6 +73,7 @@ pub struct Header { pub inode_count: U16, pub bootstrap_entry: U64, pub initfs_size: U64, + pub page_size: U16, } const _: () = { diff --git a/initfs/tests/archive_and_read.rs b/initfs/tests/archive_and_read.rs index 294d9defe0..00880b878a 100644 --- a/initfs/tests/archive_and_read.rs +++ b/initfs/tests/archive_and_read.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, path::Path}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result, anyhow}; use redox_initfs::{InitFs, InodeKind, InodeStruct}; #[derive(Debug, Clone, PartialEq)] @@ -83,7 +83,8 @@ fn archive_and_read() -> Result<()> { archive_common::archive(&args).context("failed to archive")?; let data = std::fs::read(args.destination_path).context("failed to read new archive")?; - let filesystem = redox_initfs::InitFs::new(&data).context("failed to parse archive header")?; + let filesystem = + redox_initfs::InitFs::new(&data, None).context("failed to parse archive header")?; let inode = filesystem .get_inode(redox_initfs::InitFs::ROOT_INODE) .ok_or_else(|| anyhow!("Failed to get root inode"))?; diff --git a/initfs/tools/src/bin/dump.rs b/initfs/tools/src/bin/dump.rs index 414d58be0d..aed7496167 100644 --- a/initfs/tools/src/bin/dump.rs +++ b/initfs/tools/src/bin/dump.rs @@ -23,7 +23,7 @@ fn main() -> Result<()> { .expect("expected the required arg IMAGE to exist"); let bytes = std::fs::read(source).context("failed to read image into memory")?; - let initfs = InitFs::new(&bytes).context("failed to parse initfs header")?; + let initfs = InitFs::new(&bytes, None).context("failed to parse initfs header")?; dbg!(initfs.header()); From bd184871b74b0054857382d6d03a20853658a04f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Dec 2025 21:46:32 +0100 Subject: [PATCH 2/2] Update redox-rt --- Cargo.lock | 4 ++-- bootstrap/Cargo.lock | 4 ++-- bootstrap/src/exec.rs | 5 ----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99235e2c24..787f1dfceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -802,7 +802,7 @@ dependencies = [ [[package]] name = "generic-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#7fcab3a43a6cf023aacd3ac9ced2a479b7f9c455" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#9db10bb0a9651b86012a0d58a3327df95a20a297" [[package]] name = "getrandom" @@ -1612,7 +1612,7 @@ dependencies = [ [[package]] name = "redox-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#7fcab3a43a6cf023aacd3ac9ced2a479b7f9c455" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#9db10bb0a9651b86012a0d58a3327df95a20a297" dependencies = [ "bitflags 2.10.0", "generic-rt", diff --git a/bootstrap/Cargo.lock b/bootstrap/Cargo.lock index 269eacbdcb..5c1c1771d1 100644 --- a/bootstrap/Cargo.lock +++ b/bootstrap/Cargo.lock @@ -40,7 +40,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "generic-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#fe5273890a8f39f8ffa1507bfb243d76270e8a27" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#9db10bb0a9651b86012a0d58a3327df95a20a297" [[package]] name = "goblin" @@ -143,7 +143,7 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717" [[package]] name = "redox-rt" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#fe5273890a8f39f8ffa1507bfb243d76270e8a27" +source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#9db10bb0a9651b86012a0d58a3327df95a20a297" dependencies = [ "bitflags", "generic-rt", diff --git a/bootstrap/src/exec.rs b/bootstrap/src/exec.rs index de7a5f899b..d1f7f473d7 100644 --- a/bootstrap/src/exec.rs +++ b/bootstrap/src/exec.rs @@ -107,16 +107,11 @@ pub fn main() -> ! { .expect("failed to open init") .to_upper() .unwrap(); - let memory = FdGuard::open("/scheme/memory", O_CLOEXEC) - .expect("failed to open memory") - .to_upper() - .unwrap(); fexec_impl( image_file, init_thr_fd, init_proc_fd, - &memory, path.as_bytes(), &[path.as_bytes()], &envs,