mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2025-12-23 22:47:55 -05:00
implement sys_chroot
This commit is contained in:
@@ -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 |
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(¤t_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(¤t_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()
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 _)
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
@@ -119,6 +125,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,
|
||||
|
||||
@@ -270,8 +270,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?;
|
||||
|
||||
|
||||
@@ -123,6 +123,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>,
|
||||
@@ -155,6 +156,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)),
|
||||
@@ -175,6 +177,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"),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user