Support syscall fchmodat2

This commit is contained in:
vvsv 2025-12-02 10:03:57 +00:00 committed by Tate, Hongliang Tian
parent 0dd061269e
commit 8152695a17
6 changed files with 58 additions and 15 deletions

View File

@ -288,7 +288,7 @@ which are summarized in the table below.
| 265 | linkat | ✅ | ❓ |
| 266 | symlinkat | ✅ | 💯 |
| 267 | readlinkat | ✅ | 💯 |
| 268 | fchmodat | ✅ | |
| 268 | fchmodat | ✅ | 💯 |
| 269 | faccessat | ✅ | ❓ |
| 270 | pselect6 | ✅ | 💯 |
| 271 | ppoll | ✅ | ❓ |
@ -348,6 +348,7 @@ which are summarized in the table below.
| 436 | close_range | ✅ | ❓ |
| 439 | faccessat2 | ✅ | ❓ |
| 441 | epoll_pwait2 | ✅ | ❓ |
| 452 | fchmodat2 | ✅ | 💯 |
- Supported:
- ✅ = syscall supported

View File

@ -68,6 +68,8 @@ readlinkat(dirfd, path, buf, bufsiz);
// Change permissions of a file
chmod(path, mode);
fchmod(fd, mode);
fchmodat(dirfd, path_ptr, mode);
fchmodat2(dirfd, path_ptr, mode, flags = AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
// Change ownership of a file
chown(path, owner, group);

View File

@ -10,7 +10,7 @@ use super::{
capget::sys_capget,
capset::sys_capset,
chdir::{sys_chdir, sys_fchdir},
chmod::{sys_fchmod, sys_fchmodat},
chmod::{sys_fchmod, sys_fchmodat, sys_fchmodat2},
chown::{sys_fchown, sys_fchownat},
chroot::sys_chroot,
clock_gettime::sys_clock_gettime,
@ -356,4 +356,5 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_CLOSE_RANGE = 436 => sys_close_range(args[..3]);
SYS_FACCESSAT2 = 439 => sys_faccessat2(args[..4]);
SYS_EPOLL_PWAIT2 = 441 => sys_epoll_pwait2(args[..5]);
SYS_FCHMODAT2 = 452 => sys_fchmodat2(args[..4]);
}

View File

@ -10,7 +10,7 @@ use super::{
capget::sys_capget,
capset::sys_capset,
chdir::{sys_chdir, sys_fchdir},
chmod::{sys_fchmod, sys_fchmodat},
chmod::{sys_fchmod, sys_fchmodat, sys_fchmodat2},
chown::{sys_fchown, sys_fchownat},
chroot::sys_chroot,
clock_gettime::sys_clock_gettime,
@ -358,4 +358,5 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_CLOSE_RANGE = 436 => sys_close_range(args[..3]);
SYS_FACCESSAT2 = 439 => sys_faccessat2(args[..4]);
SYS_EPOLL_PWAIT2 = 441 => sys_epoll_pwait2(args[..5]);
SYS_FCHMODAT2 = 452 => sys_fchmodat2(args[..4]);
}

View File

@ -12,7 +12,7 @@ use super::{
capget::sys_capget,
capset::sys_capset,
chdir::{sys_chdir, sys_fchdir},
chmod::{sys_chmod, sys_fchmod, sys_fchmodat},
chmod::{sys_chmod, sys_fchmod, sys_fchmodat, sys_fchmodat2},
chown::{sys_chown, sys_fchown, sys_fchownat, sys_lchown},
chroot::sys_chroot,
clock_gettime::sys_clock_gettime,
@ -407,4 +407,5 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_CLOSE_RANGE = 436 => sys_close_range(args[..3]);
SYS_FACCESSAT2 = 439 => sys_faccessat2(args[..4]);
SYS_EPOLL_PWAIT2 = 441 => sys_epoll_pwait2(args[..5]);
SYS_FCHMODAT2 = 452 => sys_fchmodat2(args[..4]);
}

View File

@ -24,32 +24,62 @@ pub fn sys_fchmod(fd: FileDesc, mode: u16, ctx: &Context) -> Result<SyscallRetur
}
pub fn sys_chmod(path_ptr: Vaddr, mode: u16, ctx: &Context) -> Result<SyscallReturn> {
self::sys_fchmodat(AT_FDCWD, path_ptr, mode, ctx)
do_fchmodat(AT_FDCWD, path_ptr, mode, ChmodFlags::empty(), ctx)
}
// Glibc handles the `flags` argument, so we just ignore it.
pub fn sys_fchmodat(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
/* flags: u32, */
ctx: &Context,
) -> Result<SyscallReturn> {
do_fchmodat(dirfd, path_ptr, mode, ChmodFlags::empty(), ctx)
}
pub fn sys_fchmodat2(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
flags: u32,
ctx: &Context,
) -> Result<SyscallReturn> {
let flags = ChmodFlags::from_bits(flags)
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid chmod flags"))?;
do_fchmodat(dirfd, path_ptr, mode, flags, ctx)
}
fn do_fchmodat(
dirfd: FileDesc,
path_ptr: Vaddr,
mode: u16,
flags: ChmodFlags,
ctx: &Context,
) -> Result<SyscallReturn> {
let path_name = ctx.user_space().read_cstring(path_ptr, PATH_MAX)?;
debug!(
"dirfd = {}, path_name = {:?}, mode = 0o{:o}",
dirfd, path_name, mode,
"dirfd = {}, path_name = {:?}, mode = 0o{:o}, flags = {:?}",
dirfd, path_name, mode, flags,
);
let path_or_inode = {
let path_name = path_name.to_string_lossy();
let fs_path = FsPath::from_fd_and_path(dirfd, &path_name)?;
ctx.thread_local
.borrow_fs()
.resolver()
.read()
.lookup_inode(&fs_path)?
let fs_path = if flags.contains(ChmodFlags::AT_EMPTY_PATH) && path_name.is_empty() {
FsPath::from_fd(dirfd)?
} else {
FsPath::from_fd_and_path(dirfd, &path_name)?
};
let fs_ref = ctx.thread_local.borrow_fs();
let fs = fs_ref.resolver().read();
if flags.contains(ChmodFlags::AT_SYMLINK_NOFOLLOW) {
fs.lookup_inode_no_follow(&fs_path)?
} else {
fs.lookup_inode(&fs_path)?
}
};
path_or_inode
.inode()
.set_mode(InodeMode::from_bits_truncate(mode))?;
@ -58,3 +88,10 @@ pub fn sys_fchmodat(
}
Ok(SyscallReturn::Return(0))
}
bitflags::bitflags! {
struct ChmodFlags: u32 {
const AT_EMPTY_PATH = 1 << 12;
const AT_SYMLINK_NOFOLLOW = 1 << 8;
}
}