Merge pull request #72 from some100/master

This commit is contained in:
Matthew Leach
2025-12-21 13:30:05 +00:00
committed by GitHub
14 changed files with 137 additions and 21 deletions

View File

@@ -51,7 +51,7 @@
| 0x30 (48) | faccessat | (int dfd, const char *filename, int mode) | __arm64_sys_faccessat | true |
| 0x31 (49) | chdir | (const char *filename) | __arm64_sys_chdir | true |
| 0x32 (50) | fchdir | (unsigned int fd) | __arm64_sys_fchdir | false |
| 0x33 (51) | chroot | (const char *filename) | __arm64_sys_chroot | false |
| 0x33 (51) | chroot | (const char *filename) | __arm64_sys_chroot | true |
| 0x34 (52) | fchmod | (unsigned int fd, umode_t mode) | __arm64_sys_fchmod | false |
| 0x35 (53) | fchmodat | (int dfd, const char *filename, umode_t mode) | __arm64_sys_fchmodat | false |
| 0x36 (54) | fchownat | (int dfd, const char *filename, uid_t user, gid_t group, int flag) | __arm64_sys_fchownat | false |

View File

@@ -1,3 +1,4 @@
use crate::fs::syscalls::chdir::sys_chroot;
use crate::fs::syscalls::trunc::sys_ftruncate;
use crate::kernel::power::sys_reboot;
use crate::kernel::rand::sys_getrandom;
@@ -100,6 +101,7 @@ pub async fn handle_syscall() {
0x2e => sys_ftruncate(arg1.into(), arg2 as _).await,
0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await,
0x31 => sys_chdir(TUA::from_value(arg1 as _)).await,
0x33 => sys_chroot(TUA::from_value(arg1 as _)).await,
0x38 => {
sys_openat(
arg1.into(),

View File

@@ -11,6 +11,7 @@ use open_file::OpenFile;
use reg::RegFile;
use crate::drivers::{DM, Driver};
use crate::process::Task;
use crate::sync::SpinLock;
use alloc::vec::Vec;
@@ -169,7 +170,52 @@ impl VFS {
/// Resolves a path string to an Inode, starting from a given root for
/// relative paths.
pub async fn resolve_path(&self, path: &Path, root: Arc<dyn Inode>) -> Result<Arc<dyn Inode>> {
pub async fn resolve_path(
&self,
path: &Path,
root: Arc<dyn Inode>,
task: Arc<Task>,
) -> Result<Arc<dyn Inode>> {
let mut current_inode = if path.is_absolute() {
task.root.lock_save_irq().0.clone() // use the task's root inode, in case a custom chroot was set
} else {
root
};
for component in path.components() {
// Before looking up the component, check if the current inode is a
// mount point. If so, traverse into the mounted filesystem's root.
if let Some(mount_root) = self
.state
.lock_save_irq()
.get_mount_root(&current_inode.id())
{
current_inode = mount_root;
}
// Delegate the lookup to the underlying filesystem.
current_inode = current_inode.lookup(component).await?;
}
// After the final lookup, check if the destination is itself a mount point.
if let Some(mount_root) = self
.state
.lock_save_irq()
.get_mount_root(&current_inode.id())
{
current_inode = mount_root;
}
Ok(current_inode)
}
/// Resolves a path string to an Inode, starting from a given root for
/// relative paths, and using the filesystem root inode for absolute paths.
pub async fn resolve_path_absolute(
&self,
path: &Path,
root: Arc<dyn Inode>,
) -> Result<Arc<dyn Inode>> {
let mut current_inode = if path.is_absolute() {
self.root_inode
.lock_save_irq()
@@ -218,9 +264,10 @@ impl VFS {
flags: OpenFlags,
root: Arc<dyn Inode>,
mode: FilePermissions,
task: Arc<Task>,
) -> Result<Arc<OpenFile>> {
// Attempt to resolve the full path first.
let resolve_result = self.resolve_path(path, root.clone()).await;
let resolve_result = self.resolve_path(path, root.clone(), task.clone()).await;
let target_inode = match resolve_result {
// The file/directory exists.
@@ -243,7 +290,7 @@ impl VFS {
// (cwd or dirfd) as the parent directory.
let file_name = path.file_name().ok_or(FsError::InvalidInput)?;
let parent_inode = if let Some(parent_path) = path.parent() {
self.resolve_path(parent_path, root.clone()).await?
self.resolve_path(parent_path, root.clone(), task).await?
} else {
root.clone()
};
@@ -324,9 +371,10 @@ impl VFS {
path: &Path,
root: Arc<dyn Inode>,
mode: FilePermissions,
task: Arc<Task>,
) -> Result<()> {
// Try to resolve the target directory first.
match self.resolve_path(path, root.clone()).await {
match self.resolve_path(path, root.clone(), task.clone()).await {
// The path already exists, this is an error.
Ok(_) => Err(FsError::AlreadyExists.into()),
@@ -339,7 +387,7 @@ impl VFS {
// component (e.g., \"foo\"), treat the provided `root`
// directory (AT_FDCWD / cwd / dirfd) as the parent.
let parent_inode = if let Some(parent_path) = path.parent() {
self.resolve_path(parent_path, root.clone()).await?
self.resolve_path(parent_path, root.clone(), task).await?
} else {
root.clone()
};
@@ -362,9 +410,15 @@ impl VFS {
}
}
pub async fn unlink(&self, path: &Path, root: Arc<dyn Inode>, remove_dir: bool) -> Result<()> {
pub async fn unlink(
&self,
path: &Path,
root: Arc<dyn Inode>,
remove_dir: bool,
task: Arc<Task>,
) -> Result<()> {
// First, resolve the target inode so we can inspect its type.
let target_inode = self.resolve_path(path, root.clone()).await?;
let target_inode = self.resolve_path(path, root.clone(), task.clone()).await?;
let attr = target_inode.getattr().await?;
@@ -382,7 +436,7 @@ impl VFS {
// Determine the parent directory inode in which to perform the unlink.
let parent_inode = if let Some(parent_path) = path.parent() {
self.resolve_path(parent_path, root.clone()).await?
self.resolve_path(parent_path, root.clone(), task).await?
} else {
root.clone()
};

View File

@@ -14,10 +14,11 @@ pub async fn sys_faccessat(dirfd: Fd, path: TUA<c_char>, mode: i32) -> Result<us
pub async fn sys_faccessat2(dirfd: Fd, path: TUA<c_char>, mode: i32, flags: i32) -> Result<usize> {
let mut buf = [0; 1024];
let task = current_task();
let access_mode = AccessMode::from_bits_retain(mode);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let start_node = resolve_at_start_node(dirfd, path).await?;
let node = VFS.resolve_path(path, start_node).await?;
let node = VFS.resolve_path(path, start_node, task.clone()).await?;
let at_flags = AtFlags::from_bits_retain(flags);
// If mode is F_OK (value 0), the check is for the file's existence.
@@ -26,7 +27,6 @@ pub async fn sys_faccessat2(dirfd: Fd, path: TUA<c_char>, mode: i32, flags: i32)
return Ok(0);
}
let task = current_task();
let attrs = node.getattr().await?;
let creds = task.creds.lock_save_irq();

View File

@@ -1,3 +1,4 @@
use crate::current_task;
use crate::fs::VFS;
use crate::fs::syscalls::at::resolve_at_start_node;
use crate::memory::uaccess::cstr::UserCStr;
@@ -14,10 +15,11 @@ pub async fn sys_mkdirat(
) -> libkernel::error::Result<usize> {
let mut buf = [0; 1024];
let task = current_task();
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let start_node = resolve_at_start_node(dirfd, path).await?;
let mode = FilePermissions::from_bits_retain(mode);
VFS.mkdir(path, start_node, mode).await?;
VFS.mkdir(path, start_node, mode, task.clone()).await?;
Ok(0)
}

View File

@@ -11,14 +11,17 @@ use super::resolve_at_start_node;
pub async fn sys_openat(dirfd: Fd, path: TUA<c_char>, flags: u32, mode: u16) -> Result<usize> {
let mut buf = [0; 1024];
let task = current_task();
let flags = OpenFlags::from_bits_truncate(flags);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let start_node = resolve_at_start_node(dirfd, path).await?;
let mode = FilePermissions::from_bits_retain(mode);
let file = VFS.open(path, flags, start_node, mode).await?;
let file = VFS
.open(path, flags, start_node, mode, task.clone())
.await?;
let fd = current_task().fd_table.lock_save_irq().insert(file)?;
let fd = task.fd_table.lock_save_irq().insert(file)?;
Ok(fd.as_raw() as _)
}

View File

@@ -1,4 +1,5 @@
use crate::{
current_task,
fs::{VFS, syscalls::at::resolve_at_start_node},
memory::uaccess::{UserCopyable, copy_to_user, cstr::UserCStr},
process::fd_table::Fd,
@@ -84,11 +85,12 @@ pub async fn sys_newfstatat(
) -> Result<usize> {
let mut buf = [0; 1024];
let task = current_task();
let _flags = AtFlags::from_bits_truncate(flags);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let start_node = resolve_at_start_node(dirfd, path).await?;
let node = VFS.resolve_path(path, start_node).await?;
let node = VFS.resolve_path(path, start_node, task.clone()).await?;
let attr = node.getattr().await?;

View File

@@ -3,6 +3,7 @@ use core::ffi::c_char;
use libkernel::{error::Result, fs::path::Path, memory::address::TUA};
use crate::{
current_task,
fs::{VFS, syscalls::at::resolve_at_start_node},
memory::uaccess::cstr::UserCStr,
process::fd_table::Fd,
@@ -21,12 +22,15 @@ pub async fn sys_unlinkat(dirfd: Fd, path: TUA<c_char>, flags: u32) -> Result<us
let mut buf = [0u8; 1024];
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let task = current_task();
// Determine the starting inode for path resolution.
let start_node = resolve_at_start_node(dirfd, path).await?;
let remove_dir = flags & AT_REMOVEDIR != 0;
VFS.unlink(path, start_node, remove_dir).await?;
VFS.unlink(path, start_node, remove_dir, task.clone())
.await?;
Ok(0)
}

View File

@@ -34,9 +34,24 @@ pub async fn sys_chdir(path: TUA<c_char>) -> Result<usize> {
let current_path = task.cwd.lock_save_irq().0.clone();
let new_path = task.cwd.lock_save_irq().1.join(path);
let node = VFS.resolve_path(path, current_path).await?;
let node = VFS.resolve_path(path, current_path, task.clone()).await?;
*task.cwd.lock_save_irq() = (node, new_path);
Ok(0)
}
pub async fn sys_chroot(path: TUA<c_char>) -> Result<usize> {
let mut buf = [0; 1024];
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let task = current_task();
let current_path = task.root.lock_save_irq().0.clone();
let new_path = task.root.lock_save_irq().1.join(path);
let node = VFS.resolve_path(path, current_path, task.clone()).await?;
*task.root.lock_save_irq() = (node, new_path);
Ok(0)
}

View File

@@ -107,7 +107,7 @@ async fn launch_init(opts: KOptions) {
// Process all automounts.
for (path, fs) in opts.automounts.iter() {
let mount_point = VFS
.resolve_path(path, VFS.root_inode())
.resolve_path_absolute(path, VFS.root_inode())
.await
.unwrap_or_else(|e| panic!("Could not find automount path: {}. {e}", path.as_str()));
@@ -117,7 +117,7 @@ async fn launch_init(opts: KOptions) {
}
let inode = VFS
.resolve_path(&init, VFS.root_inode())
.resolve_path_absolute(&init, VFS.root_inode())
.await
.expect("Unable to find init");
@@ -127,8 +127,9 @@ async fn launch_init(opts: KOptions) {
assert!(task.process.tgid.is_init());
// Now that the root fs has been mounted, set the real root inode as the
// cwd.
// cwd and root.
*task.cwd.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
*task.root.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
let console = VFS
.open(
@@ -136,6 +137,7 @@ async fn launch_init(opts: KOptions) {
OpenFlags::O_RDWR,
VFS.root_inode(),
FilePermissions::empty(),
task.clone(),
)
.await
.expect("Could not open console for init process");

View File

@@ -105,6 +105,12 @@ pub async fn sys_clone(
Arc::new(SpinLock::new(current_task.cwd.lock_save_irq().clone()))
};
let root = if flags.contains(CloneFlags::CLONE_FS) {
current_task.root.clone()
} else {
Arc::new(SpinLock::new(current_task.root.lock_save_irq().clone()))
};
let creds = current_task.creds.lock_save_irq().clone();
let mut user_ctx = *current_task.ctx.lock_save_irq().user();
@@ -120,6 +126,7 @@ pub async fn sys_clone(
vm,
fd_table: files,
cwd,
root,
creds: SpinLock::new(creds),
ctx: SpinLock::new(Context::from_user_ctx(user_ctx)),
priority: current_task.priority,

View File

@@ -276,8 +276,11 @@ pub async fn sys_execve(
usr_env = usr_env.add_objs(1);
}
let task = current_task();
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?);
let inode = VFS.resolve_path(path, VFS.root_inode()).await?;
let inode = VFS
.resolve_path(path, VFS.root_inode(), task.clone())
.await?;
kernel_exec(inode, argv, envp).await?;

View File

@@ -168,6 +168,7 @@ pub struct Task {
pub process: Arc<ThreadGroup>,
pub vm: Arc<SpinLock<ProcVM>>,
pub cwd: Arc<SpinLock<(Arc<dyn Inode>, PathBuf)>>,
pub root: Arc<SpinLock<(Arc<dyn Inode>, PathBuf)>>,
pub creds: SpinLock<Credentials>,
pub fd_table: Arc<SpinLock<FileDescriptorTable>>,
pub ctx: SpinLock<Context>,
@@ -201,6 +202,7 @@ impl Task {
state: Arc::new(SpinLock::new(TaskState::Runnable)),
priority: i8::MIN,
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
root: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
creds: SpinLock::new(Credentials::new_root()),
ctx: SpinLock::new(Context::from_user_ctx(user_ctx)),
vm: Arc::new(SpinLock::new(vm)),
@@ -222,6 +224,7 @@ impl Task {
process: ThreadGroupBuilder::new(Tgid::init()).build(),
state: Arc::new(SpinLock::new(TaskState::Runnable)),
cwd: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
root: Arc::new(SpinLock::new((Arc::new(DummyInode {}), PathBuf::new()))),
creds: SpinLock::new(Credentials::new_root()),
vm: Arc::new(SpinLock::new(
ProcessVM::empty().expect("Could not create init process's VM"),

View File

@@ -54,6 +54,24 @@ fn test_chdir() {
println!(" OK");
}
fn test_chroot() {
print!("Testing chroot syscall ...");
let file = "/bin/busybox";
let c_file = std::ffi::CString::new(file).unwrap();
let path = std::ffi::CString::new("/dev").unwrap();
unsafe {
if libc::chroot(path.as_ptr()) != 0 {
panic!("chroot failed");
} else {
let fd = libc::open(c_file.as_ptr(), libc::O_RDONLY);
if fd != -1 {
panic!("chroot failed");
}
}
}
println!(" OK");
}
fn test_fork() {
print!("Testing fork syscall ...");
unsafe {
@@ -173,6 +191,7 @@ fn main() {
run_test(test_opendir);
run_test(test_readdir);
run_test(test_chdir);
run_test(test_chroot);
run_test(test_fork);
run_test(test_read);
run_test(test_write);