From b2de3d6e2ea8b64ee3fe93f93b49a8fa0bd79c2a Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sun, 29 Mar 2026 13:11:36 +0700 Subject: [PATCH] Implement exec cache from ld_so cache --- src/fs.rs | 7 ++++++ src/platform/redox/exec.rs | 49 +++++++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index f42916b034..5d27252b65 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -9,6 +9,7 @@ use crate::{ platform::{Pal, Sys, types::*}, }; use core::ops::Deref; +use syscall::Stat; pub struct File { pub fd: c_int, @@ -57,6 +58,12 @@ impl File { Sys::ftruncate(self.fd, size as off_t).map_err(Errno::sync) } + pub fn fstat(&self) -> Result { + let mut stat = Stat::default(); + redox_rt::sys::fstat(self.fd as usize, &mut stat)?; + Ok(stat) + } + pub fn try_clone(&self) -> io::Result { Ok(Self::new(Sys::dup(self.fd)?)) } diff --git a/src/platform/redox/exec.rs b/src/platform/redox/exec.rs index da0a0d9087..ef6ad0b6d4 100644 --- a/src/platform/redox/exec.rs +++ b/src/platform/redox/exec.rs @@ -74,12 +74,47 @@ pub fn execve( ) -> Result { // NOTE: We must omit O_CLOEXEC and close manually, otherwise it will be closed before we // have even read it! - let (mut image_file, arg0) = match exec { - Executable::AtPath(path) => ( - File::open(path, O_RDONLY as c_int).map_err(|_| Error::new(ENOENT))?, - path.to_bytes(), - ), - Executable::InFd { file, arg0 } => (file, arg0), + let (mut image_file, stat, arg0) = match exec { + Executable::AtPath(path) => { + let Ok(src_fd) = File::open(path, O_RDONLY as c_int) else { + return Err(Error::new(ENOENT)); + }; + + let Ok(src_stat) = src_fd.fstat() else { + return Err(Error::new(ENOENT)); + }; + + #[cfg(feature = "ld_so_cache")] + let src_fd = { + let mtime_sec = src_stat.st_mtime; + let mtime_nsec = src_stat.st_mtime_nsec; + + let safe_path = path.to_str().unwrap_or("").replace('/', "_"); + let shm_path_owned = format!( + "/scheme/shm/ld.so.cache.{}.{}.{}\0", + safe_path, mtime_sec, mtime_nsec + ); + let shm_path = + unsafe { CStr::from_bytes_with_nul_unchecked(shm_path_owned.as_bytes()) }; + + let mut file_opt = None; + if let Ok(shm_fd) = File::open(shm_path, O_RDONLY as c_int) { + if let Ok(shm_stat) = shm_fd.fstat() + && shm_stat.st_size > 0 + { + file_opt = Some(shm_fd); + } + } + file_opt.unwrap_or(src_fd) + }; + + (src_fd, src_stat, path.to_bytes()) + } + Executable::InFd { file, arg0 } => { + let mut stat = Stat::default(); + redox_rt::sys::fstat(*file as usize, &mut stat)?; + (file, stat, arg0) + } }; // With execve now being implemented in userspace, we need to check ourselves that this @@ -93,8 +128,6 @@ pub fn execve( // TODO: At some point we might have capabilities limiting the ability to allocate // executable memory. - let mut stat = Stat::default(); - redox_rt::sys::fstat(*image_file as usize, &mut stat)?; let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid(); let mode = if ruid == stat.st_uid {