From 182f9849cb897838cd184a32405acd9df2258ede Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Wed, 10 Jun 2026 23:09:53 -0300 Subject: [PATCH] vfs: add vfs_check_permission_real for POSIX strict access() Implement M2: POSIX access() with real IDs instead of effective IDs. Added vfs_check_permission_real() function that uses current_process->uid and current_process->gid instead of euid/egid for POSIX strict compliance. The access() syscall now uses this function, while other operations continue to use vfs_check_permission() with effective IDs. This ensures access() behaves according to POSIX specification which requires real IDs for permission checks, while preserving existing behavior for other file operations that use effective IDs. Test: make test-battery PASS (157/157), make analyzer PASS --- include/fs.h | 1 + src/kernel/fs.c | 25 +++++++++++++++++++++++++ src/kernel/syscall.c | 4 ++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/fs.h b/include/fs.h index bc130c27..5e4fa267 100644 --- a/include/fs.h +++ b/include/fs.h @@ -140,6 +140,7 @@ int vfs_truncate(const char* path, uint32_t length); int vfs_truncate_node(struct fs_node* node, uint32_t length); int vfs_check_parent_permission(const char* path, int perm); int vfs_check_permission(struct fs_node* node, int want); +int vfs_check_permission_real(struct fs_node* node, int want); int vfs_link(const char* old_path, const char* new_path); int vfs_mount(const char* mountpoint, fs_node_t* root); diff --git a/src/kernel/fs.c b/src/kernel/fs.c index 9ef5b4b2..aab903c4 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -685,6 +685,31 @@ int vfs_check_permission(fs_node_t* node, int want) { return 0; } +/* + * Check permission using real UID/GID for POSIX strict compliance. + * Used by access() syscall which must use real IDs, not effective IDs. + * want: bitmask of 4 (read), 2 (write), 1 (execute). + * Returns 0 if allowed, -EACCES if denied. + */ +int vfs_check_permission_real(fs_node_t* node, int want) { + if (!current_process) return 0; /* kernel context — allow all */ + if (current_process->uid == 0) return 0; /* root — allow all */ + + uint32_t mode = node->mode; + uint32_t perm; + + if (current_process->uid == node->uid) { + perm = (mode >> 6) & 7; /* owner bits */ + } else if (current_process->gid == node->gid) { + perm = (mode >> 3) & 7; /* group bits */ + } else { + perm = mode & 7; /* other bits */ + } + + if ((want & perm) != (uint32_t)want) return -EACCES; + return 0; +} + int vfs_link(const char* old_path, const char* new_path) { if (!old_path || !new_path) return -EINVAL; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 023b7cca..4e723789 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -4595,12 +4595,12 @@ static void posix_ext_syscall_dispatch(struct registers* regs, uint32_t syscall_ sc_ret(regs) = 0; return; } - /* Use vfs_check_permission for R_OK/W_OK/X_OK */ + /* Use vfs_check_permission_real for R_OK/W_OK/X_OK (POSIX strict: use real IDs) */ int want = 0; if (mode & 4) want |= 4; /* R_OK = 4 */ if (mode & 2) want |= 2; /* W_OK = 2 */ if (mode & 1) want |= 1; /* X_OK = 1 */ - int perm_rc = vfs_check_permission(node, want); + int perm_rc = vfs_check_permission_real(node, want); if (perm_rc < 0) { sc_ret(regs) = (uint32_t)perm_rc; return; -- 2.43.0