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 | | 0x30 (48) | faccessat | (int dfd, const char *filename, int mode) | __arm64_sys_faccessat | true |
| 0x31 (49) | chdir | (const char *filename) | __arm64_sys_chdir | true | | 0x31 (49) | chdir | (const char *filename) | __arm64_sys_chdir | true |
| 0x32 (50) | fchdir | (unsigned int fd) | __arm64_sys_fchdir | false | | 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 | | 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 | | 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 | | 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::fs::syscalls::trunc::sys_ftruncate;
use crate::kernel::power::sys_reboot; use crate::kernel::power::sys_reboot;
use crate::kernel::rand::sys_getrandom; use crate::kernel::rand::sys_getrandom;
@@ -100,6 +101,7 @@ pub async fn handle_syscall() {
0x2e => sys_ftruncate(arg1.into(), arg2 as _).await, 0x2e => sys_ftruncate(arg1.into(), arg2 as _).await,
0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await, 0x30 => sys_faccessat(arg1.into(), TUA::from_value(arg2 as _), arg3 as _).await,
0x31 => sys_chdir(TUA::from_value(arg1 as _)).await, 0x31 => sys_chdir(TUA::from_value(arg1 as _)).await,
0x33 => sys_chroot(TUA::from_value(arg1 as _)).await,
0x38 => { 0x38 => {
sys_openat( sys_openat(
arg1.into(), arg1.into(),

View File

@@ -11,6 +11,7 @@ use open_file::OpenFile;
use reg::RegFile; use reg::RegFile;
use crate::drivers::{DM, Driver}; use crate::drivers::{DM, Driver};
use crate::process::Task;
use crate::sync::SpinLock; use crate::sync::SpinLock;
use alloc::vec::Vec; use alloc::vec::Vec;
@@ -169,7 +170,52 @@ impl VFS {
/// Resolves a path string to an Inode, starting from a given root for /// Resolves a path string to an Inode, starting from a given root for
/// relative paths. /// 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() { let mut current_inode = if path.is_absolute() {
self.root_inode self.root_inode
.lock_save_irq() .lock_save_irq()
@@ -218,9 +264,10 @@ impl VFS {
flags: OpenFlags, flags: OpenFlags,
root: Arc<dyn Inode>, root: Arc<dyn Inode>,
mode: FilePermissions, mode: FilePermissions,
task: Arc<Task>,
) -> Result<Arc<OpenFile>> { ) -> Result<Arc<OpenFile>> {
// Attempt to resolve the full path first. // 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 { let target_inode = match resolve_result {
// The file/directory exists. // The file/directory exists.
@@ -243,7 +290,7 @@ impl VFS {
// (cwd or dirfd) as the parent directory. // (cwd or dirfd) as the parent directory.
let file_name = path.file_name().ok_or(FsError::InvalidInput)?; let file_name = path.file_name().ok_or(FsError::InvalidInput)?;
let parent_inode = if let Some(parent_path) = path.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 { } else {
root.clone() root.clone()
}; };
@@ -324,9 +371,10 @@ impl VFS {
path: &Path, path: &Path,
root: Arc<dyn Inode>, root: Arc<dyn Inode>,
mode: FilePermissions, mode: FilePermissions,
task: Arc<Task>,
) -> Result<()> { ) -> Result<()> {
// Try to resolve the target directory first. // 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. // The path already exists, this is an error.
Ok(_) => Err(FsError::AlreadyExists.into()), Ok(_) => Err(FsError::AlreadyExists.into()),
@@ -339,7 +387,7 @@ impl VFS {
// component (e.g., \"foo\"), treat the provided `root` // component (e.g., \"foo\"), treat the provided `root`
// directory (AT_FDCWD / cwd / dirfd) as the parent. // directory (AT_FDCWD / cwd / dirfd) as the parent.
let parent_inode = if let Some(parent_path) = path.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 { } else {
root.clone() 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. // 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?; let attr = target_inode.getattr().await?;
@@ -382,7 +436,7 @@ impl VFS {
// Determine the parent directory inode in which to perform the unlink. // Determine the parent directory inode in which to perform the unlink.
let parent_inode = if let Some(parent_path) = path.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 { } else {
root.clone() 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> { pub async fn sys_faccessat2(dirfd: Fd, path: TUA<c_char>, mode: i32, flags: i32) -> Result<usize> {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let task = current_task();
let access_mode = AccessMode::from_bits_retain(mode); let access_mode = AccessMode::from_bits_retain(mode);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); 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 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); let at_flags = AtFlags::from_bits_retain(flags);
// If mode is F_OK (value 0), the check is for the file's existence. // 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); return Ok(0);
} }
let task = current_task();
let attrs = node.getattr().await?; let attrs = node.getattr().await?;
let creds = task.creds.lock_save_irq(); let creds = task.creds.lock_save_irq();

View File

@@ -1,3 +1,4 @@
use crate::current_task;
use crate::fs::VFS; use crate::fs::VFS;
use crate::fs::syscalls::at::resolve_at_start_node; use crate::fs::syscalls::at::resolve_at_start_node;
use crate::memory::uaccess::cstr::UserCStr; use crate::memory::uaccess::cstr::UserCStr;
@@ -14,10 +15,11 @@ pub async fn sys_mkdirat(
) -> libkernel::error::Result<usize> { ) -> libkernel::error::Result<usize> {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let task = current_task();
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); 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 start_node = resolve_at_start_node(dirfd, path).await?;
let mode = FilePermissions::from_bits_retain(mode); 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) 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> { pub async fn sys_openat(dirfd: Fd, path: TUA<c_char>, flags: u32, mode: u16) -> Result<usize> {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let task = current_task();
let flags = OpenFlags::from_bits_truncate(flags); let flags = OpenFlags::from_bits_truncate(flags);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); 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 start_node = resolve_at_start_node(dirfd, path).await?;
let mode = FilePermissions::from_bits_retain(mode); 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 _) Ok(fd.as_raw() as _)
} }

View File

@@ -1,4 +1,5 @@
use crate::{ use crate::{
current_task,
fs::{VFS, syscalls::at::resolve_at_start_node}, fs::{VFS, syscalls::at::resolve_at_start_node},
memory::uaccess::{UserCopyable, copy_to_user, cstr::UserCStr}, memory::uaccess::{UserCopyable, copy_to_user, cstr::UserCStr},
process::fd_table::Fd, process::fd_table::Fd,
@@ -84,11 +85,12 @@ pub async fn sys_newfstatat(
) -> Result<usize> { ) -> Result<usize> {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
let task = current_task();
let _flags = AtFlags::from_bits_truncate(flags); let _flags = AtFlags::from_bits_truncate(flags);
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); 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 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?; 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 libkernel::{error::Result, fs::path::Path, memory::address::TUA};
use crate::{ use crate::{
current_task,
fs::{VFS, syscalls::at::resolve_at_start_node}, fs::{VFS, syscalls::at::resolve_at_start_node},
memory::uaccess::cstr::UserCStr, memory::uaccess::cstr::UserCStr,
process::fd_table::Fd, 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 mut buf = [0u8; 1024];
let path = Path::new(UserCStr::from_ptr(path).copy_from_user(&mut buf).await?); 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. // Determine the starting inode for path resolution.
let start_node = resolve_at_start_node(dirfd, path).await?; let start_node = resolve_at_start_node(dirfd, path).await?;
let remove_dir = flags & AT_REMOVEDIR != 0; 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) 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 current_path = task.cwd.lock_save_irq().0.clone();
let new_path = task.cwd.lock_save_irq().1.join(path); 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); *task.cwd.lock_save_irq() = (node, new_path);
Ok(0) 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. // Process all automounts.
for (path, fs) in opts.automounts.iter() { for (path, fs) in opts.automounts.iter() {
let mount_point = VFS let mount_point = VFS
.resolve_path(path, VFS.root_inode()) .resolve_path_absolute(path, VFS.root_inode())
.await .await
.unwrap_or_else(|e| panic!("Could not find automount path: {}. {e}", path.as_str())); .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 let inode = VFS
.resolve_path(&init, VFS.root_inode()) .resolve_path_absolute(&init, VFS.root_inode())
.await .await
.expect("Unable to find init"); .expect("Unable to find init");
@@ -127,8 +127,9 @@ async fn launch_init(opts: KOptions) {
assert!(task.process.tgid.is_init()); assert!(task.process.tgid.is_init());
// Now that the root fs has been mounted, set the real root inode as the // 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.cwd.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
*task.root.lock_save_irq() = (VFS.root_inode(), PathBuf::new());
let console = VFS let console = VFS
.open( .open(
@@ -136,6 +137,7 @@ async fn launch_init(opts: KOptions) {
OpenFlags::O_RDWR, OpenFlags::O_RDWR,
VFS.root_inode(), VFS.root_inode(),
FilePermissions::empty(), FilePermissions::empty(),
task.clone(),
) )
.await .await
.expect("Could not open console for init process"); .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())) 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 creds = current_task.creds.lock_save_irq().clone();
let mut user_ctx = *current_task.ctx.lock_save_irq().user(); let mut user_ctx = *current_task.ctx.lock_save_irq().user();
@@ -120,6 +126,7 @@ pub async fn sys_clone(
vm, vm,
fd_table: files, fd_table: files,
cwd, cwd,
root,
creds: SpinLock::new(creds), creds: SpinLock::new(creds),
ctx: SpinLock::new(Context::from_user_ctx(user_ctx)), ctx: SpinLock::new(Context::from_user_ctx(user_ctx)),
priority: current_task.priority, priority: current_task.priority,

View File

@@ -276,8 +276,11 @@ pub async fn sys_execve(
usr_env = usr_env.add_objs(1); 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 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?; kernel_exec(inode, argv, envp).await?;

View File

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

View File

@@ -54,6 +54,24 @@ fn test_chdir() {
println!(" OK"); 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() { fn test_fork() {
print!("Testing fork syscall ..."); print!("Testing fork syscall ...");
unsafe { unsafe {
@@ -173,6 +191,7 @@ fn main() {
run_test(test_opendir); run_test(test_opendir);
run_test(test_readdir); run_test(test_readdir);
run_test(test_chdir); run_test(test_chdir);
run_test(test_chroot);
run_test(test_fork); run_test(test_fork);
run_test(test_read); run_test(test_read);
run_test(test_write); run_test(test_write);