#include "Pledge.h" #include "memory/MemoryManager.h" #include "sys/Syscall.h" #include "thread/Scheduler.h" #include #include #include #include static mode_t make_mode(mode_t mode, VFS::InodeType type) { mode_t result = mode; switch (type) { case VFS::InodeType::RegularFile: result |= S_IFREG; break; case VFS::InodeType::Directory: result |= S_IFDIR; break; case VFS::InodeType::CharacterDevice: result |= S_IFCHR; break; case VFS::InodeType::BlockDevice: result |= S_IFBLK; break; case VFS::InodeType::Symlink: result |= S_IFLNK; break; case VFS::InodeType::FIFO: result |= S_IFIFO; break; case VFS::InodeType::Socket: result |= S_IFSOCK; break; default: break; } return result; } Result sys_fstatat(Registers*, SyscallArgs args) { int dirfd = (int)args[0]; auto path = TRY(MemoryManager::strdup_from_user(args[1])); stat* st = (stat*)args[2]; int flags = (int)args[3]; Thread* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_rpath)); auto inode = TRY(current->resolve_atfile(dirfd, path, flags & AT_EMPTY_PATH, !(flags & AT_SYMLINK_NOFOLLOW))); stat kstat; const auto& metadata = inode->metadata(); kstat.st_ino = metadata.inum; kstat.st_mode = make_mode(metadata.mode, inode->type()); kstat.st_nlink = metadata.nlinks; kstat.st_uid = metadata.uid; kstat.st_gid = metadata.gid; kstat.st_size = metadata.size; kstat.st_dev = inode->fs() ? inode->fs()->host_device_id() : 0; kstat.st_rdev = metadata.devid; kstat.st_atim = metadata.atime; kstat.st_mtim = metadata.mtime; kstat.st_ctim = metadata.ctime; if (!MemoryManager::copy_to_user_typed(st, &kstat)) return err(EFAULT); return 0; } Result sys_faccessat(Registers*, SyscallArgs args) { int dirfd = (int)args[0]; auto path = TRY(MemoryManager::strdup_from_user(args[1])); int amode = (int)args[2]; int flags = (int)args[3]; Credentials creds; auto* current = Scheduler::current(); TRY(check_pledge(current, Promise::p_rpath)); if (flags & AT_EACCESS) creds = current->auth; else { auto auth = current->auth; creds.euid = auth.uid; creds.egid = auth.gid; } auto inode = TRY(current->resolve_atfile(dirfd, path, false, true)); if ((amode & R_OK) && !VFS::can_read(inode, creds)) return err(EACCES); if ((amode & W_OK) && !VFS::can_write(inode, creds)) return err(EACCES); if ((amode & X_OK) && !VFS::can_execute(inode, creds)) return err(EACCES); // Either all checks succeeded, or amode == F_OK and the file exists, since resolve_atfile() would have failed // otherwise. return 0; }