From b50d6fad52b02fd7727fd09cfbed5c0f288e8f21 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 10 Mar 2024 19:24:30 +0100 Subject: [PATCH 1/2] Support embedding bootstrap blob into the initfs --- src/aarch64.ld | 3 ++- src/exec.rs | 19 ++++++++++++------- src/i686.ld | 3 ++- src/start.rs | 5 +++-- src/x86_64.ld | 3 ++- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/aarch64.ld b/src/aarch64.ld index 3abb18108d..cee830f08a 100644 --- a/src/aarch64.ld +++ b/src/aarch64.ld @@ -2,7 +2,8 @@ ENTRY(_start) OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") SECTIONS { - . = 0; + . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ + __initfs_header = . - 4096; . += SIZEOF_HEADERS; . = ALIGN(4096); diff --git a/src/exec.rs b/src/exec.rs index a2bd02c324..d76a98105f 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -7,7 +7,7 @@ use syscall::flag::{O_CLOEXEC, O_RDONLY}; use redox_exec::*; pub fn main() -> ! { - let (initfs_offset, initfs_length); + let initfs_length; let envs = { let mut env = [0_u8; 4096]; @@ -23,7 +23,6 @@ pub fn main() -> ! { let raw_iter = || env.split(|c| *c == b'\n').filter(|var| !var.is_empty()); - let mut initfs_offset_opt = None; let mut initfs_length_opt = None; for var in raw_iter() { @@ -32,21 +31,27 @@ pub fn main() -> ! { let value = &var[equal_sign + 1..]; match name { - b"INITFS_OFFSET" => initfs_offset_opt = core::str::from_utf8(value).ok().and_then(|s| usize::from_str_radix(s, 16).ok()), b"INITFS_LENGTH" => initfs_length_opt = core::str::from_utf8(value).ok().and_then(|s| usize::from_str_radix(s, 16).ok()), _ => continue, } } - initfs_offset = initfs_offset_opt.expect("missing INITFS_OFFSET"); initfs_length = initfs_length_opt.expect("missing INITFS_LENGTH"); let iter = || raw_iter().filter(|var| !var.starts_with(b"INITFS_")); iter().map(|var| var.to_owned()).collect::>() }; + + extern { + // The linker script will define this as the location of the initfs header. + static __initfs_header: u8; + } + unsafe { - spawn_initfs(initfs_offset, initfs_length); + // 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. + spawn_initfs(core::ptr::addr_of!(__initfs_header), initfs_length); } const CWD: &[u8] = b"/scheme/initfs"; let extrainfo = redox_exec::ExtraInfo { @@ -65,7 +70,7 @@ pub fn main() -> ! { unreachable!() } -unsafe fn spawn_initfs(initfs_start: usize, initfs_length: usize) { +unsafe fn spawn_initfs(initfs_start: *const u8, initfs_length: usize) { let read = syscall::open("pipe:", O_CLOEXEC).expect("failed to open sync read pipe"); // The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later. @@ -92,5 +97,5 @@ unsafe fn spawn_initfs(initfs_start: usize, initfs_length: usize) { return; } } - crate::initfs::run(core::slice::from_raw_parts(initfs_start as *const u8, initfs_length), write); + crate::initfs::run(core::slice::from_raw_parts(initfs_start, initfs_length), write); } diff --git a/src/i686.ld b/src/i686.ld index e07ab63713..9bfb676b6b 100644 --- a/src/i686.ld +++ b/src/i686.ld @@ -2,7 +2,8 @@ ENTRY(_start) OUTPUT_FORMAT(elf32-i386) SECTIONS { - . = 0; + . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ + __initfs_header = . - 4096; . += SIZEOF_HEADERS; . = ALIGN(4096); diff --git a/src/start.rs b/src/start.rs index 920f285645..12b271b037 100644 --- a/src/start.rs +++ b/src/start.rs @@ -35,13 +35,14 @@ pub unsafe extern "C" fn start() -> ! { let _ = syscall::open("debug:", syscall::O_WRONLY); // stdout let _ = syscall::open("debug:", syscall::O_WRONLY); // stderr - // TODO: PROT_NONE - let _ = syscall::mprotect(0, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for NULL page"); + let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for initfs header page"); let _ = syscall::mprotect(text_start, text_end - text_start, MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE).expect("mprotect failed for .text"); let _ = syscall::mprotect(rodata_start, rodata_end - rodata_start, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for .rodata"); let _ = syscall::mprotect(data_start, data_end - data_start, MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE).expect("mprotect failed for .data/.bss"); let _ = syscall::mprotect(data_end, crate::arch::STACK_START - data_end, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE).expect("mprotect failed for rest of memory"); + // FIXME make the initfs read-only + crate::exec::main(); } diff --git a/src/x86_64.ld b/src/x86_64.ld index 232fbf72fc..ecb2094222 100644 --- a/src/x86_64.ld +++ b/src/x86_64.ld @@ -2,7 +2,8 @@ ENTRY(_start) OUTPUT_FORMAT(elf64-x86-64) SECTIONS { - . = 0; + . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ + __initfs_header = . - 4096; . += SIZEOF_HEADERS; . = ALIGN(4096); From 70700df944b932c253ad116881945fa0dfbb24eb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 12 Mar 2024 21:49:53 +0100 Subject: [PATCH 2/2] Update redox-initfs and use the initfs_size header field instead of INITFS_LENGTH --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/exec.rs | 21 +++------------------ 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 885b28f1f3..ad49099eb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,7 @@ dependencies = [ [[package]] name = "redox-initfs" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#89b8fb8984cf96c418880b7dcd9ce3d6afc3f71c" +source = "git+https://gitlab.redox-os.org/redox-os/redox-initfs.git#7dd9b2e84d983a444518218f3ec74d3e9ac900b3" dependencies = [ "plain", ] diff --git a/Cargo.toml b/Cargo.toml index feb816d5e8..9c7c863cac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["staticlib"] [dependencies] hashbrown = { version = "0.14", default-features = false, features = ["inline-more"] } linked_list_allocator = "0.10" -redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", features = ["kernel"], default-features = false } +redox-initfs = { git = "https://gitlab.redox-os.org/redox-os/redox-initfs.git", default-features = false } redox-exec = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" } redox_syscall = "0.4" diff --git a/src/exec.rs b/src/exec.rs index d76a98105f..37f7781a17 100644 --- a/src/exec.rs +++ b/src/exec.rs @@ -7,8 +7,6 @@ use syscall::flag::{O_CLOEXEC, O_RDONLY}; use redox_exec::*; pub fn main() -> ! { - let initfs_length; - let envs = { let mut env = [0_u8; 4096]; @@ -23,21 +21,6 @@ pub fn main() -> ! { let raw_iter = || env.split(|c| *c == b'\n').filter(|var| !var.is_empty()); - let mut initfs_length_opt = None; - - for var in raw_iter() { - let equal_sign = var.iter().position(|c| *c == b'=').expect("malformed environment variable"); - let name = &var[..equal_sign]; - let value = &var[equal_sign + 1..]; - - match name { - b"INITFS_LENGTH" => initfs_length_opt = core::str::from_utf8(value).ok().and_then(|s| usize::from_str_radix(s, 16).ok()), - - _ => continue, - } - } - initfs_length = initfs_length_opt.expect("missing INITFS_LENGTH"); - let iter = || raw_iter().filter(|var| !var.starts_with(b"INITFS_")); iter().map(|var| var.to_owned()).collect::>() @@ -48,10 +31,12 @@ pub fn main() -> ! { static __initfs_header: u8; } + let initfs_length = unsafe { (*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size }; + 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. - spawn_initfs(core::ptr::addr_of!(__initfs_header), initfs_length); + spawn_initfs(core::ptr::addr_of!(__initfs_header), initfs_length.get() as usize); } const CWD: &[u8] = b"/scheme/initfs"; let extrainfo = redox_exec::ExtraInfo {