From d33f90eaebecfc0de8ccf18ac82c606e03cc1882 Mon Sep 17 00:00:00 2001 From: Fabing Li Date: Thu, 27 Jun 2024 11:12:22 +0800 Subject: [PATCH] Add sys_access and sys_faccessat --- docs/src/kernel/linux-compatibility.md | 2 +- kernel/aster-nix/src/syscall/access.rs | 97 +++++++++++++++++-- kernel/aster-nix/src/syscall/arch/x86.rs | 3 +- regression/syscall_test/Makefile | 1 + .../syscall_test/blocklists.exfat/access_test | 1 + .../syscall_test/blocklists/access_test | 3 + 6 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 regression/syscall_test/blocklists.exfat/access_test create mode 100644 regression/syscall_test/blocklists/access_test diff --git a/docs/src/kernel/linux-compatibility.md b/docs/src/kernel/linux-compatibility.md index be1afba8..6f6feb07 100644 --- a/docs/src/kernel/linux-compatibility.md +++ b/docs/src/kernel/linux-compatibility.md @@ -289,7 +289,7 @@ provided by Linux on x86-64 architecture. | 266 | symlinkat | ✅ | | 267 | readlinkat | ✅ | | 268 | fchmodat | ✅ | -| 269 | faccessat | ❌ | +| 269 | faccessat | ✅ | | 270 | pselect6 | ❌ | | 271 | ppoll | ❌ | | 272 | unshare | ❌ | diff --git a/kernel/aster-nix/src/syscall/access.rs b/kernel/aster-nix/src/syscall/access.rs index 713971d6..16c8b713 100644 --- a/kernel/aster-nix/src/syscall/access.rs +++ b/kernel/aster-nix/src/syscall/access.rs @@ -1,11 +1,96 @@ // SPDX-License-Identifier: MPL-2.0 -use super::{constants::*, SyscallReturn}; -use crate::{prelude::*, util::read_cstring_from_user}; +use super::SyscallReturn; +use crate::{ + fs::{ + file_table::FileDesc, + fs_resolver::{FsPath, AT_FDCWD}, + utils::PATH_MAX, + }, + prelude::*, + util::read_cstring_from_user, +}; + +pub fn sys_faccessat(dirfd: FileDesc, path_ptr: Vaddr, mode: u16) -> Result { + debug!( + "faccessat: dirfd = {}, path_ptr = {:#x}, mode = {:o}", + dirfd, path_ptr, mode + ); + + do_faccessat(dirfd, path_ptr, mode, 0) +} + +pub fn sys_access(path_ptr: Vaddr, mode: u16) -> Result { + debug!("access: path_ptr = {:#x}, mode = {:o}", path_ptr, mode); + + do_faccessat(AT_FDCWD, path_ptr, mode, 0) +} + +bitflags! { + struct FaccessatFlags: i32 { + const AT_EACCESS = 0x200; + const AT_SYMLINK_NOFOLLOW = 0x100; + const AT_EMPTY_PATH = 0x1000; + } +} + +bitflags! { + struct AccessMode: u16 { + const R_OK = 0x4; + const W_OK = 0x2; + const X_OK = 0x1; + // We could ignore F_OK in bitflags. + // const F_OK = 0x0; + } +} + +pub fn do_faccessat( + dirfd: FileDesc, + path_ptr: Vaddr, + mode: u16, + flags: i32, +) -> Result { + let mode = AccessMode::from_bits(mode) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "Invalid mode"))?; + let flags = FaccessatFlags::from_bits(flags) + .ok_or_else(|| Error::with_message(Errno::EINVAL, "Invalid flags"))?; + + let path = read_cstring_from_user(path_ptr, PATH_MAX)?; + debug!( + "dirfd = {}, path = {:?}, mode = {:o}, flags = {:?}", + dirfd, path, mode, flags + ); + + let current = current!(); + let dentry = { + let path = path.to_string_lossy(); + let fs_path = FsPath::new(dirfd, path.as_ref())?; + let fs = current.fs().read(); + if flags.contains(FaccessatFlags::AT_SYMLINK_NOFOLLOW) { + fs.lookup_no_follow(&fs_path)? + } else { + fs.lookup(&fs_path)? + } + }; + // AccessMode::empty() means F_OK and no more permission check needed. + if mode.is_empty() { + return Ok(SyscallReturn::Return(0)); + } + + let inode_mode = dentry.mode()?; + + // FIXME: The current implementation is dummy + if mode.contains(AccessMode::R_OK) && !inode_mode.is_readable() { + return_errno_with_message!(Errno::EACCES, "Read permission denied"); + } + + if mode.contains(AccessMode::W_OK) && !inode_mode.is_writable() { + return_errno_with_message!(Errno::EACCES, "Write permission denied"); + } + + if mode.contains(AccessMode::X_OK) && !inode_mode.is_executable() { + return_errno_with_message!(Errno::EACCES, "Execute permission denied"); + } -pub fn sys_access(filename_ptr: Vaddr, file_mode: u64) -> Result { - let filename = read_cstring_from_user(filename_ptr, MAX_FILENAME_LEN)?; - debug!("filename: {:?}, file_mode = {}", filename, file_mode); - // TODO: access currenly does not check and just return success Ok(SyscallReturn::Return(0)) } diff --git a/kernel/aster-nix/src/syscall/arch/x86.rs b/kernel/aster-nix/src/syscall/arch/x86.rs index 84c82584..35abb6a7 100644 --- a/kernel/aster-nix/src/syscall/arch/x86.rs +++ b/kernel/aster-nix/src/syscall/arch/x86.rs @@ -2,7 +2,7 @@ use crate::syscall::{ accept::{sys_accept, sys_accept4}, - access::sys_access, + access::{sys_access, sys_faccessat}, alarm::sys_alarm, arch_prctl::sys_arch_prctl, bind::sys_bind, @@ -272,6 +272,7 @@ impl_syscall_nums_and_dispatch_fn! { SYS_SYMLINKAT = 266 => sys_symlinkat(args[..3]); SYS_READLINKAT = 267 => sys_readlinkat(args[..4]); SYS_FCHMODAT = 268 => sys_fchmodat(args[..3]); + SYS_FACCESSAT = 269 => sys_faccessat(args[..3]); SYS_SET_ROBUST_LIST = 273 => sys_set_robust_list(args[..2]); SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]); SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]); diff --git a/regression/syscall_test/Makefile b/regression/syscall_test/Makefile index 424d5c23..7d0853bc 100644 --- a/regression/syscall_test/Makefile +++ b/regression/syscall_test/Makefile @@ -6,6 +6,7 @@ # # Please keep the list sorted by name. TESTS ?= \ + access_test \ alarm_test \ chmod_test \ chown_test \ diff --git a/regression/syscall_test/blocklists.exfat/access_test b/regression/syscall_test/blocklists.exfat/access_test new file mode 100644 index 00000000..3ae65a25 --- /dev/null +++ b/regression/syscall_test/blocklists.exfat/access_test @@ -0,0 +1 @@ +AccessTest.UsrReadWrite \ No newline at end of file diff --git a/regression/syscall_test/blocklists/access_test b/regression/syscall_test/blocklists/access_test new file mode 100644 index 00000000..ac3d2789 --- /dev/null +++ b/regression/syscall_test/blocklists/access_test @@ -0,0 +1,3 @@ +AccessTest.NoPerms +AccessTest.UsrReadOnly +AccessTest.UsrReadExec \ No newline at end of file