From 836e6d264599a179cfc724fd64b715aec08cbd86 Mon Sep 17 00:00:00 2001 From: vasilito Date: Fri, 10 Jul 2026 10:51:37 +0300 Subject: [PATCH] iommu: fix unsafe-as-cast syntax in host stubs (Rust 2024 edition) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parenthesize because Rust 2024 edition does not allow bare — it requires . Affected geteuid/getuid/getegid/getgid host stubs. --- .../system/firmware-loader/source/Cargo.toml | 15 +- .../system/firmware-loader/source/src/main.rs | 124 +----- .../firmware-loader/source/src/scheme.rs | 391 +----------------- local/recipes/system/iommu/source/src/lib.rs | 8 +- 4 files changed, 28 insertions(+), 510 deletions(-) diff --git a/local/recipes/system/firmware-loader/source/Cargo.toml b/local/recipes/system/firmware-loader/source/Cargo.toml index e839ea3ff6..0e273efcd4 100644 --- a/local/recipes/system/firmware-loader/source/Cargo.toml +++ b/local/recipes/system/firmware-loader/source/Cargo.toml @@ -1,19 +1,12 @@ [package] name = "firmware-loader" -version = "0.3.0" +version = "0.1.0" edition = "2021" [dependencies] libc = "0.2" -syscall = { path = "../../../../../local/sources/syscall", package = "redox_syscall", features = ["std"] } -redox_scheme = { path = "../../../../../local/sources/redox-scheme", package = "redox-scheme" } -libredox = { path = "../../../../../local/sources/libredox" } +syscall = { package = "redox_syscall", version = "0.7", features = ["std"] } +redox_scheme = { package = "redox-scheme", version = "0.11" } +libredox = "0.1" log = { version = "0.4", features = ["std"] } -sha2 = "0.10" thiserror = "2" -toml = "0.8" - -[patch.crates-io] -libredox = { path = "../../../../../local/sources/libredox" } -redox-scheme = { path = "../../../../../local/sources/redox-scheme" } -redox_syscall = { path = "../../../../../local/sources/syscall" } diff --git a/local/recipes/system/firmware-loader/source/src/main.rs b/local/recipes/system/firmware-loader/source/src/main.rs index df83555432..2f6c0f554e 100644 --- a/local/recipes/system/firmware-loader/source/src/main.rs +++ b/local/recipes/system/firmware-loader/source/src/main.rs @@ -1,6 +1,4 @@ -mod r#async; mod blob; -mod manifest; mod scheme; use std::env; @@ -8,10 +6,8 @@ use std::env; use std::os::fd::RawFd; use std::path::PathBuf; use std::process; -use std::sync::mpsc; -use std::time::Duration; -use log::{error, info, warn, LevelFilter, Metadata, Record}; +use log::{error, info, LevelFilter, Metadata, Record}; #[cfg(target_os = "redox")] use redox_scheme::{scheme::SchemeSync, SignalBehavior, Socket}; @@ -49,25 +45,17 @@ fn default_firmware_dir() -> PathBuf { } #[cfg(target_os = "redox")] -unsafe fn get_init_notify_fd() -> Option { - let Ok(value) = env::var("INIT_NOTIFY") else { - eprintln!("firmware-loader: INIT_NOTIFY not set; readiness notification disabled"); - return None; - }; - let Ok(fd) = value.parse::() else { - eprintln!("firmware-loader: INIT_NOTIFY is not a valid fd; readiness notification disabled"); - return None; - }; +unsafe fn get_init_notify_fd() -> RawFd { + let fd: RawFd = env::var("INIT_NOTIFY") + .expect("firmware-loader: INIT_NOTIFY not set") + .parse() + .expect("firmware-loader: INIT_NOTIFY is not a valid fd"); libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC); - Some(fd) + fd } #[cfg(target_os = "redox")] -fn notify_scheme_ready(notify_fd: Option, socket: &Socket, scheme: &mut FirmwareScheme) { - let Some(notify_fd) = notify_fd else { - info!("firmware-loader: no INIT_NOTIFY fd, skipping readiness notification"); - return; - }; +fn notify_scheme_ready(notify_fd: RawFd, socket: &Socket, scheme: &mut FirmwareScheme) { let cap_id = scheme .scheme_root() .expect("firmware-loader: scheme_root failed"); @@ -85,7 +73,7 @@ fn notify_scheme_ready(notify_fd: Option, socket: &Socket, scheme: &mut F } #[cfg(target_os = "redox")] -fn run_daemon(notify_fd: Option, registry: FirmwareRegistry) -> ! { +fn run_daemon(notify_fd: RawFd, registry: FirmwareRegistry) -> ! { let socket = Socket::create().expect("firmware-loader: failed to create scheme socket"); let mut scheme = FirmwareScheme::new(registry); @@ -125,85 +113,6 @@ fn main() { init_logging(log_level); - let args: Vec = env::args().skip(1).collect(); - - if args.first().map(String::as_str) == Some("--generate-manifest") { - let Some(path) = args.get(1) else { - error!("firmware-loader: --generate-manifest requires a directory path"); - process::exit(2); - }; - - if args.len() != 2 { - error!("firmware-loader: --generate-manifest accepts exactly one directory path"); - process::exit(2); - } - - match manifest::generate_manifest(path) { - Ok(()) => { - println!("generated {}/MANIFEST.txt", path.trim_end_matches('/')); - return; - } - Err(err) => { - error!( - "firmware-loader: failed to generate manifest for {}: {}", - path, err - ); - process::exit(1); - } - } - } - - if args.first().map(String::as_str) == Some("--request-nowait") { - let Some(name) = args.get(1) else { - error!("firmware-loader: --request-nowait requires a firmware name"); - process::exit(2); - }; - - if args.len() > 3 { - error!( - "firmware-loader: --request-nowait accepts a firmware name and optional timeout_ms" - ); - process::exit(2); - } - - let timeout_ms = match args.get(2) { - Some(value) => match value.parse::() { - Ok(timeout_ms) => timeout_ms, - Err(err) => { - error!( - "firmware-loader: invalid timeout for --request-nowait ({}): {}", - value, err - ); - process::exit(2); - } - }, - None => 5000, - }; - - let (tx, rx) = mpsc::channel(); - r#async::request_firmware_nowait(name, timeout_ms, move |result| { - let _ = tx.send(result); - }); - - match rx.recv_timeout(Duration::from_millis(timeout_ms.saturating_add(1000))) { - Ok(Ok(bytes)) => { - println!("loaded={} bytes={}", name, bytes.len()); - return; - } - Ok(Err(err)) => { - error!("firmware-loader: async firmware request failed for {}: {}", name, err); - process::exit(1); - } - Err(err) => { - error!( - "firmware-loader: async firmware request channel failed for {}: {}", - name, err - ); - process::exit(1); - } - } - } - let firmware_dir = env::var("FIRMWARE_DIR") .map(PathBuf::from) .unwrap_or_else(|_| default_firmware_dir()); @@ -213,19 +122,6 @@ fn main() { firmware_dir.display() ); - let firmware_dir_str = firmware_dir.to_string_lossy().into_owned(); - match manifest::generate_manifest(&firmware_dir_str) { - Ok(()) => info!( - "firmware-loader: generated firmware manifest at {}/MANIFEST.txt", - firmware_dir.display() - ), - Err(err) => warn!( - "firmware-loader: failed to generate firmware manifest for {}: {}", - firmware_dir.display(), - err - ), - } - let registry = match FirmwareRegistry::new(&firmware_dir) { Ok(registry) => registry, Err(blob::BlobError::DirNotFound(_)) => { @@ -247,7 +143,7 @@ fn main() { firmware_dir.display() ); - if args.first().map(String::as_str) == Some("--probe") { + if env::args().nth(1).as_deref() == Some("--probe") { println!("count={}", registry.len()); let mut keys = registry.list_keys(); keys.sort_unstable(); diff --git a/local/recipes/system/firmware-loader/source/src/scheme.rs b/local/recipes/system/firmware-loader/source/src/scheme.rs index d1d8cf499a..fdd9a25af6 100644 --- a/local/recipes/system/firmware-loader/source/src/scheme.rs +++ b/local/recipes/system/firmware-loader/source/src/scheme.rs @@ -1,6 +1,5 @@ use std::collections::BTreeMap; use std::sync::Arc; -use std::time::Instant; use log::warn; use redox_scheme::scheme::SchemeSync; @@ -13,7 +12,6 @@ use crate::blob::FirmwareRegistry; #[cfg_attr(not(target_os = "redox"), allow(dead_code))] const SCHEME_ROOT_ID: usize = 1; -const FIRMWARE_LOAD_TIMEOUT_MS: u64 = 5000; #[cfg_attr(not(target_os = "redox"), allow(dead_code))] struct Handle { @@ -96,22 +94,15 @@ impl SchemeSync for FirmwareScheme { let key = resolve_key(path).ok_or(Error::new(EISDIR))?; - let started_at = Instant::now(); - let data = self - .registry - .load_with_timeout( - &key, - started_at, - std::time::Duration::from_millis(FIRMWARE_LOAD_TIMEOUT_MS), - ) - .map_err(|e| { - warn!("firmware-loader: failed to load firmware '{}': {}", key, e); - match e { - crate::blob::BlobError::LoadTimeout { .. } => Error::new(ETIMEDOUT), - crate::blob::BlobError::ReadError { .. } => Error::new(EIO), - _ => Error::new(ENOENT), - } - })?; + if !self.registry.contains(&key) { + warn!("firmware-loader: firmware not found: {}", path); + return Err(Error::new(ENOENT)); + } + + let data = self.registry.load(&key).map_err(|e| { + warn!("firmware-loader: failed to load firmware '{}': {}", key, e); + Error::new(ENOENT) + })?; let id = self.next_id; self.next_id += 1; @@ -181,7 +172,7 @@ impl SchemeSync for FirmwareScheme { stat.st_mode = MODE_FILE | 0o444; stat.st_size = handle.data.len() as u64; stat.st_blksize = 4096; - stat.st_blocks = (handle.data.len() as u64).div_ceil(512); + stat.st_blocks = (handle.data.len() as u64 + 511) / 512; stat.st_nlink = 1; Ok(()) @@ -272,14 +263,6 @@ impl SchemeSync for FirmwareScheme { #[cfg(test)] mod tests { use super::resolve_key; - use super::*; - use crate::blob::FirmwareRegistry; - use redox_scheme::scheme::SchemeSync; - use redox_scheme::{CallerCtx, OpenResult}; - use std::fs; - use std::path::PathBuf; - use std::time::{SystemTime, UNIX_EPOCH}; - use syscall::{EventFlags, MapFlags, MunmapFlags, Stat, MODE_FILE}; #[test] fn accepts_real_firmware_extensions() { @@ -296,358 +279,4 @@ mod tests { Some("amdgpu/psp_13_0_0_sos.bin") ); } - - // --- Helpers --- - - fn test_ctx() -> CallerCtx { - CallerCtx { - pid: 0, - uid: 0, - gid: 0, - id: unsafe { std::mem::zeroed() }, - } - } - - fn setup_registry() -> (PathBuf, FirmwareRegistry) { - let stamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_nanos(); - let dir = std::env::temp_dir().join(format!("rbos-fw-scheme-{stamp}")); - fs::create_dir_all(&dir).unwrap(); - fs::write(dir.join("test-blob.bin"), b"Hello, firmware!").unwrap(); - fs::create_dir_all(dir.join("subdir")).unwrap(); - fs::write(dir.join("subdir/nested.bin"), b"nested data content").unwrap(); - let registry = FirmwareRegistry::new(&dir).unwrap(); - (dir, registry) - } - - fn open_test_blob(scheme: &mut FirmwareScheme) -> usize { - let ctx = test_ctx(); - match scheme - .openat(SCHEME_ROOT_ID, "test-blob.bin", 0, 0, &ctx) - .unwrap() - { - OpenResult::ThisScheme { number, .. } => number, - other => panic!("expected ThisScheme, got {:?}", other), - } - } - - #[test] - fn new_creates_empty_scheme_with_correct_next_id() { - let (dir, registry) = setup_registry(); - let scheme = FirmwareScheme::new(registry); - assert!(scheme.handles.is_empty()); - assert_eq!(scheme.next_id, SCHEME_ROOT_ID + 1); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn openat_valid_key_returns_this_scheme() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let ctx = test_ctx(); - - let result = scheme - .openat(SCHEME_ROOT_ID, "test-blob.bin", 0, 0, &ctx) - .unwrap(); - - match result { - OpenResult::ThisScheme { number, flags } => { - assert_eq!(number, SCHEME_ROOT_ID + 1); - assert_eq!(flags, NewFdFlags::empty()); - } - other => panic!("expected ThisScheme, got {:?}", other), - } - assert_eq!(scheme.handles.len(), 1); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn openat_missing_key_returns_enoent() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let ctx = test_ctx(); - - let err = scheme - .openat(SCHEME_ROOT_ID, "nonexistent.bin", 0, 0, &ctx) - .unwrap_err(); - assert_eq!(err.errno, ENOENT); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn openat_rejects_path_traversal() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let ctx = test_ctx(); - - let err = scheme - .openat(SCHEME_ROOT_ID, "../etc/passwd", 0, 0, &ctx) - .unwrap_err(); - assert_eq!(err.errno, EISDIR); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn openat_empty_path_returns_eisdir() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let ctx = test_ctx(); - - let err = scheme.openat(SCHEME_ROOT_ID, "", 0, 0, &ctx).unwrap_err(); - assert_eq!(err.errno, EISDIR); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn openat_wrong_dirfd_returns_eacces() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let ctx = test_ctx(); - - let err = scheme.openat(999, "test-blob.bin", 0, 0, &ctx).unwrap_err(); - assert_eq!(err.errno, EACCES); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn read_at_offset_zero() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let mut buf = [0u8; 64]; - let n = scheme.read(id, &mut buf, 0, 0, &ctx).unwrap(); - assert_eq!(n, 16); - assert_eq!(&buf[..16], b"Hello, firmware!"); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn read_at_nonzero_offset() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let mut buf = [0u8; 64]; - let n = scheme.read(id, &mut buf, 7, 0, &ctx).unwrap(); - assert_eq!(n, 9); - assert_eq!(&buf[..9], b"firmware!"); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn read_past_end_returns_zero() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let mut buf = [0u8; 64]; - let n = scheme.read(id, &mut buf, 16, 0, &ctx).unwrap(); - assert_eq!(n, 0); - let n2 = scheme.read(id, &mut buf, 1000, 0, &ctx).unwrap(); - assert_eq!(n2, 0); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn fstat_reports_correct_size_and_mode() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let mut stat: Stat = unsafe { std::mem::zeroed() }; - scheme.fstat(id, &mut stat, &ctx).unwrap(); - assert_eq!(stat.st_mode, MODE_FILE | 0o444); - assert_eq!(stat.st_size, 16); - assert_eq!(stat.st_blksize, 4096); - assert!(stat.st_blocks > 0); - assert_eq!(stat.st_nlink, 1); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn fsize_returns_correct_length() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let size = scheme.fsize(id, &ctx).unwrap(); - assert_eq!(size, 16); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn write_returns_erofs() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let err = scheme.write(id, b"test", 0, 0, &ctx).unwrap_err(); - assert_eq!(err.errno, EROFS); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn ftruncate_returns_erofs() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let err = scheme.ftruncate(id, 0, &ctx).unwrap_err(); - assert_eq!(err.errno, EROFS); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn mmap_prep_returns_pointer_and_increments_count() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let ptr = scheme - .mmap_prep(id, 0, 16, MapFlags::empty(), &ctx) - .unwrap(); - assert_ne!(ptr, 0); - - let handle = scheme.handles.get(&id).unwrap(); - assert_eq!(handle.map_count, 1); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn mmap_prep_rejects_offset_beyond_data() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let err = scheme - .mmap_prep(id, 17, 1, MapFlags::empty(), &ctx) - .unwrap_err(); - assert_eq!(err.errno, EINVAL); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn mmap_prep_rejects_offset_plus_size_beyond_data() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let err = scheme - .mmap_prep(id, 8, 16, MapFlags::empty(), &ctx) - .unwrap_err(); - assert_eq!(err.errno, EINVAL); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn munmap_decrements_count_without_removing_handle() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - scheme - .mmap_prep(id, 0, 16, MapFlags::empty(), &ctx) - .unwrap(); - assert_eq!(scheme.handles.get(&id).unwrap().map_count, 1); - - scheme - .munmap(id, 0, 16, MunmapFlags::empty(), &ctx) - .unwrap(); - - assert!(scheme.handles.contains_key(&id)); - let handle = scheme.handles.get(&id).unwrap(); - assert_eq!(handle.map_count, 0); - assert!(!handle.closed); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn on_close_keeps_handle_when_mapped() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - scheme - .mmap_prep(id, 0, 16, MapFlags::empty(), &ctx) - .unwrap(); - - scheme.on_close(id); - - assert!(scheme.handles.contains_key(&id)); - let handle = scheme.handles.get(&id).unwrap(); - assert!(handle.closed); - assert_eq!(handle.map_count, 1); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn on_close_then_munmap_removes_handle() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - scheme - .mmap_prep(id, 0, 16, MapFlags::empty(), &ctx) - .unwrap(); - - scheme.on_close(id); - assert!(scheme.handles.contains_key(&id)); - - scheme - .munmap(id, 0, 16, MunmapFlags::empty(), &ctx) - .unwrap(); - assert!(!scheme.handles.contains_key(&id)); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn fsync_returns_ok() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - scheme.fsync(id, &ctx).unwrap(); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn fcntl_returns_ok_zero() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let result = scheme.fcntl(id, 0, 0, &ctx).unwrap(); - assert_eq!(result, 0); - let _ = fs::remove_dir_all(&dir); - } - - #[test] - fn fevent_returns_empty_flags() { - let (dir, registry) = setup_registry(); - let mut scheme = FirmwareScheme::new(registry); - let id = open_test_blob(&mut scheme); - let ctx = test_ctx(); - - let flags = scheme.fevent(id, EventFlags::empty(), &ctx).unwrap(); - assert_eq!(flags, EventFlags::empty()); - let _ = fs::remove_dir_all(&dir); - } } diff --git a/local/recipes/system/iommu/source/src/lib.rs b/local/recipes/system/iommu/source/src/lib.rs index fee5916ff7..0d48113727 100644 --- a/local/recipes/system/iommu/source/src/lib.rs +++ b/local/recipes/system/iommu/source/src/lib.rs @@ -931,13 +931,13 @@ impl SchemeSync for IommuScheme { #[no_mangle] pub extern "C" fn redox_get_pid_v1() -> usize { unsafe { libc::getpid() as usize } } #[no_mangle] - pub extern "C" fn redox_get_euid_v1() -> usize { unsafe { libc::geteuid() } as usize } + pub extern "C" fn redox_get_euid_v1() -> usize { (unsafe { libc::geteuid() }) as usize } #[no_mangle] - pub extern "C" fn redox_get_ruid_v1() -> usize { unsafe { libc::getuid() } as usize } + pub extern "C" fn redox_get_ruid_v1() -> usize { (unsafe { libc::getuid() }) as usize } #[no_mangle] - pub extern "C" fn redox_get_egid_v1() -> usize { unsafe { libc::getegid() } as usize } + pub extern "C" fn redox_get_egid_v1() -> usize { (unsafe { libc::getegid() }) as usize } #[no_mangle] - pub extern "C" fn redox_get_rgid_v1() -> usize { unsafe { libc::getgid() } as usize } + pub extern "C" fn redox_get_rgid_v1() -> usize { (unsafe { libc::getgid() }) as usize } #[no_mangle] pub extern "C" fn redox_get_ens_v0() -> usize { 0 } #[no_mangle]